1 /*
2 Copyright 2002-2014 Han The Thanh, <thanh@pdftex.org>
3 
4 This file is part of pdfTeX.
5 
6 pdfTeX is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10 
11 pdfTeX is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15 
16 You should have received a copy of the GNU General Public License along
17 with this program.  If not, see <http://www.gnu.org/licenses/>.
18 
19 This is experimental JBIG2 image support to pdfTeX. JBIG2 image decoding
20 is part of Adobe PDF-1.4, and requires Acroread 5.0 or later.
21 
22 References
23 ==========
24 
25 * 14492 FCD: Information technology -- coded representation of picture
26 and audio information -- lossy/lossless coding of bi-level images /
27 JBIG committee, 1999 July 16. This JBIG2 Working Draft is available from
28 http://www.jpeg.org/public/fcd14492.pdf. The references in the C-code
29 correspond to the sections of this document.
30 
31 * PDF Reference, 5th edition, version 1.6, 1985--2005 Adobe Systems
32 Incorporated. Available online:
33 
34 http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf
35 
36 News
37 ====
38 
39 31 May 2006: no need to wait for endoffileflag in sequential access
40 organization.
41 
42 10 May 2006: ygetc() for some catching of broken JBIG2 files; modify to
43 accept Example 3.4 from PDFRef 5th ed. with short end-of-file segment.
44 
45 09 May 2006: pages_maketree() and segments_maketree() by AVL tree,
46 some cleaning up.
47 
48 06 May 2006: File list replaced by AVL tree; new_fileinfo(),
49 new_pageinfo().
50 
51 04 May 2006: Updated for pdftex-1.40-beta-20060213.
52 
53 08 Jan. 2003: Added flushjbig2page0objects() function. Now at the end
54 of the pdfTeX run all pending page0 objects are written out.
55 
56 08 Jan. 2003: Release on private webpage.
57 
58 04 Jan. 2003: Completely rewritten. Now with some data structures.
59 Rudimentary local file and image bookkeeping. Multiple image inclusion
60 from one JBIG2 file. Only required page0 segments are marked for
61 inclusion.
62 
63 13 Nov. 2002: pdfcrypting removed.
64 
65 08 Dec. 2002: bug in page 0 stream writing repaired.
66 Strategy for multiple page inclusion from same JBIG2 file: When writing
67 1st image, create fresh PDF object for page 0, and include any page
68 0 segments from complete file (even if these segments are not needed
69 for image). When writing next image, check by filename comparison if
70 PDF object for page 0 of this JBIG2 file has already been written. This
71 can only remember the file name for the direct predecessor JBIG2 image
72 (but images of other types might come inbetween). If such page 0 PDF
73 object exists, reference it. Else create fresh one.
74 
75 09 Dec. 2002: JBIG2 seg. page numbers > 0 are now set to 1, see PDF Ref.
76 
77 ***********************************************************************/
78 
79 #include "ptexlib.h"
80 #include <stdlib.h>
81 #include <stdio.h>
82 #include <assert.h>
83 #include "ptexmac.h"
84 #include "image.h"
85 
86 /* 7.3 Segment types */
87 #define M_SymbolDictionary 0
88 #define M_IntermediateTextRegion 4
89 #define M_ImmediateTextRegion 6
90 #define M_ImmediateLosslessTextRegion 7
91 #define M_PatternDictionary 16
92 #define M_IntermediateHalftoneRegion 20
93 #define M_ImmediateHalftoneRegion 22
94 #define M_ImmediateLosslessHalftoneRegion 23
95 #define M_IntermediateGenericRegion 36
96 #define M_ImmediateGenericRegion 38
97 #define M_ImmediateLosslessGenericRegion 39
98 #define M_IntermediateGenericRefinementRegion 40
99 #define M_ImmediateGenericRefinementRegion 42
100 #define M_ImmediateLosslessGenericRefinementRegion 43
101 #define M_PageInformation 48
102 #define M_EndOfPage 49
103 #define M_EndOfStripe 50
104 #define M_EndOfFile 51
105 #define M_Profiles 52
106 #define M_Tables 53
107 #define M_Extension 62
108 
109 /**********************************************************************/
110 
111 typedef enum { INITIAL, HAVEINFO, WRITEPDF } PHASE;
112 
113 typedef struct _LITEM {
114     struct _LITEM *prev;
115     struct _LITEM *next;
116     void *d;                    /* data */
117 } LITEM;
118 
119 typedef struct _LIST {
120     LITEM *first;
121     LITEM *last;
122     struct avl_table *tree;
123 } LIST;
124 
125 typedef struct _SEGINFO {
126     unsigned long segnum;
127     boolean isrefered;
128     boolean refers;
129     unsigned int seghdrflags;   /* set by readseghdr() */
130     boolean pageassocsizeflag;  /* set by readseghdr() */
131     unsigned int reftosegcount; /* set by readseghdr() */
132     unsigned int countofrefered;        /* set by readseghdr() */
133     unsigned int fieldlen;      /* set by readseghdr() */
134     unsigned int segnumwidth;   /* set by readseghdr() */
135     long segpage;               /* set by readseghdr() */
136     unsigned long segdatalen;   /* set by readseghdr() */
137     off_t hdrstart;             /* set by readseghdr() */
138     off_t hdrend;               /* set by readseghdr() */
139     off_t datastart;
140     off_t dataend;
141     boolean endofstripeflag;    /* set by checkseghdrflags() */
142     boolean endofpageflag;      /* set by checkseghdrflags() */
143     boolean pageinfoflag;       /* set by checkseghdrflags() */
144     boolean endoffileflag;      /* set by checkseghdrflags() */
145 } SEGINFO;
146 
147 typedef struct _PAGEINFO {
148     LIST segments;              /* segments associated with page */
149     unsigned long pagenum;
150     unsigned int width;
151     unsigned int height;
152     unsigned int xres;
153     unsigned int yres;
154     unsigned int pagesegmentflags;
155     unsigned int stripinginfo;
156     unsigned int stripedheight;
157 } PAGEINFO;
158 
159 typedef struct _FILEINFO {
160     FILE *file;
161     char *filename;
162     off_t filesize;
163     LIST pages;                 /* not including page0 */
164     LIST page0;
165     unsigned int filehdrflags;  /* set by readfilehdr() */
166     boolean sequentialaccess;   /* set by readfilehdr() */
167     unsigned long numofpages;   /* set by readfilehdr() */
168     off_t streamstart;          /* set by get_jbig2_info() */
169     unsigned long pdfpage0objnum;
170     PHASE phase;
171 } FILEINFO;
172 
173 /**********************************************************************/
174 
175 static void initlinkedlist(LIST * lp);
176 static void checkseghdrflags(SEGINFO * sip);
177 static void markpage0seg(FILEINFO * fip, unsigned long referedseg);
178 
179 /**********************************************************************/
180 
181 struct avl_table *file_tree = NULL;
182 
comp_file_entry(const void * pa,const void * pb,void * p)183 static int comp_file_entry(const void *pa, const void *pb, void *p)
184 {
185     return strcmp(((const FILEINFO *) pa)->filename,
186                   ((const FILEINFO *) pb)->filename);
187 }
188 
comp_page_entry(const void * pa,const void * pb,void * p)189 static int comp_page_entry(const void *pa, const void *pb, void *p)
190 {
191     return ((const PAGEINFO *) pa)->pagenum - ((const PAGEINFO *) pb)->pagenum;
192 }
193 
comp_segment_entry(const void * pa,const void * pb,void * p)194 static int comp_segment_entry(const void *pa, const void *pb, void *p)
195 {
196     return ((const SEGINFO *) pa)->segnum - ((const SEGINFO *) pb)->segnum;
197 }
198 
199 /**********************************************************************/
200 
ygetc(FILE * stream)201 static int ygetc(FILE * stream)
202 {
203     int c = getc(stream);
204     if (c < 0) {
205         if (c == EOF)
206             pdftex_fail("getc() failed; premature end of JBIG2 image file");
207         else
208             pdftex_fail("getc() failed (can't happen)");
209     }
210     return c;
211 }
212 
213 /**********************************************************************/
214 
new_fileinfo(void)215 static FILEINFO *new_fileinfo(void)
216 {
217     FILEINFO *fip;
218     fip = xtalloc(1, FILEINFO);
219     fip->file = NULL;
220     fip->filename = NULL;
221     fip->filesize = 0;
222     initlinkedlist(&(fip->pages));
223     initlinkedlist(&(fip->page0));
224     fip->filehdrflags = 0;
225     fip->sequentialaccess = false;
226     fip->numofpages = 0;
227     fip->streamstart = 0;
228     fip->pdfpage0objnum = 0;
229     fip->phase = INITIAL;
230     return fip;
231 }
232 
new_pageinfo(void)233 static PAGEINFO *new_pageinfo(void)
234 {
235     PAGEINFO *pip;
236     pip = xtalloc(1, PAGEINFO);
237     initlinkedlist(&(pip->segments));
238     pip->pagenum = 0;
239     pip->width = 0;
240     pip->height = 0;
241     pip->xres = 0;
242     pip->yres = 0;
243     pip->pagesegmentflags = 0;
244     pip->stripinginfo = 0;
245     pip->stripedheight = 0;
246     return pip;
247 }
248 
init_seginfo(SEGINFO * sip)249 static void init_seginfo(SEGINFO * sip)
250 {
251     sip->segnum = 0;
252     sip->isrefered = false;
253     sip->refers = false;
254     sip->seghdrflags = 0;
255     sip->pageassocsizeflag = false;
256     sip->reftosegcount = 0;
257     sip->countofrefered = 0;
258     sip->fieldlen = 0;
259     sip->segnumwidth = 0;
260     sip->segpage = 0;
261     sip->segdatalen = 0;
262     sip->hdrstart = 0;
263     sip->hdrend = 0;
264     sip->datastart = 0;
265     sip->dataend = 0;
266     sip->endofstripeflag = false;
267     sip->endofpageflag = false;
268     sip->pageinfoflag = false;
269     sip->endoffileflag = false;
270 }
271 
272 /**********************************************************************/
273 
initlinkedlist(LIST * lp)274 static void initlinkedlist(LIST * lp)
275 {
276     lp->first = NULL;
277     lp->last = NULL;
278     lp->tree = NULL;
279 }
280 
litem_append(LIST * lp)281 static LIST *litem_append(LIST * lp)
282 {
283     LITEM *ip;
284     ip = xtalloc(1, LITEM);
285     if (lp->first == NULL) {
286         lp->first = ip;
287         ip->prev = NULL;
288     } else {
289         lp->last->next = ip;
290         ip->prev = lp->last;
291     }
292     lp->last = ip;
293     ip->next = NULL;
294     ip->d = NULL;
295     return lp;
296 }
297 
298 /**********************************************************************/
299 
pages_maketree(LIST * plp)300 static void pages_maketree(LIST * plp)
301 {
302     LITEM *ip;
303     void **aa;
304     assert(plp->tree == NULL);
305     plp->tree = avl_create(comp_page_entry, NULL, &avl_xallocator);
306     assert(plp->tree != NULL);
307     for (ip = plp->first; ip != NULL; ip = ip->next) {
308         aa = avl_probe(plp->tree, (PAGEINFO *) ip->d);
309         assert(aa != NULL);
310     }
311 }
312 
segments_maketree(LIST * slp)313 static void segments_maketree(LIST * slp)
314 {
315     LITEM *ip;
316     void **aa;
317     assert(slp->tree == NULL);
318     slp->tree = avl_create(comp_segment_entry, NULL, &avl_xallocator);
319     assert(slp->tree != NULL);
320     for (ip = slp->first; ip != NULL; ip = ip->next) {
321         aa = avl_probe(slp->tree, (SEGINFO *) ip->d);
322         assert(aa != NULL);
323     }
324 }
325 
326 /**********************************************************************/
327 
find_pageinfo(LIST * plp,unsigned long pagenum)328 static PAGEINFO *find_pageinfo(LIST * plp, unsigned long pagenum)
329 {
330     PAGEINFO tmp;
331     tmp.pagenum = pagenum;
332     assert(plp->tree != NULL);
333     return (PAGEINFO *) avl_find(plp->tree, &tmp);
334 }
335 
find_seginfo(LIST * slp,unsigned long segnum)336 static SEGINFO *find_seginfo(LIST * slp, unsigned long segnum)
337 {
338     SEGINFO tmp;
339     tmp.segnum = segnum;
340     assert(slp->tree != NULL);
341     return (SEGINFO *) avl_find(slp->tree, &tmp);
342 }
343 
344 /**********************************************************************/
345 
read2bytes(FILE * f)346 static unsigned int read2bytes(FILE * f)
347 {
348     unsigned int c = ygetc(f);
349     return (c << 8) + ygetc(f);
350 }
351 
read4bytes(FILE * f)352 static unsigned long read4bytes(FILE * f)
353 {
354     unsigned int l = read2bytes(f);
355     return (l << 16) + read2bytes(f);
356 }
357 
358 /**********************************************************************/
359 
getstreamlen(LITEM * slip,boolean refer)360 static off_t getstreamlen(LITEM * slip, boolean refer)
361 {
362     SEGINFO *sip;
363     off_t len = 0;
364     for (; slip != NULL; slip = slip->next) {
365         sip = slip->d;
366         if (refer || sip->isrefered)
367             len += (sip->hdrend - sip->hdrstart) + (sip->dataend - sip->datastart);
368     }
369     return len;
370 }
371 
372 /**********************************************************************/
373 
readfilehdr(FILEINFO * fip)374 static void readfilehdr(FILEINFO * fip)
375 {
376     unsigned int i;
377     /* Annex D.4 File header syntax */
378     /* Annex D.4.1 ID string */
379     unsigned char jbig2_id[] = { 0x97, 'J', 'B', '2', 0x0d, 0x0a, 0x1a, 0x0a };
380     xfseeko(fip->file, (off_t)0, SEEK_SET, fip->filename);
381     for (i = 0; i < 8; i++)
382         if (ygetc(fip->file) != jbig2_id[i])
383             pdftex_fail
384                 ("readfilehdr(): reading JBIG2 image file failed: ID string missing");
385     /* Annex D.4.2 File header flags */
386     fip->filehdrflags = ygetc(fip->file);
387     fip->sequentialaccess = (fip->filehdrflags & 0x01) ? true : false;
388     if (fip->sequentialaccess) {        /* Annex D.1 vs. Annex D.2 */
389         xfseeko(fip->file, (off_t)0, SEEK_END, fip->filename);
390         fip->filesize = xftello(fip->file, fip->filename);
391         xfseeko(fip->file, (off_t)9, SEEK_SET, fip->filename);
392     }
393     /* Annex D.4.3 Number of pages */
394     if (!(fip->filehdrflags >> 1) & 0x01)       /* known number of pages */
395         fip->numofpages = read4bytes(fip->file);
396     /* --- at end of file header --- */
397 }
398 
399 /**********************************************************************/
400 /* for first reading of file; return value tells if header been read */
401 
readseghdr(FILEINFO * fip,SEGINFO * sip)402 static boolean readseghdr(FILEINFO * fip, SEGINFO * sip)
403 {
404     unsigned int i;
405     sip->hdrstart = xftello(fip->file, fip->filename);
406     if (fip->sequentialaccess && sip->hdrstart == fip->filesize)
407         return false;           /* no endoffileflag is ok for sequentialaccess */
408     /* 7.2.2 Segment number */
409     sip->segnum = read4bytes(fip->file);
410     /* 7.2.3 Segment header flags */
411     sip->seghdrflags = ygetc(fip->file);
412     checkseghdrflags(sip);
413     if (fip->sequentialaccess && sip->endoffileflag)    /* accept shorter segment, */
414         return true;            /* makes it compliant with Example 3.4 of PDFRef. 5th ed. */
415     sip->pageassocsizeflag = ((sip->seghdrflags >> 6) & 0x01) ? true : false;
416     /* 7.2.4 Referred-to segment count and retention flags */
417     sip->reftosegcount = (unsigned int) ygetc(fip->file);
418     sip->countofrefered = sip->reftosegcount >> 5;
419     if (sip->countofrefered < 5)
420         sip->fieldlen = 1;
421     else {
422         sip->fieldlen = 5 + sip->countofrefered / 8;
423         xfseeko(fip->file, (off_t) sip->fieldlen - 1, SEEK_CUR, fip->filename);
424     }
425     /* 7.2.5 Referred-to segment numbers */
426     if (sip->segnum <= 256)
427         sip->segnumwidth = 1;
428     else if (sip->segnum <= 65536)
429         sip->segnumwidth = 2;
430     else
431         sip->segnumwidth = 4;
432     for (i = 0; i < sip->countofrefered; i++) {
433         switch (sip->segnumwidth) {
434         case 1:
435             (void) ygetc(fip->file);
436             break;
437         case 2:
438             (void) read2bytes(fip->file);
439             break;
440         case 4:
441             (void) read4bytes(fip->file);
442             break;
443         }
444     }
445     /* 7.2.6 Segment page association */
446     if (sip->pageassocsizeflag)
447         sip->segpage = read4bytes(fip->file);
448     else
449         sip->segpage = ygetc(fip->file);
450     /* 7.2.7 Segment data length */
451     sip->segdatalen = read4bytes(fip->file);
452     sip->hdrend = xftello(fip->file, fip->filename);
453     /* ---- at end of segment header ---- */
454     return true;
455 }
456 
457 /**********************************************************************/
458 /* for writing, marks refered page0 segments, sets segpage > 0 to 1 */
459 
writeseghdr(FILEINFO * fip,SEGINFO * sip)460 static void writeseghdr(FILEINFO * fip, SEGINFO * sip)
461 {
462     unsigned int i;
463     unsigned long referedseg = 0;
464     /* 7.2.2 Segment number */
465     /* 7.2.3 Segment header flags */
466     /* 7.2.4 Referred-to segment count and retention flags */
467     for (i = 0; i < 5 + sip->fieldlen; i++)
468         pdfout(ygetc(fip->file));
469     /* 7.2.5 Referred-to segment numbers */
470     for (i = 0; i < sip->countofrefered; i++) {
471         switch (sip->segnumwidth) {
472         case 1:
473             referedseg = ygetc(fip->file);
474             pdfout(referedseg);
475             break;
476         case 2:
477             referedseg = read2bytes(fip->file);
478             pdfout((referedseg >> 8) & 0xff);
479             pdfout(referedseg & 0xff);
480             break;
481         case 4:
482             referedseg = read4bytes(fip->file);
483             pdfout((referedseg >> 24) & 0xff);
484             pdfout((referedseg >> 16) & 0xff);
485             pdfout((referedseg >> 8) & 0xff);
486             pdfout(referedseg & 0xff);
487             break;
488         }
489         if (fip->page0.last != NULL && !sip->refers)
490             markpage0seg(fip, referedseg);
491     }
492     if (sip->countofrefered > 0)
493         sip->refers = true;
494     /* 7.2.6 Segment page association */
495     if (sip->pageassocsizeflag)
496         for (i = 0; i < 3; i++) {
497             (void) ygetc(fip->file);
498             pdfout(0);
499         }
500     (void) ygetc(fip->file);
501     pdfout((sip->segpage > 0) ? 1 : 0);
502     /* 7.2.7 Segment data length */
503     for (i = 0; i < 4; i++)
504         pdfout(ygetc(fip->file));
505     /* ---- at end of segment header ---- */
506 }
507 
508 /**********************************************************************/
509 /* for recursive marking of refered page0 segments */
510 
checkseghdr(FILEINFO * fip,SEGINFO * sip)511 static void checkseghdr(FILEINFO * fip, SEGINFO * sip)
512 {
513     unsigned int i;
514     unsigned long referedseg = 0;
515     /* 7.2.2 Segment number */
516     /* 7.2.3 Segment header flags */
517     /* 7.2.4 Referred-to segment count and retention flags */
518     xfseeko(fip->file, (off_t) sip->fieldlen + 5, SEEK_CUR, fip->filename);
519     /* 7.2.5 Referred-to segment numbers */
520     for (i = 0; i < sip->countofrefered; i++) {
521         switch (sip->segnumwidth) {
522         case 1:
523             referedseg = ygetc(fip->file);
524             break;
525         case 2:
526             referedseg = read2bytes(fip->file);
527             break;
528         case 4:
529             referedseg = read4bytes(fip->file);
530             break;
531         }
532         if (!sip->refers)
533             markpage0seg(fip, referedseg);
534     }
535     if (sip->countofrefered > 0)
536         sip->refers = true;
537     /* 7.2.6 Segment page association */
538     /* 7.2.7 Segment data length */
539     if (sip->pageassocsizeflag)
540         xfseeko(fip->file, 8, SEEK_CUR, fip->filename);
541     else
542         xfseeko(fip->file, 5, SEEK_CUR, fip->filename);
543     /* ---- at end of segment header ---- */
544 }
545 
546 /**********************************************************************/
547 
checkseghdrflags(SEGINFO * sip)548 static void checkseghdrflags(SEGINFO * sip)
549 {
550     sip->endofstripeflag = false;
551     sip->endofpageflag = false;
552     sip->pageinfoflag = false;
553     sip->endoffileflag = false;
554     /* 7.3 Segment types */
555     switch (sip->seghdrflags & 0x3f) {
556     case M_SymbolDictionary:
557     case M_IntermediateTextRegion:
558     case M_ImmediateTextRegion:
559     case M_ImmediateLosslessTextRegion:
560     case M_PatternDictionary:
561     case M_IntermediateHalftoneRegion:
562     case M_ImmediateHalftoneRegion:
563     case M_ImmediateLosslessHalftoneRegion:
564     case M_IntermediateGenericRegion:
565     case M_ImmediateGenericRegion:
566     case M_ImmediateLosslessGenericRegion:
567     case M_IntermediateGenericRefinementRegion:
568     case M_ImmediateGenericRefinementRegion:
569     case M_ImmediateLosslessGenericRefinementRegion:
570         break;
571     case M_PageInformation:
572         sip->pageinfoflag = true;
573         break;
574     case M_EndOfPage:
575         sip->endofpageflag = true;
576         break;
577     case M_EndOfStripe:
578         sip->endofstripeflag = true;
579         break;
580     case M_EndOfFile:
581         sip->endoffileflag = true;
582         break;
583     case M_Profiles:
584     case M_Tables:
585     case M_Extension:
586         break;
587     default:
588         pdftex_fail
589             ("checkseghdrflags(): unknown segment type in JBIG2 image file");
590         break;
591     }
592 }
593 
594 /**********************************************************************/
595 
markpage0seg(FILEINFO * fip,unsigned long referedseg)596 static void markpage0seg(FILEINFO * fip, unsigned long referedseg)
597 {
598     PAGEINFO *pip;
599     SEGINFO *sip;
600     pip = fip->page0.first->d;
601     sip = find_seginfo(&(pip->segments), referedseg);
602     if (sip != NULL) {
603         if (!sip->refers && sip->countofrefered > 0)
604             checkseghdr(fip, sip);
605         sip->isrefered = true;
606     }
607 }
608 
609 /**********************************************************************/
610 
findstreamstart(FILEINFO * fip)611 static off_t findstreamstart(FILEINFO * fip)
612 {
613     SEGINFO tmp;
614     assert(!fip->sequentialaccess);     /* D.2 Random-access organisation */
615     do                          /* find random-access stream start */
616         (void) readseghdr(fip, &tmp);
617     while (!tmp.endoffileflag);
618     fip->streamstart = tmp.hdrend;
619     readfilehdr(fip);
620     return fip->streamstart;
621 }
622 
623 /**********************************************************************/
624 
rd_jbig2_info(FILEINFO * fip)625 static void rd_jbig2_info(FILEINFO * fip)
626 {
627     off_t seekdist = 0;         /* for sequential-access only */
628     off_t streampos = 0;        /* for random-access only */
629     unsigned long currentpage = 0;
630     boolean sipavail = false;
631     PAGEINFO *pip;
632     SEGINFO *sip = NULL;
633     LIST *plp, *slp;
634     fip->file = xfopen(fip->filename, FOPEN_RBIN_MODE);
635     readfilehdr(fip);
636     if (!fip->sequentialaccess) /* D.2 Random-access organisation */
637         streampos = findstreamstart(fip);
638     while (true) {              /* loop over segments */
639         if (!sipavail) {
640             sip = xtalloc(1, SEGINFO);
641             sipavail = true;
642         }
643         init_seginfo(sip);
644         if (!readseghdr(fip, sip) || sip->endoffileflag)
645             break;
646         if (sip->segpage > 0) {
647             if (sip->segpage > currentpage) {
648                 plp = litem_append(&(fip->pages));
649                 plp->last->d = new_pageinfo();
650                 currentpage = sip->segpage;
651             }
652             pip = fip->pages.last->d;
653         } else {
654             if (fip->page0.last == NULL) {
655                 plp = litem_append(&(fip->page0));
656                 plp->last->d = new_pageinfo();
657             }
658             pip = fip->page0.last->d;
659         }
660         if (!sip->endofpageflag) {
661             slp = litem_append(&(pip->segments));
662             slp->last->d = sip;
663             sipavail = false;
664         }
665         if (!fip->sequentialaccess)
666             sip->datastart = streampos;
667         else
668             sip->datastart = sip->hdrend;
669         sip->dataend = sip->datastart + sip->segdatalen;
670         if (!fip->sequentialaccess
671             && (sip->pageinfoflag || sip->endofstripeflag))
672             xfseeko(fip->file, sip->datastart, SEEK_SET, fip->filename);
673         seekdist = (off_t) sip->segdatalen;
674         /* 7.4.8 Page information segment syntax */
675         if (sip->pageinfoflag) {
676             pip->pagenum = sip->segpage;
677             pip->width = read4bytes(fip->file);
678             pip->height = read4bytes(fip->file);
679             pip->xres = read4bytes(fip->file);
680             pip->yres = read4bytes(fip->file);
681             pip->pagesegmentflags = ygetc(fip->file);
682             /* 7.4.8.6 Page striping information */
683             pip->stripinginfo = read2bytes(fip->file);
684             seekdist -= 19;
685         }
686         if (sip->endofstripeflag) {
687             pip->stripedheight = read4bytes(fip->file);
688             seekdist -= 4;
689         }
690         if (!fip->sequentialaccess
691             && (sip->pageinfoflag || sip->endofstripeflag))
692             xfseeko(fip->file, sip->hdrend, SEEK_SET, fip->filename);
693         if (!fip->sequentialaccess)
694             streampos += sip->segdatalen;
695         if (fip->sequentialaccess)
696             xfseeko(fip->file, seekdist, SEEK_CUR, fip->filename);
697         if (sip->endofpageflag && currentpage && (pip->stripinginfo >> 15))
698             pip->height = pip->stripedheight;
699     }
700     fip->phase = HAVEINFO;
701     if (sipavail)
702         xfree(sip);
703     xfclose(fip->file, fip->filename);
704 }
705 
706 /**********************************************************************/
707 
wr_jbig2(FILEINFO * fip,unsigned long page)708 static void wr_jbig2(FILEINFO * fip, unsigned long page)
709 {
710     LITEM *slip;
711     PAGEINFO *pip;
712     SEGINFO *sip;
713     off_t i;
714     if (page > 0) {
715         pip = find_pageinfo(&(fip->pages), page);
716         assert(pip != NULL);
717         pdf_puts("/Type /XObject\n");
718         pdf_puts("/Subtype /Image\n");
719         pdf_printf("/Width %i\n", pip->width);
720         pdf_printf("/Height %i\n", pip->height);
721         pdf_puts("/ColorSpace /DeviceGray\n");
722         pdf_puts("/BitsPerComponent 1\n");
723         pdf_printf("/Length %" LONGINTEGER_PRI "d\n",
724                    (LONGINTEGER_TYPE) getstreamlen(pip->segments.first, true));
725         pdf_puts("/Filter [/JBIG2Decode]\n");
726         if (fip->page0.last != NULL) {
727             if (fip->pdfpage0objnum == 0) {
728                 pdfcreateobj(0, 0);
729                 fip->pdfpage0objnum = objptr;
730             }
731             pdf_printf("/DecodeParms [<< /JBIG2Globals %lu 0 R >>]\n",
732                        fip->pdfpage0objnum);
733         }
734     } else {
735         pip = find_pageinfo(&(fip->page0), page);
736         assert(pip != NULL);
737         pdfbegindict(fip->pdfpage0objnum, 0);
738         pdf_printf("/Length %" LONGINTEGER_PRI "d\n",
739                    (LONGINTEGER_TYPE) getstreamlen(pip->segments.first, false));
740     }
741     pdf_puts(">>\n");
742     pdf_puts("stream\n");
743     fip->file = xfopen(fip->filename, FOPEN_RBIN_MODE);
744     for (slip = pip->segments.first; slip != NULL; slip = slip->next) { /* loop over page segments */
745         sip = slip->d;
746         if (sip->isrefered || page > 0) {
747             xfseeko(fip->file, sip->hdrstart, SEEK_SET, fip->filename);
748             /* mark refered-to page 0 segments, change segpages > 1 to 1 */
749             writeseghdr(fip, sip);
750             xfseeko(fip->file, sip->datastart, SEEK_SET, fip->filename);
751             for (i = sip->datastart; i < sip->dataend; i++)
752                 pdfout(ygetc(fip->file));
753         }
754     }
755     pdfendstream();
756     xfclose(fip->file, fip->filename);
757 }
758 
759 /**********************************************************************/
760 
read_jbig2_info(integer img)761 void read_jbig2_info(integer img)
762 {
763     FILEINFO *fip, tmp;
764     PAGEINFO *pip;
765     void **aa;
766     if (jbig2_ptr(img)->selected_page < 1)
767         pdftex_fail
768             ("read_jbig2_info(): page %d not in JBIG2 image file; page must be > 0",
769              (int) jbig2_ptr(img)->selected_page);
770     if (file_tree == NULL) {
771         file_tree = avl_create(comp_file_entry, NULL, &avl_xallocator);
772         assert(file_tree != NULL);
773     }
774     tmp.filename = img_name(img);
775     fip = (FILEINFO *) avl_find(file_tree, &tmp);
776     if (fip == NULL) {
777         fip = new_fileinfo();
778         fip->filename = xstrdup(img_name(img));
779         aa = avl_probe(file_tree, fip);
780         assert(aa != NULL);
781     }
782     if (fip->phase == INITIAL) {
783         rd_jbig2_info(fip);
784         pages_maketree(&(fip->pages));
785         if (fip->page0.last != NULL) {
786             pages_maketree(&(fip->page0));
787             pip = fip->page0.first->d;
788             segments_maketree(&(pip->segments));
789         }
790     }
791     pip = find_pageinfo(&(fip->pages), jbig2_ptr(img)->selected_page);
792     if (pip == NULL)
793         pdftex_fail("read_jbig2_info(): page %d not found in JBIG2 image file",
794                     (int) jbig2_ptr(img)->selected_page);
795     img_pages(img) = fip->numofpages;
796     img_width(img) = pip->width;
797     img_height(img) = pip->height;
798     img_xres(img) = (int) (pip->xres * 0.0254 + 0.5);
799     img_yres(img) = (int) (pip->yres * 0.0254 + 0.5);
800 }
801 
802 /**********************************************************************/
803 
write_jbig2(integer img)804 void write_jbig2(integer img)
805 {
806     FILEINFO *fip, tmp;
807     PAGEINFO *pip;
808     assert(file_tree != NULL);
809     tmp.filename = img_name(img);
810     fip = (FILEINFO *) avl_find(file_tree, &tmp);
811     assert(fip != NULL);
812     assert(fip->phase == HAVEINFO);     /* don't write before rd_jbig2_info() call */
813     pip = find_pageinfo(&(fip->pages), jbig2_ptr(img)->selected_page);
814     assert(pip != NULL);
815     wr_jbig2(fip, pip->pagenum);
816 }
817 
818 /**********************************************************************/
819 
flushjbig2page0objects(void)820 void flushjbig2page0objects(void)
821 {
822     FILEINFO *fip;
823     struct avl_traverser t;
824     if (file_tree != NULL) {
825         avl_t_init(&t, file_tree);
826         for (fip = avl_t_first(&t, file_tree); fip != NULL;
827              fip = avl_t_next(&t)) {
828             if (fip->page0.last != NULL)
829                 wr_jbig2(fip, 0);
830         }
831     }
832 }
833 
834 /**********************************************************************/
835