# Correct the needed linklibs in curl-config also.
[AROS-Contrib.git] / arospdf / xpdf / JPXStream.cc
blob0527519b9acc2369cad43b027a407442eb6bc6c7
1 //========================================================================
2 //
3 // JPXStream.cc
4 //
5 // Copyright 2002-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include <limits.h>
16 #include "gmem.h"
17 #include "Error.h"
18 #include "JArithmeticDecoder.h"
19 #include "JPXStream.h"
21 //~ to do:
22 // - precincts
23 // - ROI
24 // - progression order changes
25 // - packed packet headers
26 // - support for palettes, channel maps, etc.
27 // - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
28 // - can we assume that QCC segments must come after the QCD segment?
29 // - skip EPH markers (readTilePartData)
30 // - handle tilePartToEOC in readTilePartData
31 // - deal with multiple codeword segments (readTilePartData,
32 // readCodeBlockData)
33 // - progression orders 2, 3, and 4
34 // - in coefficient decoding (readCodeBlockData):
35 // - termination pattern: terminate after every coding pass
36 // - error resilience segmentation symbol
37 // - selective arithmetic coding bypass
38 // - vertically causal context formation
39 // - coeffs longer than 31 bits (should just ignore the extra bits?)
40 // - handle boxes larger than 2^32 bytes
41 // - the fixed-point arithmetic won't handle 16-bit pixels
43 //------------------------------------------------------------------------
45 // number of contexts for the arithmetic decoder
46 #define jpxNContexts 19
48 #define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup
49 #define jpxContextSign 9 // 9 - 13: sign
50 #define jpxContextMagRef 14 // 14 -16: magnitude refinement
51 #define jpxContextRunLength 17 // cleanup: run length
52 #define jpxContextUniform 18 // cleanup: first signif coeff
54 //------------------------------------------------------------------------
56 #define jpxPassSigProp 0
57 #define jpxPassMagRef 1
58 #define jpxPassCleanup 2
60 //------------------------------------------------------------------------
62 // arithmetic decoder context for the significance propagation and
63 // cleanup passes:
64 // [horiz][vert][diag][subband]
65 // where subband = 0 for HL
66 // = 1 for LH and LL
67 // = 2 for HH
68 static Guint sigPropContext[3][3][5][3] = {
69 {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0
70 { 1, 1, 3 }, // horiz=0, vert=0, diag=1
71 { 2, 2, 6 }, // horiz=0, vert=0, diag=2
72 { 2, 2, 8 }, // horiz=0, vert=0, diag=3
73 { 2, 2, 8 }}, // horiz=0, vert=0, diag=4
74 {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0
75 { 6, 3, 4 }, // horiz=0, vert=1, diag=1
76 { 6, 3, 7 }, // horiz=0, vert=1, diag=2
77 { 6, 3, 8 }, // horiz=0, vert=1, diag=3
78 { 6, 3, 8 }}, // horiz=0, vert=1, diag=4
79 {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0
80 { 8, 4, 5 }, // horiz=0, vert=2, diag=1
81 { 8, 4, 7 }, // horiz=0, vert=2, diag=2
82 { 8, 4, 8 }, // horiz=0, vert=2, diag=3
83 { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4
84 {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0
85 { 3, 6, 4 }, // horiz=1, vert=0, diag=1
86 { 3, 6, 7 }, // horiz=1, vert=0, diag=2
87 { 3, 6, 8 }, // horiz=1, vert=0, diag=3
88 { 3, 6, 8 }}, // horiz=1, vert=0, diag=4
89 {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0
90 { 7, 7, 5 }, // horiz=1, vert=1, diag=1
91 { 7, 7, 7 }, // horiz=1, vert=1, diag=2
92 { 7, 7, 8 }, // horiz=1, vert=1, diag=3
93 { 7, 7, 8 }}, // horiz=1, vert=1, diag=4
94 {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0
95 { 8, 7, 5 }, // horiz=1, vert=2, diag=1
96 { 8, 7, 7 }, // horiz=1, vert=2, diag=2
97 { 8, 7, 8 }, // horiz=1, vert=2, diag=3
98 { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4
99 {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0
100 { 4, 8, 5 }, // horiz=2, vert=0, diag=1
101 { 4, 8, 7 }, // horiz=2, vert=0, diag=2
102 { 4, 8, 8 }, // horiz=2, vert=0, diag=3
103 { 4, 8, 8 }}, // horiz=2, vert=0, diag=4
104 {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0
105 { 7, 8, 5 }, // horiz=2, vert=1, diag=1
106 { 7, 8, 7 }, // horiz=2, vert=1, diag=2
107 { 7, 8, 8 }, // horiz=2, vert=1, diag=3
108 { 7, 8, 8 }}, // horiz=2, vert=1, diag=4
109 {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0
110 { 8, 8, 5 }, // horiz=2, vert=2, diag=1
111 { 8, 8, 7 }, // horiz=2, vert=2, diag=2
112 { 8, 8, 8 }, // horiz=2, vert=2, diag=3
113 { 8, 8, 8 }}} // horiz=2, vert=2, diag=4
116 // arithmetic decoder context and xor bit for the sign bit in the
117 // significance propagation pass:
118 // [horiz][vert][k]
119 // where horiz/vert are offset by 2 (i.e., range is -2 .. 2)
120 // and k = 0 for the context
121 // = 1 for the xor bit
122 static Guint signContext[5][5][2] = {
123 {{ 13, 1 }, // horiz=-2, vert=-2
124 { 13, 1 }, // horiz=-2, vert=-1
125 { 12, 1 }, // horiz=-2, vert= 0
126 { 11, 1 }, // horiz=-2, vert=+1
127 { 11, 1 }}, // horiz=-2, vert=+2
128 {{ 13, 1 }, // horiz=-1, vert=-2
129 { 13, 1 }, // horiz=-1, vert=-1
130 { 12, 1 }, // horiz=-1, vert= 0
131 { 11, 1 }, // horiz=-1, vert=+1
132 { 11, 1 }}, // horiz=-1, vert=+2
133 {{ 10, 1 }, // horiz= 0, vert=-2
134 { 10, 1 }, // horiz= 0, vert=-1
135 { 9, 0 }, // horiz= 0, vert= 0
136 { 10, 0 }, // horiz= 0, vert=+1
137 { 10, 0 }}, // horiz= 0, vert=+2
138 {{ 11, 0 }, // horiz=+1, vert=-2
139 { 11, 0 }, // horiz=+1, vert=-1
140 { 12, 0 }, // horiz=+1, vert= 0
141 { 13, 0 }, // horiz=+1, vert=+1
142 { 13, 0 }}, // horiz=+1, vert=+2
143 {{ 11, 0 }, // horiz=+2, vert=-2
144 { 11, 0 }, // horiz=+2, vert=-1
145 { 12, 0 }, // horiz=+2, vert= 0
146 { 13, 0 }, // horiz=+2, vert=+1
147 { 13, 0 }}, // horiz=+2, vert=+2
150 //------------------------------------------------------------------------
152 // constants used in the IDWT
153 #define idwtAlpha -1.586134342059924
154 #define idwtBeta -0.052980118572961
155 #define idwtGamma 0.882911075530934
156 #define idwtDelta 0.443506852043971
157 #define idwtKappa 1.230174104914001
158 #define idwtIKappa (1.0 / idwtKappa)
160 // number of bits to the right of the decimal point for the fixed
161 // point arithmetic used in the IDWT
162 #define fracBits 16
164 //------------------------------------------------------------------------
166 // floor(x / y)
167 #define jpxFloorDiv(x, y) ((x) / (y))
169 // floor(x / 2^y)
170 #define jpxFloorDivPow2(x, y) ((x) >> (y))
172 // ceil(x / y)
173 #define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y))
175 // ceil(x / 2^y)
176 #define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y))
178 //------------------------------------------------------------------------
180 #if 1 //----- disable coverage tracking
182 #define cover(idx)
184 #else //----- enable coverage tracking
186 class JPXCover {
187 public:
189 JPXCover(int sizeA);
190 ~JPXCover();
191 void incr(int idx);
193 private:
195 int size, used;
196 int *data;
199 JPXCover::JPXCover(int sizeA) {
200 size = sizeA;
201 used = -1;
202 data = (int *)gmallocn(size, sizeof(int));
203 memset(data, 0, size * sizeof(int));
206 JPXCover::~JPXCover() {
207 int i;
209 printf("JPX coverage:\n");
210 for (i = 0; i <= used; ++i) {
211 printf(" %4d: %8d\n", i, data[i]);
213 gfree(data);
216 void JPXCover::incr(int idx) {
217 if (idx < size) {
218 ++data[idx];
219 if (idx > used) {
220 used = idx;
225 JPXCover jpxCover(150);
227 #define cover(idx) jpxCover.incr(idx)
229 #endif //----- coverage tracking
231 //------------------------------------------------------------------------
233 JPXStream::JPXStream(Stream *strA):
234 FilterStream(strA)
236 nComps = 0;
237 bpc = NULL;
238 width = height = 0;
239 haveCS = gFalse;
240 havePalette = gFalse;
241 haveCompMap = gFalse;
242 haveChannelDefn = gFalse;
244 img.tiles = NULL;
245 bitBuf = 0;
246 bitBufLen = 0;
247 bitBufSkip = gFalse;
248 byteCount = 0;
251 JPXStream::~JPXStream() {
252 close();
253 delete str;
256 void JPXStream::reset() {
257 str->reset();
258 if (readBoxes()) {
259 curY = img.yOffset;
260 } else {
261 // readBoxes reported an error, so we go immediately to EOF
262 curY = img.ySize;
264 curX = img.xOffset;
265 curComp = 0;
266 readBufLen = 0;
269 void JPXStream::close() {
270 JPXTile *tile;
271 JPXTileComp *tileComp;
272 JPXResLevel *resLevel;
273 JPXPrecinct *precinct;
274 JPXSubband *subband;
275 JPXCodeBlock *cb;
276 Guint comp, i, k, r, pre, sb;
278 gfree(bpc);
279 bpc = NULL;
280 if (havePalette) {
281 gfree(palette.bpc);
282 gfree(palette.c);
283 havePalette = gFalse;
285 if (haveCompMap) {
286 gfree(compMap.comp);
287 gfree(compMap.type);
288 gfree(compMap.pComp);
289 haveCompMap = gFalse;
291 if (haveChannelDefn) {
292 gfree(channelDefn.idx);
293 gfree(channelDefn.type);
294 gfree(channelDefn.assoc);
295 haveChannelDefn = gFalse;
298 if (img.tiles) {
299 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
300 tile = &img.tiles[i];
301 if (tile->tileComps) {
302 for (comp = 0; comp < img.nComps; ++comp) {
303 tileComp = &tile->tileComps[comp];
304 gfree(tileComp->quantSteps);
305 gfree(tileComp->data);
306 gfree(tileComp->buf);
307 if (tileComp->resLevels) {
308 for (r = 0; r <= tileComp->nDecompLevels; ++r) {
309 resLevel = &tileComp->resLevels[r];
310 if (resLevel->precincts) {
311 for (pre = 0; pre < 1; ++pre) {
312 precinct = &resLevel->precincts[pre];
313 if (precinct->subbands) {
314 for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) {
315 subband = &precinct->subbands[sb];
316 gfree(subband->inclusion);
317 gfree(subband->zeroBitPlane);
318 if (subband->cbs) {
319 for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
320 cb = &subband->cbs[k];
321 gfree(cb->coeffs);
322 if (cb->arithDecoder) {
323 delete cb->arithDecoder;
325 if (cb->stats) {
326 delete cb->stats;
329 gfree(subband->cbs);
332 gfree(precinct->subbands);
335 gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
338 gfree(img.tiles[i].tileComps[comp].resLevels);
341 gfree(img.tiles[i].tileComps);
344 gfree(img.tiles);
345 img.tiles = NULL;
347 FilterStream::close();
350 int JPXStream::getChar() {
351 int c;
353 if (readBufLen < 8) {
354 fillReadBuf();
356 if (readBufLen == 8) {
357 c = readBuf & 0xff;
358 readBufLen = 0;
359 } else if (readBufLen > 8) {
360 c = (readBuf >> (readBufLen - 8)) & 0xff;
361 readBufLen -= 8;
362 } else if (readBufLen == 0) {
363 c = EOF;
364 } else {
365 c = (readBuf << (8 - readBufLen)) & 0xff;
366 readBufLen = 0;
368 return c;
371 int JPXStream::lookChar() {
372 int c;
374 if (readBufLen < 8) {
375 fillReadBuf();
377 if (readBufLen == 8) {
378 c = readBuf & 0xff;
379 } else if (readBufLen > 8) {
380 c = (readBuf >> (readBufLen - 8)) & 0xff;
381 } else if (readBufLen == 0) {
382 c = EOF;
383 } else {
384 c = (readBuf << (8 - readBufLen)) & 0xff;
386 return c;
389 void JPXStream::fillReadBuf() {
390 JPXTileComp *tileComp;
391 Guint tileIdx, tx, ty;
392 int pix, pixBits;
394 do {
395 if (curY >= img.ySize) {
396 return;
398 tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles
399 + (curX - img.xTileOffset) / img.xTileSize;
400 #if 1 //~ ignore the palette, assume the PDF ColorSpace xObject is valid
401 tileComp = &img.tiles[tileIdx].tileComps[curComp];
402 #else
403 tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp];
404 #endif
405 tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep);
406 ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep);
407 pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx];
408 pixBits = tileComp->prec;
409 #if 1 //~ ignore the palette, assume the PDF ColorSpace xObject is valid
410 if (++curComp == img.nComps) {
411 #else
412 if (havePalette) {
413 if (pix >= 0 && pix < palette.nEntries) {
414 pix = palette.c[pix * palette.nComps + curComp];
415 } else {
416 pix =
417 pixBits = palette.bpc[curComp];
419 if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) {
420 #endif
421 curComp = 0;
422 if (++curX == img.xSize) {
423 curX = img.xOffset;
424 ++curY;
427 if (pixBits == 8) {
428 readBuf = (readBuf << 8) | (pix & 0xff);
429 } else {
430 readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1));
432 readBufLen += pixBits;
433 } while (readBufLen < 8);
436 GString *JPXStream::getPSFilter(int psLevel, char *indent) {
437 return NULL;
440 GBool JPXStream::isBinary(GBool last) {
441 return str->isBinary(gTrue);
444 void JPXStream::getImageParams(int *bitsPerComponent,
445 StreamColorSpaceMode *csMode) {
446 Guint boxType, boxLen, dataLen, csEnum;
447 Guint bpc1, dummy, i;
448 int csMeth, csPrec, csPrec1, dummy2;
449 StreamColorSpaceMode csMode1;
450 GBool haveBPC, haveCSMode;
452 csPrec = 0; // make gcc happy
453 haveBPC = haveCSMode = gFalse;
454 str->reset();
455 if (str->lookChar() == 0xff) {
456 getImageParams2(bitsPerComponent, csMode);
457 } else {
458 while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
459 if (boxType == 0x6a703268) { // JP2 header
460 cover(0);
461 // skip the superbox
462 } else if (boxType == 0x69686472) { // image header
463 cover(1);
464 if (readULong(&dummy) &&
465 readULong(&dummy) &&
466 readUWord(&dummy) &&
467 readUByte(&bpc1) &&
468 readUByte(&dummy) &&
469 readUByte(&dummy) &&
470 readUByte(&dummy)) {
471 *bitsPerComponent = bpc1 + 1;
472 haveBPC = gTrue;
474 } else if (boxType == 0x636F6C72) { // color specification
475 cover(2);
476 if (readByte(&csMeth) &&
477 readByte(&csPrec1) &&
478 readByte(&dummy2)) {
479 if (csMeth == 1) {
480 if (readULong(&csEnum)) {
481 csMode1 = streamCSNone;
482 if (csEnum == jpxCSBiLevel ||
483 csEnum == jpxCSGrayscale) {
484 csMode1 = streamCSDeviceGray;
485 } else if (csEnum == jpxCSCMYK) {
486 csMode1 = streamCSDeviceCMYK;
487 } else if (csEnum == jpxCSsRGB ||
488 csEnum == jpxCSCISesRGB ||
489 csEnum == jpxCSROMMRGB) {
490 csMode1 = streamCSDeviceRGB;
492 if (csMode1 != streamCSNone &&
493 (!haveCSMode || csPrec1 > csPrec)) {
494 *csMode = csMode1;
495 csPrec = csPrec1;
496 haveCSMode = gTrue;
498 for (i = 0; i < dataLen - 7; ++i) {
499 str->getChar();
502 } else {
503 for (i = 0; i < dataLen - 3; ++i) {
504 str->getChar();
508 } else if (boxType == 0x6A703263) { // codestream
509 cover(3);
510 if (!(haveBPC && haveCSMode)) {
511 getImageParams2(bitsPerComponent, csMode);
513 break;
514 } else {
515 cover(4);
516 for (i = 0; i < dataLen; ++i) {
517 str->getChar();
522 str->close();
525 // Get image parameters from the codestream.
526 void JPXStream::getImageParams2(int *bitsPerComponent,
527 StreamColorSpaceMode *csMode) {
528 int segType;
529 Guint segLen, nComps1, bpc1, dummy, i;
531 while (readMarkerHdr(&segType, &segLen)) {
532 if (segType == 0x51) { // SIZ - image and tile size
533 cover(5);
534 if (readUWord(&dummy) &&
535 readULong(&dummy) &&
536 readULong(&dummy) &&
537 readULong(&dummy) &&
538 readULong(&dummy) &&
539 readULong(&dummy) &&
540 readULong(&dummy) &&
541 readULong(&dummy) &&
542 readULong(&dummy) &&
543 readUWord(&nComps1) &&
544 readUByte(&bpc1)) {
545 *bitsPerComponent = (bpc1 & 0x7f) + 1;
546 // if there's no color space info, take a guess
547 if (nComps1 == 1) {
548 *csMode = streamCSDeviceGray;
549 } else if (nComps1 == 3) {
550 *csMode = streamCSDeviceRGB;
551 } else if (nComps1 == 4) {
552 *csMode = streamCSDeviceCMYK;
555 break;
556 } else {
557 cover(6);
558 if (segLen > 2) {
559 for (i = 0; i < segLen - 2; ++i) {
560 str->getChar();
567 GBool JPXStream::readBoxes() {
568 Guint boxType, boxLen, dataLen;
569 Guint bpc1, compression, unknownColorspace, ipr;
570 Guint i, j;
572 haveImgHdr = gFalse;
574 // check for a naked JPEG 2000 codestream (without the JP2/JPX
575 // wrapper) -- this appears to be a violation of the PDF spec, but
576 // Acrobat allows it
577 if (str->lookChar() == 0xff) {
578 cover(7);
579 error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
580 readCodestream(0);
581 nComps = img.nComps;
582 bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
583 for (i = 0; i < nComps; ++i) {
584 bpc[i] = img.tiles[0].tileComps[i].prec;
586 width = img.xSize - img.xOffset;
587 height = img.ySize - img.yOffset;
588 return gTrue;
591 while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
592 switch (boxType) {
593 case 0x6a703268: // JP2 header
594 // this is a grouping box ('superbox') which has no real
595 // contents and doesn't appear to be used consistently, i.e.,
596 // some things which should be subboxes of the JP2 header box
597 // show up outside of it - so we simply ignore the JP2 header
598 // box
599 cover(8);
600 break;
601 case 0x69686472: // image header
602 cover(9);
603 if (!readULong(&height) ||
604 !readULong(&width) ||
605 !readUWord(&nComps) ||
606 !readUByte(&bpc1) ||
607 !readUByte(&compression) ||
608 !readUByte(&unknownColorspace) ||
609 !readUByte(&ipr)) {
610 error(getPos(), "Unexpected EOF in JPX stream");
611 return gFalse;
613 if (compression != 7) {
614 error(getPos(), "Unknown compression type in JPX stream");
615 return gFalse;
617 bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
618 for (i = 0; i < nComps; ++i) {
619 bpc[i] = bpc1;
621 haveImgHdr = gTrue;
622 break;
623 case 0x62706363: // bits per component
624 cover(10);
625 if (!haveImgHdr) {
626 error(getPos(), "Found bits per component box before image header box in JPX stream");
627 return gFalse;
629 if (dataLen != nComps) {
630 error(getPos(), "Invalid bits per component box in JPX stream");
631 return gFalse;
633 for (i = 0; i < nComps; ++i) {
634 if (!readUByte(&bpc[i])) {
635 error(getPos(), "Unexpected EOF in JPX stream");
636 return gFalse;
639 break;
640 case 0x636F6C72: // color specification
641 cover(11);
642 if (!readColorSpecBox(dataLen)) {
643 return gFalse;
645 break;
646 case 0x70636c72: // palette
647 cover(12);
648 if (!readUWord(&palette.nEntries) ||
649 !readUByte(&palette.nComps)) {
650 error(getPos(), "Unexpected EOF in JPX stream");
651 return gFalse;
653 palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
654 palette.c =
655 (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
656 for (i = 0; i < palette.nComps; ++i) {
657 if (!readUByte(&palette.bpc[i])) {
658 error(getPos(), "Unexpected EOF in JPX stream");
659 return gFalse;
661 ++palette.bpc[i];
663 for (i = 0; i < palette.nEntries; ++i) {
664 for (j = 0; j < palette.nComps; ++j) {
665 if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3,
666 (palette.bpc[j] & 0x80) ? gTrue : gFalse,
667 &palette.c[i * palette.nComps + j])) {
668 error(getPos(), "Unexpected EOF in JPX stream");
669 return gFalse;
673 havePalette = gTrue;
674 break;
675 case 0x636d6170: // component mapping
676 cover(13);
677 compMap.nChannels = dataLen / 4;
678 compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
679 compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
680 compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
681 for (i = 0; i < compMap.nChannels; ++i) {
682 if (!readUWord(&compMap.comp[i]) ||
683 !readUByte(&compMap.type[i]) ||
684 !readUByte(&compMap.pComp[i])) {
685 error(getPos(), "Unexpected EOF in JPX stream");
686 return gFalse;
689 haveCompMap = gTrue;
690 break;
691 case 0x63646566: // channel definition
692 cover(14);
693 if (!readUWord(&channelDefn.nChannels)) {
694 error(getPos(), "Unexpected EOF in JPX stream");
695 return gFalse;
697 channelDefn.idx =
698 (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
699 channelDefn.type =
700 (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
701 channelDefn.assoc =
702 (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
703 for (i = 0; i < channelDefn.nChannels; ++i) {
704 if (!readUWord(&channelDefn.idx[i]) ||
705 !readUWord(&channelDefn.type[i]) ||
706 !readUWord(&channelDefn.assoc[i])) {
707 error(getPos(), "Unexpected EOF in JPX stream");
708 return gFalse;
711 haveChannelDefn = gTrue;
712 break;
713 case 0x6A703263: // contiguous codestream
714 cover(15);
715 if (!bpc) {
716 error(getPos(), "JPX stream is missing the image header box");
718 if (!haveCS) {
719 error(getPos(), "JPX stream has no supported color spec");
721 if (!readCodestream(dataLen)) {
722 return gFalse;
724 break;
725 default:
726 cover(16);
727 for (i = 0; i < dataLen; ++i) {
728 if (str->getChar() == EOF) {
729 error(getPos(), "Unexpected EOF in JPX stream");
730 return gFalse;
733 break;
736 return gTrue;
739 GBool JPXStream::readColorSpecBox(Guint dataLen) {
740 JPXColorSpec newCS;
741 Guint csApprox, csEnum;
742 Guint i;
743 GBool ok;
745 ok = gFalse;
746 if (!readUByte(&newCS.meth) ||
747 !readByte(&newCS.prec) ||
748 !readUByte(&csApprox)) {
749 goto err;
751 switch (newCS.meth) {
752 case 1: // enumerated colorspace
753 cover(17);
754 if (!readULong(&csEnum)) {
755 goto err;
757 newCS.enumerated.type = (JPXColorSpaceType)csEnum;
758 switch (newCS.enumerated.type) {
759 case jpxCSBiLevel:
760 ok = gTrue;
761 break;
762 case jpxCSYCbCr1:
763 ok = gTrue;
764 break;
765 case jpxCSYCbCr2:
766 ok = gTrue;
767 break;
768 case jpxCSYCBCr3:
769 ok = gTrue;
770 break;
771 case jpxCSPhotoYCC:
772 ok = gTrue;
773 break;
774 case jpxCSCMY:
775 ok = gTrue;
776 break;
777 case jpxCSCMYK:
778 ok = gTrue;
779 break;
780 case jpxCSYCCK:
781 ok = gTrue;
782 break;
783 case jpxCSCIELab:
784 if (dataLen == 7 + 7*4) {
785 if (!readULong(&newCS.enumerated.cieLab.rl) ||
786 !readULong(&newCS.enumerated.cieLab.ol) ||
787 !readULong(&newCS.enumerated.cieLab.ra) ||
788 !readULong(&newCS.enumerated.cieLab.oa) ||
789 !readULong(&newCS.enumerated.cieLab.rb) ||
790 !readULong(&newCS.enumerated.cieLab.ob) ||
791 !readULong(&newCS.enumerated.cieLab.il)) {
792 goto err;
794 } else if (dataLen == 7) {
795 //~ this assumes the 8-bit case
796 cover(92);
797 newCS.enumerated.cieLab.rl = 100;
798 newCS.enumerated.cieLab.ol = 0;
799 newCS.enumerated.cieLab.ra = 255;
800 newCS.enumerated.cieLab.oa = 128;
801 newCS.enumerated.cieLab.rb = 255;
802 newCS.enumerated.cieLab.ob = 96;
803 newCS.enumerated.cieLab.il = 0x00443530;
804 } else {
805 goto err;
807 ok = gTrue;
808 break;
809 case jpxCSsRGB:
810 ok = gTrue;
811 break;
812 case jpxCSGrayscale:
813 ok = gTrue;
814 break;
815 case jpxCSBiLevel2:
816 ok = gTrue;
817 break;
818 case jpxCSCIEJab:
819 // not allowed in PDF
820 goto err;
821 case jpxCSCISesRGB:
822 ok = gTrue;
823 break;
824 case jpxCSROMMRGB:
825 ok = gTrue;
826 break;
827 case jpxCSsRGBYCbCr:
828 ok = gTrue;
829 break;
830 case jpxCSYPbPr1125:
831 ok = gTrue;
832 break;
833 case jpxCSYPbPr1250:
834 ok = gTrue;
835 break;
836 default:
837 goto err;
839 break;
840 case 2: // restricted ICC profile
841 case 3: // any ICC profile (JPX)
842 case 4: // vendor color (JPX)
843 cover(18);
844 for (i = 0; i < dataLen - 3; ++i) {
845 if (str->getChar() == EOF) {
846 goto err;
849 break;
852 if (ok && (!haveCS || newCS.prec > cs.prec)) {
853 cs = newCS;
854 haveCS = gTrue;
857 return gTrue;
859 err:
860 error(getPos(), "Error in JPX color spec");
861 return gFalse;
864 GBool JPXStream::readCodestream(Guint len) {
865 JPXTile *tile;
866 JPXTileComp *tileComp;
867 int segType;
868 GBool haveSIZ, haveCOD, haveQCD, haveSOT;
869 Guint precinctSize, style;
870 Guint segLen, capabilities, comp, i, j, r;
872 //----- main header
873 haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
874 do {
875 if (!readMarkerHdr(&segType, &segLen)) {
876 error(getPos(), "Error in JPX codestream");
877 return gFalse;
879 switch (segType) {
880 case 0x4f: // SOC - start of codestream
881 // marker only
882 cover(19);
883 break;
884 case 0x51: // SIZ - image and tile size
885 cover(20);
886 if (!readUWord(&capabilities) ||
887 !readULong(&img.xSize) ||
888 !readULong(&img.ySize) ||
889 !readULong(&img.xOffset) ||
890 !readULong(&img.yOffset) ||
891 !readULong(&img.xTileSize) ||
892 !readULong(&img.yTileSize) ||
893 !readULong(&img.xTileOffset) ||
894 !readULong(&img.yTileOffset) ||
895 !readUWord(&img.nComps)) {
896 error(getPos(), "Error in JPX SIZ marker segment");
897 return gFalse;
899 if (haveImgHdr && img.nComps != nComps) {
900 error(getPos(), "Different number of components in JPX SIZ marker segment");
901 return gFalse;
903 img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1)
904 / img.xTileSize;
905 img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
906 / img.yTileSize;
907 // check for overflow before allocating memory
908 if (img.nXTiles <= 0 || img.nYTiles <= 0 ||
909 img.nXTiles >= INT_MAX / img.nYTiles) {
910 error(getPos(), "Bad tile count in JPX SIZ marker segment");
911 return gFalse;
913 img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles,
914 sizeof(JPXTile));
915 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
916 img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
917 sizeof(JPXTileComp));
918 for (comp = 0; comp < img.nComps; ++comp) {
919 img.tiles[i].tileComps[comp].quantSteps = NULL;
920 img.tiles[i].tileComps[comp].data = NULL;
921 img.tiles[i].tileComps[comp].buf = NULL;
922 img.tiles[i].tileComps[comp].resLevels = NULL;
925 for (comp = 0; comp < img.nComps; ++comp) {
926 if (!readUByte(&img.tiles[0].tileComps[comp].prec) ||
927 !readUByte(&img.tiles[0].tileComps[comp].hSep) ||
928 !readUByte(&img.tiles[0].tileComps[comp].vSep)) {
929 error(getPos(), "Error in JPX SIZ marker segment");
930 return gFalse;
932 img.tiles[0].tileComps[comp].sgned =
933 (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse;
934 img.tiles[0].tileComps[comp].prec =
935 (img.tiles[0].tileComps[comp].prec & 0x7f) + 1;
936 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
937 img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp];
940 haveSIZ = gTrue;
941 break;
942 case 0x52: // COD - coding style default
943 cover(21);
944 if (!readUByte(&img.tiles[0].tileComps[0].style) ||
945 !readUByte(&img.tiles[0].progOrder) ||
946 !readUWord(&img.tiles[0].nLayers) ||
947 !readUByte(&img.tiles[0].multiComp) ||
948 !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) ||
949 !readUByte(&img.tiles[0].tileComps[0].codeBlockW) ||
950 !readUByte(&img.tiles[0].tileComps[0].codeBlockH) ||
951 !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) ||
952 !readUByte(&img.tiles[0].tileComps[0].transform)) {
953 error(getPos(), "Error in JPX COD marker segment");
954 return gFalse;
956 img.tiles[0].tileComps[0].codeBlockW += 2;
957 img.tiles[0].tileComps[0].codeBlockH += 2;
958 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
959 if (i != 0) {
960 img.tiles[i].progOrder = img.tiles[0].progOrder;
961 img.tiles[i].nLayers = img.tiles[0].nLayers;
962 img.tiles[i].multiComp = img.tiles[0].multiComp;
964 for (comp = 0; comp < img.nComps; ++comp) {
965 if (!(i == 0 && comp == 0)) {
966 img.tiles[i].tileComps[comp].style =
967 img.tiles[0].tileComps[0].style;
968 img.tiles[i].tileComps[comp].nDecompLevels =
969 img.tiles[0].tileComps[0].nDecompLevels;
970 img.tiles[i].tileComps[comp].codeBlockW =
971 img.tiles[0].tileComps[0].codeBlockW;
972 img.tiles[i].tileComps[comp].codeBlockH =
973 img.tiles[0].tileComps[0].codeBlockH;
974 img.tiles[i].tileComps[comp].codeBlockStyle =
975 img.tiles[0].tileComps[0].codeBlockStyle;
976 img.tiles[i].tileComps[comp].transform =
977 img.tiles[0].tileComps[0].transform;
979 img.tiles[i].tileComps[comp].resLevels =
980 (JPXResLevel *)gmallocn(
981 (img.tiles[i].tileComps[comp].nDecompLevels + 1),
982 sizeof(JPXResLevel));
983 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
984 img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
988 for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
989 if (img.tiles[0].tileComps[0].style & 0x01) {
990 cover(91);
991 if (!readUByte(&precinctSize)) {
992 error(getPos(), "Error in JPX COD marker segment");
993 return gFalse;
995 img.tiles[0].tileComps[0].resLevels[r].precinctWidth =
996 precinctSize & 0x0f;
997 img.tiles[0].tileComps[0].resLevels[r].precinctHeight =
998 (precinctSize >> 4) & 0x0f;
999 } else {
1000 img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15;
1001 img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15;
1004 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1005 for (comp = 0; comp < img.nComps; ++comp) {
1006 if (!(i == 0 && comp == 0)) {
1007 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1008 img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
1009 img.tiles[0].tileComps[0].resLevels[r].precinctWidth;
1010 img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
1011 img.tiles[0].tileComps[0].resLevels[r].precinctHeight;
1016 haveCOD = gTrue;
1017 break;
1018 case 0x53: // COC - coding style component
1019 cover(22);
1020 if (!haveCOD) {
1021 error(getPos(), "JPX COC marker segment before COD segment");
1022 return gFalse;
1024 if ((img.nComps > 256 && !readUWord(&comp)) ||
1025 (img.nComps <= 256 && !readUByte(&comp)) ||
1026 comp >= img.nComps ||
1027 !readUByte(&style) ||
1028 !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) ||
1029 !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) ||
1030 !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) ||
1031 !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) ||
1032 !readUByte(&img.tiles[0].tileComps[comp].transform)) {
1033 error(getPos(), "Error in JPX COC marker segment");
1034 return gFalse;
1036 img.tiles[0].tileComps[comp].style =
1037 (img.tiles[0].tileComps[comp].style & ~1) | (style & 1);
1038 img.tiles[0].tileComps[comp].codeBlockW += 2;
1039 img.tiles[0].tileComps[comp].codeBlockH += 2;
1040 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1041 if (i != 0) {
1042 img.tiles[i].tileComps[comp].style =
1043 img.tiles[0].tileComps[comp].style;
1044 img.tiles[i].tileComps[comp].nDecompLevels =
1045 img.tiles[0].tileComps[comp].nDecompLevels;
1046 img.tiles[i].tileComps[comp].codeBlockW =
1047 img.tiles[0].tileComps[comp].codeBlockW;
1048 img.tiles[i].tileComps[comp].codeBlockH =
1049 img.tiles[0].tileComps[comp].codeBlockH;
1050 img.tiles[i].tileComps[comp].codeBlockStyle =
1051 img.tiles[0].tileComps[comp].codeBlockStyle;
1052 img.tiles[i].tileComps[comp].transform =
1053 img.tiles[0].tileComps[comp].transform;
1055 img.tiles[i].tileComps[comp].resLevels =
1056 (JPXResLevel *)greallocn(
1057 img.tiles[i].tileComps[comp].resLevels,
1058 (img.tiles[i].tileComps[comp].nDecompLevels + 1),
1059 sizeof(JPXResLevel));
1060 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1061 img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
1064 for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) {
1065 if (img.tiles[0].tileComps[comp].style & 0x01) {
1066 if (!readUByte(&precinctSize)) {
1067 error(getPos(), "Error in JPX COD marker segment");
1068 return gFalse;
1070 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth =
1071 precinctSize & 0x0f;
1072 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight =
1073 (precinctSize >> 4) & 0x0f;
1074 } else {
1075 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15;
1076 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15;
1079 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
1080 for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
1081 img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
1082 img.tiles[0].tileComps[comp].resLevels[r].precinctWidth;
1083 img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
1084 img.tiles[0].tileComps[comp].resLevels[r].precinctHeight;
1087 break;
1088 case 0x5c: // QCD - quantization default
1089 cover(23);
1090 if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
1091 error(getPos(), "Error in JPX QCD marker segment");
1092 return gFalse;
1094 if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
1095 img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
1096 img.tiles[0].tileComps[0].quantSteps =
1097 (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
1098 img.tiles[0].tileComps[0].nQuantSteps,
1099 sizeof(Guint));
1100 for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
1101 if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
1102 error(getPos(), "Error in JPX QCD marker segment");
1103 return gFalse;
1106 } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
1107 img.tiles[0].tileComps[0].nQuantSteps = 1;
1108 img.tiles[0].tileComps[0].quantSteps =
1109 (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
1110 img.tiles[0].tileComps[0].nQuantSteps,
1111 sizeof(Guint));
1112 if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
1113 error(getPos(), "Error in JPX QCD marker segment");
1114 return gFalse;
1116 } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
1117 img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
1118 img.tiles[0].tileComps[0].quantSteps =
1119 (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
1120 img.tiles[0].tileComps[0].nQuantSteps,
1121 sizeof(Guint));
1122 for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
1123 if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
1124 error(getPos(), "Error in JPX QCD marker segment");
1125 return gFalse;
1128 } else {
1129 error(getPos(), "Error in JPX QCD marker segment");
1130 return gFalse;
1132 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1133 for (comp = 0; comp < img.nComps; ++comp) {
1134 if (!(i == 0 && comp == 0)) {
1135 img.tiles[i].tileComps[comp].quantStyle =
1136 img.tiles[0].tileComps[0].quantStyle;
1137 img.tiles[i].tileComps[comp].nQuantSteps =
1138 img.tiles[0].tileComps[0].nQuantSteps;
1139 img.tiles[i].tileComps[comp].quantSteps =
1140 (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
1141 img.tiles[0].tileComps[0].nQuantSteps,
1142 sizeof(Guint));
1143 for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
1144 img.tiles[i].tileComps[comp].quantSteps[j] =
1145 img.tiles[0].tileComps[0].quantSteps[j];
1150 haveQCD = gTrue;
1151 break;
1152 case 0x5d: // QCC - quantization component
1153 cover(24);
1154 if (!haveQCD) {
1155 error(getPos(), "JPX QCC marker segment before QCD segment");
1156 return gFalse;
1158 if ((img.nComps > 256 && !readUWord(&comp)) ||
1159 (img.nComps <= 256 && !readUByte(&comp)) ||
1160 comp >= img.nComps ||
1161 !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) {
1162 error(getPos(), "Error in JPX QCC marker segment");
1163 return gFalse;
1165 if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) {
1166 img.tiles[0].tileComps[comp].nQuantSteps =
1167 segLen - (img.nComps > 256 ? 5 : 4);
1168 img.tiles[0].tileComps[comp].quantSteps =
1169 (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
1170 img.tiles[0].tileComps[comp].nQuantSteps,
1171 sizeof(Guint));
1172 for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
1173 if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
1174 error(getPos(), "Error in JPX QCC marker segment");
1175 return gFalse;
1178 } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
1179 img.tiles[0].tileComps[comp].nQuantSteps = 1;
1180 img.tiles[0].tileComps[comp].quantSteps =
1181 (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
1182 img.tiles[0].tileComps[comp].nQuantSteps,
1183 sizeof(Guint));
1184 if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
1185 error(getPos(), "Error in JPX QCC marker segment");
1186 return gFalse;
1188 } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) {
1189 img.tiles[0].tileComps[comp].nQuantSteps =
1190 (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
1191 img.tiles[0].tileComps[comp].quantSteps =
1192 (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
1193 img.tiles[0].tileComps[comp].nQuantSteps,
1194 sizeof(Guint));
1195 for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
1196 if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
1197 error(getPos(), "Error in JPX QCD marker segment");
1198 return gFalse;
1201 } else {
1202 error(getPos(), "Error in JPX QCC marker segment");
1203 return gFalse;
1205 for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
1206 img.tiles[i].tileComps[comp].quantStyle =
1207 img.tiles[0].tileComps[comp].quantStyle;
1208 img.tiles[i].tileComps[comp].nQuantSteps =
1209 img.tiles[0].tileComps[comp].nQuantSteps;
1210 img.tiles[i].tileComps[comp].quantSteps =
1211 (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
1212 img.tiles[0].tileComps[comp].nQuantSteps,
1213 sizeof(Guint));
1214 for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
1215 img.tiles[i].tileComps[comp].quantSteps[j] =
1216 img.tiles[0].tileComps[comp].quantSteps[j];
1219 break;
1220 case 0x5e: // RGN - region of interest
1221 cover(25);
1222 #if 1 //~ ROI is unimplemented
1223 fprintf(stderr, "RGN\n");
1224 for (i = 0; i < segLen - 2; ++i) {
1225 if (str->getChar() == EOF) {
1226 error(getPos(), "Error in JPX PPM marker segment");
1227 return gFalse;
1230 #else
1231 if ((img.nComps > 256 && !readUWord(&comp)) ||
1232 (img.nComps <= 256 && !readUByte(&comp)) ||
1233 comp >= img.nComps ||
1234 !readUByte(&compInfo[comp].defROI.style) ||
1235 !readUByte(&compInfo[comp].defROI.shift)) {
1236 error(getPos(), "Error in JPX RGN marker segment");
1237 return gFalse;
1239 #endif
1240 break;
1241 case 0x5f: // POC - progression order change
1242 cover(26);
1243 #if 1 //~ progression order changes are unimplemented
1244 fprintf(stderr, "POC\n");
1245 for (i = 0; i < segLen - 2; ++i) {
1246 if (str->getChar() == EOF) {
1247 error(getPos(), "Error in JPX PPM marker segment");
1248 return gFalse;
1251 #else
1252 nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
1253 progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
1254 for (i = 0; i < nProgs; ++i) {
1255 if (!readUByte(&progs[i].startRes) ||
1256 !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
1257 !(img.nComps <= 256 && readUByte(&progs[i].startComp)) ||
1258 !readUWord(&progs[i].endLayer) ||
1259 !readUByte(&progs[i].endRes) ||
1260 !(img.nComps > 256 && readUWord(&progs[i].endComp)) ||
1261 !(img.nComps <= 256 && readUByte(&progs[i].endComp)) ||
1262 !readUByte(&progs[i].progOrder)) {
1263 error(getPos(), "Error in JPX POC marker segment");
1264 return gFalse;
1267 #endif
1268 break;
1269 case 0x60: // PPM - packed packet headers, main header
1270 cover(27);
1271 #if 1 //~ packed packet headers are unimplemented
1272 fprintf(stderr, "PPM\n");
1273 for (i = 0; i < segLen - 2; ++i) {
1274 if (str->getChar() == EOF) {
1275 error(getPos(), "Error in JPX PPM marker segment");
1276 return gFalse;
1279 #endif
1280 break;
1281 case 0x55: // TLM - tile-part lengths
1282 // skipped
1283 cover(28);
1284 for (i = 0; i < segLen - 2; ++i) {
1285 if (str->getChar() == EOF) {
1286 error(getPos(), "Error in JPX TLM marker segment");
1287 return gFalse;
1290 break;
1291 case 0x57: // PLM - packet length, main header
1292 // skipped
1293 cover(29);
1294 for (i = 0; i < segLen - 2; ++i) {
1295 if (str->getChar() == EOF) {
1296 error(getPos(), "Error in JPX PLM marker segment");
1297 return gFalse;
1300 break;
1301 case 0x63: // CRG - component registration
1302 // skipped
1303 cover(30);
1304 for (i = 0; i < segLen - 2; ++i) {
1305 if (str->getChar() == EOF) {
1306 error(getPos(), "Error in JPX CRG marker segment");
1307 return gFalse;
1310 break;
1311 case 0x64: // COM - comment
1312 // skipped
1313 cover(31);
1314 for (i = 0; i < segLen - 2; ++i) {
1315 if (str->getChar() == EOF) {
1316 error(getPos(), "Error in JPX COM marker segment");
1317 return gFalse;
1320 break;
1321 case 0x90: // SOT - start of tile
1322 cover(32);
1323 haveSOT = gTrue;
1324 break;
1325 default:
1326 cover(33);
1327 error(getPos(), "Unknown marker segment %02x in JPX stream", segType);
1328 for (i = 0; i < segLen - 2; ++i) {
1329 if (str->getChar() == EOF) {
1330 break;
1333 break;
1335 } while (!haveSOT);
1337 if (!haveSIZ) {
1338 error(getPos(), "Missing SIZ marker segment in JPX stream");
1339 return gFalse;
1341 if (!haveCOD) {
1342 error(getPos(), "Missing COD marker segment in JPX stream");
1343 return gFalse;
1345 if (!haveQCD) {
1346 error(getPos(), "Missing QCD marker segment in JPX stream");
1347 return gFalse;
1350 //----- read the tile-parts
1351 while (1) {
1352 if (!readTilePart()) {
1353 return gFalse;
1355 if (!readMarkerHdr(&segType, &segLen)) {
1356 error(getPos(), "Error in JPX codestream");
1357 return gFalse;
1359 if (segType != 0x90) { // SOT - start of tile
1360 break;
1364 if (segType != 0xd9) { // EOC - end of codestream
1365 error(getPos(), "Missing EOC marker in JPX codestream");
1366 return gFalse;
1369 //----- finish decoding the image
1370 for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
1371 tile = &img.tiles[i];
1372 for (comp = 0; comp < img.nComps; ++comp) {
1373 tileComp = &tile->tileComps[comp];
1374 inverseTransform(tileComp);
1376 if (!inverseMultiCompAndDC(tile)) {
1377 return gFalse;
1381 //~ can free memory below tileComps here, and also tileComp.buf
1383 return gTrue;
1386 GBool JPXStream::readTilePart() {
1387 JPXTile *tile;
1388 JPXTileComp *tileComp;
1389 JPXResLevel *resLevel;
1390 JPXPrecinct *precinct;
1391 JPXSubband *subband;
1392 JPXCodeBlock *cb;
1393 GBool haveSOD;
1394 Guint tileIdx, tilePartLen, tilePartIdx, nTileParts;
1395 GBool tilePartToEOC;
1396 Guint precinctSize, style;
1397 Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
1398 Guint i, j, k, cbX, cbY, r, pre, sb, cbi;
1399 int segType, level;
1401 // process the SOT marker segment
1402 if (!readUWord(&tileIdx) ||
1403 !readULong(&tilePartLen) ||
1404 !readUByte(&tilePartIdx) ||
1405 !readUByte(&nTileParts)) {
1406 error(getPos(), "Error in JPX SOT marker segment");
1407 return gFalse;
1410 if (tileIdx >= img.nXTiles * img.nYTiles) {
1411 error(getPos(), "Weird tile index in JPX stream");
1412 return gFalse;
1415 tilePartToEOC = tilePartLen == 0;
1416 tilePartLen -= 12; // subtract size of SOT segment
1418 haveSOD = gFalse;
1419 do {
1420 if (!readMarkerHdr(&segType, &segLen)) {
1421 error(getPos(), "Error in JPX tile-part codestream");
1422 return gFalse;
1424 tilePartLen -= 2 + segLen;
1425 switch (segType) {
1426 case 0x52: // COD - coding style default
1427 cover(34);
1428 if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
1429 !readUByte(&img.tiles[tileIdx].progOrder) ||
1430 !readUWord(&img.tiles[tileIdx].nLayers) ||
1431 !readUByte(&img.tiles[tileIdx].multiComp) ||
1432 !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) ||
1433 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) ||
1434 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) ||
1435 !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) ||
1436 !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) {
1437 error(getPos(), "Error in JPX COD marker segment");
1438 return gFalse;
1440 img.tiles[tileIdx].tileComps[0].codeBlockW += 2;
1441 img.tiles[tileIdx].tileComps[0].codeBlockH += 2;
1442 for (comp = 0; comp < img.nComps; ++comp) {
1443 if (comp != 0) {
1444 img.tiles[tileIdx].tileComps[comp].style =
1445 img.tiles[tileIdx].tileComps[0].style;
1446 img.tiles[tileIdx].tileComps[comp].nDecompLevels =
1447 img.tiles[tileIdx].tileComps[0].nDecompLevels;
1448 img.tiles[tileIdx].tileComps[comp].codeBlockW =
1449 img.tiles[tileIdx].tileComps[0].codeBlockW;
1450 img.tiles[tileIdx].tileComps[comp].codeBlockH =
1451 img.tiles[tileIdx].tileComps[0].codeBlockH;
1452 img.tiles[tileIdx].tileComps[comp].codeBlockStyle =
1453 img.tiles[tileIdx].tileComps[0].codeBlockStyle;
1454 img.tiles[tileIdx].tileComps[comp].transform =
1455 img.tiles[tileIdx].tileComps[0].transform;
1457 img.tiles[tileIdx].tileComps[comp].resLevels =
1458 (JPXResLevel *)greallocn(
1459 img.tiles[tileIdx].tileComps[comp].resLevels,
1460 (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
1461 sizeof(JPXResLevel));
1462 for (r = 0;
1463 r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
1464 ++r) {
1465 img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
1468 for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) {
1469 if (img.tiles[tileIdx].tileComps[0].style & 0x01) {
1470 if (!readUByte(&precinctSize)) {
1471 error(getPos(), "Error in JPX COD marker segment");
1472 return gFalse;
1474 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth =
1475 precinctSize & 0x0f;
1476 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight =
1477 (precinctSize >> 4) & 0x0f;
1478 } else {
1479 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15;
1480 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15;
1483 for (comp = 1; comp < img.nComps; ++comp) {
1484 for (r = 0;
1485 r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
1486 ++r) {
1487 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
1488 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth;
1489 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
1490 img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight;
1493 break;
1494 case 0x53: // COC - coding style component
1495 cover(35);
1496 if ((img.nComps > 256 && !readUWord(&comp)) ||
1497 (img.nComps <= 256 && !readUByte(&comp)) ||
1498 comp >= img.nComps ||
1499 !readUByte(&style) ||
1500 !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) ||
1501 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) ||
1502 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) ||
1503 !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) ||
1504 !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) {
1505 error(getPos(), "Error in JPX COC marker segment");
1506 return gFalse;
1508 img.tiles[tileIdx].tileComps[comp].style =
1509 (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1);
1510 img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
1511 img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
1512 img.tiles[tileIdx].tileComps[comp].resLevels =
1513 (JPXResLevel *)greallocn(
1514 img.tiles[tileIdx].tileComps[comp].resLevels,
1515 (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
1516 sizeof(JPXResLevel));
1517 for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
1518 img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
1520 for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
1521 if (img.tiles[tileIdx].tileComps[comp].style & 0x01) {
1522 if (!readUByte(&precinctSize)) {
1523 error(getPos(), "Error in JPX COD marker segment");
1524 return gFalse;
1526 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
1527 precinctSize & 0x0f;
1528 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
1529 (precinctSize >> 4) & 0x0f;
1530 } else {
1531 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15;
1532 img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15;
1535 break;
1536 case 0x5c: // QCD - quantization default
1537 cover(36);
1538 if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
1539 error(getPos(), "Error in JPX QCD marker segment");
1540 return gFalse;
1542 if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) {
1543 img.tiles[tileIdx].tileComps[0].nQuantSteps =
1544 segLen - 3;
1545 img.tiles[tileIdx].tileComps[0].quantSteps =
1546 (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
1547 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1548 sizeof(Guint));
1549 for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
1550 if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
1551 error(getPos(), "Error in JPX QCD marker segment");
1552 return gFalse;
1555 } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
1556 img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
1557 img.tiles[tileIdx].tileComps[0].quantSteps =
1558 (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
1559 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1560 sizeof(Guint));
1561 if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
1562 error(getPos(), "Error in JPX QCD marker segment");
1563 return gFalse;
1565 } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
1566 img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
1567 img.tiles[tileIdx].tileComps[0].quantSteps =
1568 (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
1569 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1570 sizeof(Guint));
1571 for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
1572 if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
1573 error(getPos(), "Error in JPX QCD marker segment");
1574 return gFalse;
1577 } else {
1578 error(getPos(), "Error in JPX QCD marker segment");
1579 return gFalse;
1581 for (comp = 1; comp < img.nComps; ++comp) {
1582 img.tiles[tileIdx].tileComps[comp].quantStyle =
1583 img.tiles[tileIdx].tileComps[0].quantStyle;
1584 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1585 img.tiles[tileIdx].tileComps[0].nQuantSteps;
1586 img.tiles[tileIdx].tileComps[comp].quantSteps =
1587 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1588 img.tiles[tileIdx].tileComps[0].nQuantSteps,
1589 sizeof(Guint));
1590 for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
1591 img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
1592 img.tiles[tileIdx].tileComps[0].quantSteps[j];
1595 break;
1596 case 0x5d: // QCC - quantization component
1597 cover(37);
1598 if ((img.nComps > 256 && !readUWord(&comp)) ||
1599 (img.nComps <= 256 && !readUByte(&comp)) ||
1600 comp >= img.nComps ||
1601 !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) {
1602 error(getPos(), "Error in JPX QCC marker segment");
1603 return gFalse;
1605 if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) {
1606 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1607 segLen - (img.nComps > 256 ? 5 : 4);
1608 img.tiles[tileIdx].tileComps[comp].quantSteps =
1609 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1610 img.tiles[tileIdx].tileComps[comp].nQuantSteps,
1611 sizeof(Guint));
1612 for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
1613 if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
1614 error(getPos(), "Error in JPX QCC marker segment");
1615 return gFalse;
1618 } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
1619 == 0x01) {
1620 img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
1621 img.tiles[tileIdx].tileComps[comp].quantSteps =
1622 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1623 img.tiles[tileIdx].tileComps[comp].nQuantSteps,
1624 sizeof(Guint));
1625 if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
1626 error(getPos(), "Error in JPX QCC marker segment");
1627 return gFalse;
1629 } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
1630 == 0x02) {
1631 img.tiles[tileIdx].tileComps[comp].nQuantSteps =
1632 (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
1633 img.tiles[tileIdx].tileComps[comp].quantSteps =
1634 (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
1635 img.tiles[tileIdx].tileComps[comp].nQuantSteps,
1636 sizeof(Guint));
1637 for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
1638 if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
1639 error(getPos(), "Error in JPX QCD marker segment");
1640 return gFalse;
1643 } else {
1644 error(getPos(), "Error in JPX QCC marker segment");
1645 return gFalse;
1647 break;
1648 case 0x5e: // RGN - region of interest
1649 cover(38);
1650 #if 1 //~ ROI is unimplemented
1651 fprintf(stderr, "RGN\n");
1652 for (i = 0; i < segLen - 2; ++i) {
1653 if (str->getChar() == EOF) {
1654 error(getPos(), "Error in JPX PPM marker segment");
1655 return gFalse;
1658 #else
1659 if ((img.nComps > 256 && !readUWord(&comp)) ||
1660 (img.nComps <= 256 && !readUByte(&comp)) ||
1661 comp >= img.nComps ||
1662 !readUByte(&compInfo[comp].roi.style) ||
1663 !readUByte(&compInfo[comp].roi.shift)) {
1664 error(getPos(), "Error in JPX RGN marker segment");
1665 return gFalse;
1667 #endif
1668 break;
1669 case 0x5f: // POC - progression order change
1670 cover(39);
1671 #if 1 //~ progression order changes are unimplemented
1672 fprintf(stderr, "POC\n");
1673 for (i = 0; i < segLen - 2; ++i) {
1674 if (str->getChar() == EOF) {
1675 error(getPos(), "Error in JPX PPM marker segment");
1676 return gFalse;
1679 #else
1680 nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
1681 tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
1682 for (i = 0; i < nTileProgs; ++i) {
1683 if (!readUByte(&tileProgs[i].startRes) ||
1684 !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
1685 !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) ||
1686 !readUWord(&tileProgs[i].endLayer) ||
1687 !readUByte(&tileProgs[i].endRes) ||
1688 !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) ||
1689 !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) ||
1690 !readUByte(&tileProgs[i].progOrder)) {
1691 error(getPos(), "Error in JPX POC marker segment");
1692 return gFalse;
1695 #endif
1696 break;
1697 case 0x61: // PPT - packed packet headers, tile-part hdr
1698 cover(40);
1699 #if 1 //~ packed packet headers are unimplemented
1700 fprintf(stderr, "PPT\n");
1701 for (i = 0; i < segLen - 2; ++i) {
1702 if (str->getChar() == EOF) {
1703 error(getPos(), "Error in JPX PPT marker segment");
1704 return gFalse;
1707 #endif
1708 case 0x58: // PLT - packet length, tile-part header
1709 // skipped
1710 cover(41);
1711 for (i = 0; i < segLen - 2; ++i) {
1712 if (str->getChar() == EOF) {
1713 error(getPos(), "Error in JPX PLT marker segment");
1714 return gFalse;
1717 break;
1718 case 0x64: // COM - comment
1719 // skipped
1720 cover(42);
1721 for (i = 0; i < segLen - 2; ++i) {
1722 if (str->getChar() == EOF) {
1723 error(getPos(), "Error in JPX COM marker segment");
1724 return gFalse;
1727 break;
1728 case 0x93: // SOD - start of data
1729 cover(43);
1730 haveSOD = gTrue;
1731 break;
1732 default:
1733 cover(44);
1734 error(getPos(), "Unknown marker segment %02x in JPX tile-part stream",
1735 segType);
1736 for (i = 0; i < segLen - 2; ++i) {
1737 if (str->getChar() == EOF) {
1738 break;
1741 break;
1743 } while (!haveSOD);
1745 //----- initialize the tile, precincts, and code-blocks
1746 if (tilePartIdx == 0) {
1747 tile = &img.tiles[tileIdx];
1748 i = tileIdx / img.nXTiles;
1749 j = tileIdx % img.nXTiles;
1750 if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
1751 tile->x0 = img.xOffset;
1753 if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) {
1754 tile->y0 = img.yOffset;
1756 if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) {
1757 tile->x1 = img.xSize;
1759 if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) {
1760 tile->y1 = img.ySize;
1762 tile->comp = 0;
1763 tile->res = 0;
1764 tile->precinct = 0;
1765 tile->layer = 0;
1766 tile->maxNDecompLevels = 0;
1767 for (comp = 0; comp < img.nComps; ++comp) {
1768 tileComp = &tile->tileComps[comp];
1769 if (tileComp->nDecompLevels > tile->maxNDecompLevels) {
1770 tile->maxNDecompLevels = tileComp->nDecompLevels;
1772 tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep);
1773 tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep);
1774 tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
1775 tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
1776 tileComp->cbW = 1 << tileComp->codeBlockW;
1777 tileComp->cbH = 1 << tileComp->codeBlockH;
1778 tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
1779 (tileComp->y1 - tileComp->y0),
1780 sizeof(int));
1781 if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
1782 n = tileComp->x1 - tileComp->x0;
1783 } else {
1784 n = tileComp->y1 - tileComp->y0;
1786 tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
1787 for (r = 0; r <= tileComp->nDecompLevels; ++r) {
1788 resLevel = &tileComp->resLevels[r];
1789 k = r == 0 ? tileComp->nDecompLevels
1790 : tileComp->nDecompLevels - r + 1;
1791 resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
1792 resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
1793 resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
1794 resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
1795 if (r == 0) {
1796 resLevel->bx0[0] = resLevel->x0;
1797 resLevel->by0[0] = resLevel->y0;
1798 resLevel->bx1[0] = resLevel->x1;
1799 resLevel->by1[0] = resLevel->y1;
1800 } else {
1801 resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
1802 resLevel->by0[0] = resLevel->y0;
1803 resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
1804 resLevel->by1[0] = resLevel->y1;
1805 resLevel->bx0[1] = resLevel->x0;
1806 resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
1807 resLevel->bx1[1] = resLevel->x1;
1808 resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
1809 resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
1810 resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
1811 resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
1812 resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
1814 resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
1815 for (pre = 0; pre < 1; ++pre) {
1816 precinct = &resLevel->precincts[pre];
1817 precinct->x0 = resLevel->x0;
1818 precinct->y0 = resLevel->y0;
1819 precinct->x1 = resLevel->x1;
1820 precinct->y1 = resLevel->y1;
1821 nSBs = r == 0 ? 1 : 3;
1822 precinct->subbands =
1823 (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
1824 for (sb = 0; sb < nSBs; ++sb) {
1825 subband = &precinct->subbands[sb];
1826 subband->x0 = resLevel->bx0[sb];
1827 subband->y0 = resLevel->by0[sb];
1828 subband->x1 = resLevel->bx1[sb];
1829 subband->y1 = resLevel->by1[sb];
1830 subband->nXCBs = jpxCeilDivPow2(subband->x1,
1831 tileComp->codeBlockW)
1832 - jpxFloorDivPow2(subband->x0,
1833 tileComp->codeBlockW);
1834 subband->nYCBs = jpxCeilDivPow2(subband->y1,
1835 tileComp->codeBlockH)
1836 - jpxFloorDivPow2(subband->y0,
1837 tileComp->codeBlockH);
1838 n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
1839 : subband->nYCBs;
1840 for (subband->maxTTLevel = 0, --n;
1842 ++subband->maxTTLevel, n >>= 1) ;
1843 n = 0;
1844 for (level = subband->maxTTLevel; level >= 0; --level) {
1845 nx = jpxCeilDivPow2(subband->nXCBs, level);
1846 ny = jpxCeilDivPow2(subband->nYCBs, level);
1847 n += nx * ny;
1849 subband->inclusion =
1850 (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
1851 subband->zeroBitPlane =
1852 (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
1853 for (k = 0; k < n; ++k) {
1854 subband->inclusion[k].finished = gFalse;
1855 subband->inclusion[k].val = 0;
1856 subband->zeroBitPlane[k].finished = gFalse;
1857 subband->zeroBitPlane[k].val = 0;
1859 subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
1860 subband->nYCBs,
1861 sizeof(JPXCodeBlock));
1862 sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
1863 sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
1864 cb = subband->cbs;
1865 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1866 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1867 cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
1868 cb->x1 = cb->x0 + tileComp->cbW;
1869 if (subband->x0 > cb->x0) {
1870 cb->x0 = subband->x0;
1872 if (subband->x1 < cb->x1) {
1873 cb->x1 = subband->x1;
1875 cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
1876 cb->y1 = cb->y0 + tileComp->cbH;
1877 if (subband->y0 > cb->y0) {
1878 cb->y0 = subband->y0;
1880 if (subband->y1 < cb->y1) {
1881 cb->y1 = subband->y1;
1883 cb->seen = gFalse;
1884 cb->lBlock = 3;
1885 cb->nextPass = jpxPassCleanup;
1886 cb->nZeroBitPlanes = 0;
1887 cb->coeffs =
1888 (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW
1889 + tileComp->codeBlockH)),
1890 sizeof(JPXCoeff));
1891 for (cbi = 0;
1892 cbi < (Guint)(1 << (tileComp->codeBlockW
1893 + tileComp->codeBlockH));
1894 ++cbi) {
1895 cb->coeffs[cbi].flags = 0;
1896 cb->coeffs[cbi].len = 0;
1897 cb->coeffs[cbi].mag = 0;
1899 cb->arithDecoder = NULL;
1900 cb->stats = NULL;
1901 ++cb;
1910 return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
1913 GBool JPXStream::readTilePartData(Guint tileIdx,
1914 Guint tilePartLen, GBool tilePartToEOC) {
1915 JPXTile *tile;
1916 JPXTileComp *tileComp;
1917 JPXResLevel *resLevel;
1918 JPXPrecinct *precinct;
1919 JPXSubband *subband;
1920 JPXCodeBlock *cb;
1921 Guint ttVal;
1922 Guint bits, cbX, cbY, nx, ny, i, j, n, sb;
1923 int level;
1925 tile = &img.tiles[tileIdx];
1927 // read all packets from this tile-part
1928 while (1) {
1929 if (tilePartToEOC) {
1930 //~ peek for an EOC marker
1931 cover(93);
1932 } else if (tilePartLen == 0) {
1933 break;
1936 tileComp = &tile->tileComps[tile->comp];
1937 resLevel = &tileComp->resLevels[tile->res];
1938 precinct = &resLevel->precincts[tile->precinct];
1940 //----- packet header
1942 // setup
1943 startBitBuf(tilePartLen);
1945 // zero-length flag
1946 if (!readBits(1, &bits)) {
1947 goto err;
1949 if (!bits) {
1950 // packet is empty -- clear all code-block inclusion flags
1951 cover(45);
1952 for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
1953 subband = &precinct->subbands[sb];
1954 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1955 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1956 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
1957 cb->included = gFalse;
1961 } else {
1963 for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
1964 subband = &precinct->subbands[sb];
1965 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
1966 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
1967 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
1969 // skip code-blocks with no coefficients
1970 if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
1971 cover(46);
1972 cb->included = gFalse;
1973 continue;
1976 // code-block inclusion
1977 if (cb->seen) {
1978 cover(47);
1979 if (!readBits(1, &cb->included)) {
1980 goto err;
1982 } else {
1983 cover(48);
1984 ttVal = 0;
1985 i = 0;
1986 for (level = subband->maxTTLevel; level >= 0; --level) {
1987 nx = jpxCeilDivPow2(subband->nXCBs, level);
1988 ny = jpxCeilDivPow2(subband->nYCBs, level);
1989 j = i + (cbY >> level) * nx + (cbX >> level);
1990 if (!subband->inclusion[j].finished &&
1991 !subband->inclusion[j].val) {
1992 subband->inclusion[j].val = ttVal;
1993 } else {
1994 ttVal = subband->inclusion[j].val;
1996 while (!subband->inclusion[j].finished &&
1997 ttVal <= tile->layer) {
1998 if (!readBits(1, &bits)) {
1999 goto err;
2001 if (bits == 1) {
2002 subband->inclusion[j].finished = gTrue;
2003 } else {
2004 ++ttVal;
2007 subband->inclusion[j].val = ttVal;
2008 if (ttVal > tile->layer) {
2009 break;
2011 i += nx * ny;
2013 cb->included = level < 0;
2016 if (cb->included) {
2017 cover(49);
2019 // zero bit-plane count
2020 if (!cb->seen) {
2021 cover(50);
2022 ttVal = 0;
2023 i = 0;
2024 for (level = subband->maxTTLevel; level >= 0; --level) {
2025 nx = jpxCeilDivPow2(subband->nXCBs, level);
2026 ny = jpxCeilDivPow2(subband->nYCBs, level);
2027 j = i + (cbY >> level) * nx + (cbX >> level);
2028 if (!subband->zeroBitPlane[j].finished &&
2029 !subband->zeroBitPlane[j].val) {
2030 subband->zeroBitPlane[j].val = ttVal;
2031 } else {
2032 ttVal = subband->zeroBitPlane[j].val;
2034 while (!subband->zeroBitPlane[j].finished) {
2035 if (!readBits(1, &bits)) {
2036 goto err;
2038 if (bits == 1) {
2039 subband->zeroBitPlane[j].finished = gTrue;
2040 } else {
2041 ++ttVal;
2044 subband->zeroBitPlane[j].val = ttVal;
2045 i += nx * ny;
2047 cb->nZeroBitPlanes = ttVal;
2050 // number of coding passes
2051 if (!readBits(1, &bits)) {
2052 goto err;
2054 if (bits == 0) {
2055 cover(51);
2056 cb->nCodingPasses = 1;
2057 } else {
2058 if (!readBits(1, &bits)) {
2059 goto err;
2061 if (bits == 0) {
2062 cover(52);
2063 cb->nCodingPasses = 2;
2064 } else {
2065 cover(53);
2066 if (!readBits(2, &bits)) {
2067 goto err;
2069 if (bits < 3) {
2070 cover(54);
2071 cb->nCodingPasses = 3 + bits;
2072 } else {
2073 cover(55);
2074 if (!readBits(5, &bits)) {
2075 goto err;
2077 if (bits < 31) {
2078 cover(56);
2079 cb->nCodingPasses = 6 + bits;
2080 } else {
2081 cover(57);
2082 if (!readBits(7, &bits)) {
2083 goto err;
2085 cb->nCodingPasses = 37 + bits;
2091 // update Lblock
2092 while (1) {
2093 if (!readBits(1, &bits)) {
2094 goto err;
2096 if (!bits) {
2097 break;
2099 ++cb->lBlock;
2102 // length of compressed data
2103 //~ deal with multiple codeword segments
2104 for (n = cb->lBlock, i = cb->nCodingPasses >> 1;
2106 ++n, i >>= 1) ;
2107 if (!readBits(n, &cb->dataLen)) {
2108 goto err;
2115 tilePartLen = finishBitBuf();
2117 //----- packet data
2119 for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
2120 subband = &precinct->subbands[sb];
2121 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2122 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2123 cb = &subband->cbs[cbY * subband->nXCBs + cbX];
2124 if (cb->included) {
2125 if (!readCodeBlockData(tileComp, resLevel, precinct, subband,
2126 tile->res, sb, cb)) {
2127 return gFalse;
2129 tilePartLen -= cb->dataLen;
2130 cb->seen = gTrue;
2136 //----- next packet
2138 switch (tile->progOrder) {
2139 case 0: // layer, resolution level, component, precinct
2140 cover(58);
2141 if (++tile->comp == img.nComps) {
2142 tile->comp = 0;
2143 if (++tile->res == tile->maxNDecompLevels + 1) {
2144 tile->res = 0;
2145 if (++tile->layer == tile->nLayers) {
2146 tile->layer = 0;
2150 break;
2151 case 1: // resolution level, layer, component, precinct
2152 cover(59);
2153 if (++tile->comp == img.nComps) {
2154 tile->comp = 0;
2155 if (++tile->layer == tile->nLayers) {
2156 tile->layer = 0;
2157 if (++tile->res == tile->maxNDecompLevels + 1) {
2158 tile->res = 0;
2162 break;
2163 case 2: // resolution level, precinct, component, layer
2164 //~ this isn't correct -- see B.12.1.3
2165 cover(60);
2166 if (++tile->layer == tile->nLayers) {
2167 tile->layer = 0;
2168 if (++tile->comp == img.nComps) {
2169 tile->comp = 0;
2170 if (++tile->res == tile->maxNDecompLevels + 1) {
2171 tile->res = 0;
2175 break;
2176 case 3: // precinct, component, resolution level, layer
2177 //~ this isn't correct -- see B.12.1.4
2178 cover(61);
2179 if (++tile->layer == tile->nLayers) {
2180 tile->layer = 0;
2181 if (++tile->res == tile->maxNDecompLevels + 1) {
2182 tile->res = 0;
2183 if (++tile->comp == img.nComps) {
2184 tile->comp = 0;
2188 break;
2189 case 4: // component, precinct, resolution level, layer
2190 //~ this isn't correct -- see B.12.1.5
2191 cover(62);
2192 if (++tile->layer == tile->nLayers) {
2193 tile->layer = 0;
2194 if (++tile->res == tile->maxNDecompLevels + 1) {
2195 tile->res = 0;
2196 if (++tile->comp == img.nComps) {
2197 tile->comp = 0;
2201 break;
2205 return gTrue;
2207 err:
2208 error(getPos(), "Error in JPX stream");
2209 return gFalse;
2212 GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
2213 JPXResLevel *resLevel,
2214 JPXPrecinct *precinct,
2215 JPXSubband *subband,
2216 Guint res, Guint sb,
2217 JPXCodeBlock *cb) {
2218 JPXCoeff *coeff0, *coeff1, *coeff;
2219 Guint horiz, vert, diag, all, cx, xorBit;
2220 int horizSign, vertSign;
2221 Guint i, x, y0, y1, y2;
2223 if (cb->arithDecoder) {
2224 cover(63);
2225 cb->arithDecoder->restart(cb->dataLen);
2226 } else {
2227 cover(64);
2228 cb->arithDecoder = new JArithmeticDecoder();
2229 cb->arithDecoder->setStream(str, cb->dataLen);
2230 cb->arithDecoder->start();
2231 cb->stats = new JArithmeticDecoderStats(jpxNContexts);
2232 cb->stats->setEntry(jpxContextSigProp, 4, 0);
2233 cb->stats->setEntry(jpxContextRunLength, 3, 0);
2234 cb->stats->setEntry(jpxContextUniform, 46, 0);
2237 for (i = 0; i < cb->nCodingPasses; ++i) {
2238 switch (cb->nextPass) {
2240 //----- significance propagation pass
2241 case jpxPassSigProp:
2242 cover(65);
2243 for (y0 = cb->y0, coeff0 = cb->coeffs;
2244 y0 < cb->y1;
2245 y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
2246 for (x = cb->x0, coeff1 = coeff0;
2247 x < cb->x1;
2248 ++x, ++coeff1) {
2249 for (y1 = 0, coeff = coeff1;
2250 y1 < 4 && y0+y1 < cb->y1;
2251 ++y1, coeff += tileComp->cbW) {
2252 if (!(coeff->flags & jpxCoeffSignificant)) {
2253 horiz = vert = diag = 0;
2254 horizSign = vertSign = 2;
2255 if (x > cb->x0) {
2256 if (coeff[-1].flags & jpxCoeffSignificant) {
2257 ++horiz;
2258 horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
2260 if (y0+y1 > cb->y0) {
2261 diag += (coeff[-(int)tileComp->cbW - 1].flags
2262 >> jpxCoeffSignificantB) & 1;
2264 if (y0+y1 < cb->y1 - 1) {
2265 diag += (coeff[tileComp->cbW - 1].flags
2266 >> jpxCoeffSignificantB) & 1;
2269 if (x < cb->x1 - 1) {
2270 if (coeff[1].flags & jpxCoeffSignificant) {
2271 ++horiz;
2272 horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
2274 if (y0+y1 > cb->y0) {
2275 diag += (coeff[-(int)tileComp->cbW + 1].flags
2276 >> jpxCoeffSignificantB) & 1;
2278 if (y0+y1 < cb->y1 - 1) {
2279 diag += (coeff[tileComp->cbW + 1].flags
2280 >> jpxCoeffSignificantB) & 1;
2283 if (y0+y1 > cb->y0) {
2284 if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
2285 ++vert;
2286 vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
2287 ? -1 : 1;
2290 if (y0+y1 < cb->y1 - 1) {
2291 if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
2292 ++vert;
2293 vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
2294 ? -1 : 1;
2297 cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
2298 if (cx != 0) {
2299 if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
2300 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
2301 coeff->mag = (coeff->mag << 1) | 1;
2302 cx = signContext[horizSign][vertSign][0];
2303 xorBit = signContext[horizSign][vertSign][1];
2304 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2305 coeff->flags |= jpxCoeffSign;
2308 ++coeff->len;
2309 coeff->flags |= jpxCoeffTouched;
2315 ++cb->nextPass;
2316 break;
2318 //----- magnitude refinement pass
2319 case jpxPassMagRef:
2320 cover(66);
2321 for (y0 = cb->y0, coeff0 = cb->coeffs;
2322 y0 < cb->y1;
2323 y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
2324 for (x = cb->x0, coeff1 = coeff0;
2325 x < cb->x1;
2326 ++x, ++coeff1) {
2327 for (y1 = 0, coeff = coeff1;
2328 y1 < 4 && y0+y1 < cb->y1;
2329 ++y1, coeff += tileComp->cbW) {
2330 if ((coeff->flags & jpxCoeffSignificant) &&
2331 !(coeff->flags & jpxCoeffTouched)) {
2332 if (coeff->flags & jpxCoeffFirstMagRef) {
2333 all = 0;
2334 if (x > cb->x0) {
2335 all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
2336 if (y0+y1 > cb->y0) {
2337 all += (coeff[-(int)tileComp->cbW - 1].flags
2338 >> jpxCoeffSignificantB) & 1;
2340 if (y0+y1 < cb->y1 - 1) {
2341 all += (coeff[tileComp->cbW - 1].flags
2342 >> jpxCoeffSignificantB) & 1;
2345 if (x < cb->x1 - 1) {
2346 all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
2347 if (y0+y1 > cb->y0) {
2348 all += (coeff[-(int)tileComp->cbW + 1].flags
2349 >> jpxCoeffSignificantB) & 1;
2351 if (y0+y1 < cb->y1 - 1) {
2352 all += (coeff[tileComp->cbW + 1].flags
2353 >> jpxCoeffSignificantB) & 1;
2356 if (y0+y1 > cb->y0) {
2357 all += (coeff[-(int)tileComp->cbW].flags
2358 >> jpxCoeffSignificantB) & 1;
2360 if (y0+y1 < cb->y1 - 1) {
2361 all += (coeff[tileComp->cbW].flags
2362 >> jpxCoeffSignificantB) & 1;
2364 cx = all ? 15 : 14;
2365 } else {
2366 cx = 16;
2368 coeff->mag = (coeff->mag << 1) |
2369 cb->arithDecoder->decodeBit(cx, cb->stats);
2370 ++coeff->len;
2371 coeff->flags |= jpxCoeffTouched;
2372 coeff->flags &= ~jpxCoeffFirstMagRef;
2377 ++cb->nextPass;
2378 break;
2380 //----- cleanup pass
2381 case jpxPassCleanup:
2382 cover(67);
2383 for (y0 = cb->y0, coeff0 = cb->coeffs;
2384 y0 < cb->y1;
2385 y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
2386 for (x = cb->x0, coeff1 = coeff0;
2387 x < cb->x1;
2388 ++x, ++coeff1) {
2389 y1 = 0;
2390 if (y0 + 3 < cb->y1 &&
2391 !(coeff1->flags & jpxCoeffTouched) &&
2392 !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) &&
2393 !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
2394 !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
2395 (x == cb->x0 || y0 == cb->y0 ||
2396 !(coeff1[-(int)tileComp->cbW - 1].flags
2397 & jpxCoeffSignificant)) &&
2398 (y0 == cb->y0 ||
2399 !(coeff1[-(int)tileComp->cbW].flags
2400 & jpxCoeffSignificant)) &&
2401 (x == cb->x1 - 1 || y0 == cb->y0 ||
2402 !(coeff1[-(int)tileComp->cbW + 1].flags
2403 & jpxCoeffSignificant)) &&
2404 (x == cb->x0 ||
2405 (!(coeff1[-1].flags & jpxCoeffSignificant) &&
2406 !(coeff1[tileComp->cbW - 1].flags
2407 & jpxCoeffSignificant) &&
2408 !(coeff1[2 * tileComp->cbW - 1].flags
2409 & jpxCoeffSignificant) &&
2410 !(coeff1[3 * tileComp->cbW - 1].flags
2411 & jpxCoeffSignificant))) &&
2412 (x == cb->x1 - 1 ||
2413 (!(coeff1[1].flags & jpxCoeffSignificant) &&
2414 !(coeff1[tileComp->cbW + 1].flags
2415 & jpxCoeffSignificant) &&
2416 !(coeff1[2 * tileComp->cbW + 1].flags
2417 & jpxCoeffSignificant) &&
2418 !(coeff1[3 * tileComp->cbW + 1].flags
2419 & jpxCoeffSignificant))) &&
2420 (x == cb->x0 || y0+4 == cb->y1 ||
2421 !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) &&
2422 (y0+4 == cb->y1 ||
2423 !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) &&
2424 (x == cb->x1 - 1 || y0+4 == cb->y1 ||
2425 !(coeff1[4 * tileComp->cbW + 1].flags
2426 & jpxCoeffSignificant))) {
2427 if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
2428 y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
2429 y1 = (y1 << 1) |
2430 cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
2431 for (y2 = 0, coeff = coeff1;
2432 y2 < y1;
2433 ++y2, coeff += tileComp->cbW) {
2434 ++coeff->len;
2436 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
2437 coeff->mag = (coeff->mag << 1) | 1;
2438 ++coeff->len;
2439 cx = signContext[2][2][0];
2440 xorBit = signContext[2][2][1];
2441 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2442 coeff->flags |= jpxCoeffSign;
2444 ++y1;
2445 } else {
2446 for (y1 = 0, coeff = coeff1;
2447 y1 < 4;
2448 ++y1, coeff += tileComp->cbW) {
2449 ++coeff->len;
2451 y1 = 4;
2454 for (coeff = &coeff1[y1 << tileComp->codeBlockW];
2455 y1 < 4 && y0 + y1 < cb->y1;
2456 ++y1, coeff += tileComp->cbW) {
2457 if (!(coeff->flags & jpxCoeffTouched)) {
2458 horiz = vert = diag = 0;
2459 horizSign = vertSign = 2;
2460 if (x > cb->x0) {
2461 if (coeff[-1].flags & jpxCoeffSignificant) {
2462 ++horiz;
2463 horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
2465 if (y0+y1 > cb->y0) {
2466 diag += (coeff[-(int)tileComp->cbW - 1].flags
2467 >> jpxCoeffSignificantB) & 1;
2469 if (y0+y1 < cb->y1 - 1) {
2470 diag += (coeff[tileComp->cbW - 1].flags
2471 >> jpxCoeffSignificantB) & 1;
2474 if (x < cb->x1 - 1) {
2475 if (coeff[1].flags & jpxCoeffSignificant) {
2476 ++horiz;
2477 horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
2479 if (y0+y1 > cb->y0) {
2480 diag += (coeff[-(int)tileComp->cbW + 1].flags
2481 >> jpxCoeffSignificantB) & 1;
2483 if (y0+y1 < cb->y1 - 1) {
2484 diag += (coeff[tileComp->cbW + 1].flags
2485 >> jpxCoeffSignificantB) & 1;
2488 if (y0+y1 > cb->y0) {
2489 if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
2490 ++vert;
2491 vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
2492 ? -1 : 1;
2495 if (y0+y1 < cb->y1 - 1) {
2496 if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
2497 ++vert;
2498 vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
2499 ? -1 : 1;
2502 cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
2503 if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
2504 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
2505 coeff->mag = (coeff->mag << 1) | 1;
2506 cx = signContext[horizSign][vertSign][0];
2507 xorBit = signContext[horizSign][vertSign][1];
2508 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
2509 coeff->flags |= jpxCoeffSign;
2512 ++coeff->len;
2513 } else {
2514 coeff->flags &= ~jpxCoeffTouched;
2519 cb->nextPass = jpxPassSigProp;
2520 break;
2524 cb->arithDecoder->cleanup();
2525 return gTrue;
2528 // Inverse quantization, and wavelet transform (IDWT). This also does
2529 // the initial shift to convert to fixed point format.
2530 void JPXStream::inverseTransform(JPXTileComp *tileComp) {
2531 JPXResLevel *resLevel;
2532 JPXPrecinct *precinct;
2533 JPXSubband *subband;
2534 JPXCodeBlock *cb;
2535 JPXCoeff *coeff0, *coeff;
2536 Guint qStyle, guard, eps, shift;
2537 int shift2;
2538 double mu;
2539 int val;
2540 int *dataPtr;
2541 Guint nx0, ny0, nx1, ny1;
2542 Guint r, cbX, cbY, x, y;
2544 cover(68);
2546 //----- (NL)LL subband (resolution level 0)
2548 resLevel = &tileComp->resLevels[0];
2549 precinct = &resLevel->precincts[0];
2550 subband = &precinct->subbands[0];
2552 // i-quant parameters
2553 qStyle = tileComp->quantStyle & 0x1f;
2554 guard = (tileComp->quantStyle >> 5) & 7;
2555 if (qStyle == 0) {
2556 cover(69);
2557 eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
2558 shift = guard + eps - 1;
2559 mu = 0; // make gcc happy
2560 } else {
2561 cover(70);
2562 shift = guard - 1 + tileComp->prec;
2563 mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
2565 if (tileComp->transform == 0) {
2566 cover(71);
2567 shift += fracBits;
2570 // copy (NL)LL into the upper-left corner of the data array, doing
2571 // the fixed point adjustment and dequantization along the way
2572 cb = subband->cbs;
2573 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2574 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2575 for (y = cb->y0, coeff0 = cb->coeffs;
2576 y < cb->y1;
2577 ++y, coeff0 += tileComp->cbW) {
2578 dataPtr = &tileComp->data[(y - subband->y0)
2579 * (tileComp->x1 - tileComp->x0)
2580 + (cb->x0 - subband->x0)];
2581 for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
2582 val = (int)coeff->mag;
2583 if (val != 0) {
2584 shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
2585 if (shift2 > 0) {
2586 cover(94);
2587 val = (val << shift2) + (1 << (shift2 - 1));
2588 } else {
2589 cover(95);
2590 val >>= -shift2;
2592 if (qStyle == 0) {
2593 cover(96);
2594 if (tileComp->transform == 0) {
2595 cover(97);
2596 val &= -1 << fracBits;
2598 } else {
2599 cover(98);
2600 val = (int)((double)val * mu);
2602 if (coeff->flags & jpxCoeffSign) {
2603 cover(99);
2604 val = -val;
2607 *dataPtr++ = val;
2610 ++cb;
2614 //----- IDWT for each level
2616 for (r = 1; r <= tileComp->nDecompLevels; ++r) {
2617 resLevel = &tileComp->resLevels[r];
2619 // (n)LL is already in the upper-left corner of the
2620 // tile-component data array -- interleave with (n)HL/LH/HH
2621 // and inverse transform to get (n-1)LL, which will be stored
2622 // in the upper-left corner of the tile-component data array
2623 if (r == tileComp->nDecompLevels) {
2624 cover(72);
2625 nx0 = tileComp->x0;
2626 ny0 = tileComp->y0;
2627 nx1 = tileComp->x1;
2628 ny1 = tileComp->y1;
2629 } else {
2630 cover(73);
2631 nx0 = tileComp->resLevels[r+1].x0;
2632 ny0 = tileComp->resLevels[r+1].y0;
2633 nx1 = tileComp->resLevels[r+1].x1;
2634 ny1 = tileComp->resLevels[r+1].y1;
2636 inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1);
2640 // Do one level of the inverse transform:
2641 // - take (n)LL from the tile-component data array
2642 // - take (n)HL/LH/HH from <resLevel>
2643 // - leave the resulting (n-1)LL in the tile-component data array
2644 void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
2645 Guint r, JPXResLevel *resLevel,
2646 Guint nx0, Guint ny0,
2647 Guint nx1, Guint ny1) {
2648 JPXPrecinct *precinct;
2649 JPXSubband *subband;
2650 JPXCodeBlock *cb;
2651 JPXCoeff *coeff0, *coeff;
2652 Guint qStyle, guard, eps, shift, t;
2653 int shift2;
2654 double mu;
2655 int val;
2656 int *dataPtr;
2657 Guint xo, yo;
2658 Guint x, y, sb, cbX, cbY;
2659 int xx, yy;
2661 //----- interleave
2663 // spread out LL
2664 for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) {
2665 for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) {
2666 tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0)
2667 + (2 * xx - nx0)] =
2668 tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0)
2669 + (xx - resLevel->x0)];
2673 // i-quant parameters
2674 qStyle = tileComp->quantStyle & 0x1f;
2675 guard = (tileComp->quantStyle >> 5) & 7;
2677 // interleave HL/LH/HH
2678 precinct = &resLevel->precincts[0];
2679 for (sb = 0; sb < 3; ++sb) {
2681 // i-quant parameters
2682 if (qStyle == 0) {
2683 cover(100);
2684 eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f;
2685 shift = guard + eps - 1;
2686 mu = 0; // make gcc happy
2687 } else {
2688 cover(101);
2689 shift = guard + tileComp->prec;
2690 if (sb == 2) {
2691 cover(102);
2692 ++shift;
2694 t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)];
2695 mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
2697 if (tileComp->transform == 0) {
2698 cover(103);
2699 shift += fracBits;
2702 // copy the subband coefficients into the data array, doing the
2703 // fixed point adjustment and dequantization along the way
2704 xo = (sb & 1) ? 0 : 1;
2705 yo = (sb > 0) ? 1 : 0;
2706 subband = &precinct->subbands[sb];
2707 cb = subband->cbs;
2708 for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
2709 for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
2710 for (y = cb->y0, coeff0 = cb->coeffs;
2711 y < cb->y1;
2712 ++y, coeff0 += tileComp->cbW) {
2713 dataPtr = &tileComp->data[(2 * y + yo - ny0)
2714 * (tileComp->x1 - tileComp->x0)
2715 + (2 * cb->x0 + xo - nx0)];
2716 for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
2717 val = (int)coeff->mag;
2718 if (val != 0) {
2719 shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
2720 if (shift2 > 0) {
2721 cover(74);
2722 val = (val << shift2) + (1 << (shift2 - 1));
2723 } else {
2724 cover(75);
2725 val >>= -shift2;
2727 if (qStyle == 0) {
2728 cover(76);
2729 if (tileComp->transform == 0) {
2730 val &= -1 << fracBits;
2732 } else {
2733 cover(77);
2734 val = (int)((double)val * mu);
2736 if (coeff->flags & jpxCoeffSign) {
2737 cover(78);
2738 val = -val;
2741 *dataPtr = val;
2742 dataPtr += 2;
2745 ++cb;
2750 //----- horizontal (row) transforms
2751 dataPtr = tileComp->data;
2752 for (y = 0; y < ny1 - ny0; ++y) {
2753 inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1);
2754 dataPtr += tileComp->x1 - tileComp->x0;
2757 //----- vertical (column) transforms
2758 dataPtr = tileComp->data;
2759 for (x = 0; x < nx1 - nx0; ++x) {
2760 inverseTransform1D(tileComp, dataPtr,
2761 tileComp->x1 - tileComp->x0, ny0, ny1);
2762 ++dataPtr;
2766 void JPXStream::inverseTransform1D(JPXTileComp *tileComp,
2767 int *data, Guint stride,
2768 Guint i0, Guint i1) {
2769 int *buf;
2770 Guint offset, end, i;
2772 //----- special case for length = 1
2773 if (i1 - i0 == 1) {
2774 cover(79);
2775 if (i0 & 1) {
2776 cover(104);
2777 *data >>= 1;
2780 } else {
2781 cover(80);
2783 // choose an offset: this makes even buf[] indexes correspond to
2784 // odd values of i, and vice versa
2785 offset = 3 + (i0 & 1);
2786 end = offset + i1 - i0;
2788 //----- gather
2789 buf = tileComp->buf;
2790 for (i = 0; i < i1 - i0; ++i) {
2791 buf[offset + i] = data[i * stride];
2794 //----- extend right
2795 buf[end] = buf[end - 2];
2796 if (i1 - i0 == 2) {
2797 cover(81);
2798 buf[end+1] = buf[offset + 1];
2799 buf[end+2] = buf[offset];
2800 buf[end+3] = buf[offset + 1];
2801 } else {
2802 cover(82);
2803 buf[end+1] = buf[end - 3];
2804 if (i1 - i0 == 3) {
2805 cover(105);
2806 buf[end+2] = buf[offset + 1];
2807 buf[end+3] = buf[offset + 2];
2808 } else {
2809 cover(106);
2810 buf[end+2] = buf[end - 4];
2811 if (i1 - i0 == 4) {
2812 cover(107);
2813 buf[end+3] = buf[offset + 1];
2814 } else {
2815 cover(108);
2816 buf[end+3] = buf[end - 5];
2821 //----- extend left
2822 buf[offset - 1] = buf[offset + 1];
2823 buf[offset - 2] = buf[offset + 2];
2824 buf[offset - 3] = buf[offset + 3];
2825 if (offset == 4) {
2826 cover(83);
2827 buf[0] = buf[offset + 4];
2830 //----- 9-7 irreversible filter
2832 if (tileComp->transform == 0) {
2833 cover(84);
2834 // step 1 (even)
2835 for (i = 1; i <= end + 2; i += 2) {
2836 buf[i] = (int)(idwtKappa * buf[i]);
2838 // step 2 (odd)
2839 for (i = 0; i <= end + 3; i += 2) {
2840 buf[i] = (int)(idwtIKappa * buf[i]);
2842 // step 3 (even)
2843 for (i = 1; i <= end + 2; i += 2) {
2844 buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1]));
2846 // step 4 (odd)
2847 for (i = 2; i <= end + 1; i += 2) {
2848 buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1]));
2850 // step 5 (even)
2851 for (i = 3; i <= end; i += 2) {
2852 buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1]));
2854 // step 6 (odd)
2855 for (i = 4; i <= end - 1; i += 2) {
2856 buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1]));
2859 //----- 5-3 reversible filter
2861 } else {
2862 cover(85);
2863 // step 1 (even)
2864 for (i = 3; i <= end; i += 2) {
2865 buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2;
2867 // step 2 (odd)
2868 for (i = 4; i < end; i += 2) {
2869 buf[i] += (buf[i-1] + buf[i+1]) >> 1;
2873 //----- scatter
2874 for (i = 0; i < i1 - i0; ++i) {
2875 data[i * stride] = buf[offset + i];
2880 // Inverse multi-component transform and DC level shift. This also
2881 // converts fixed point samples back to integers.
2882 GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
2883 JPXTileComp *tileComp;
2884 int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
2885 int *dataPtr;
2886 Guint j, comp, x, y;
2888 //----- inverse multi-component transform
2890 if (tile->multiComp == 1) {
2891 cover(86);
2892 if (img.nComps < 3 ||
2893 tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
2894 tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
2895 tile->tileComps[1].hSep != tile->tileComps[2].hSep ||
2896 tile->tileComps[1].vSep != tile->tileComps[2].vSep) {
2897 return gFalse;
2900 // inverse irreversible multiple component transform
2901 if (tile->tileComps[0].transform == 0) {
2902 cover(87);
2903 j = 0;
2904 for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
2905 for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
2906 d0 = tile->tileComps[0].data[j];
2907 d1 = tile->tileComps[1].data[j];
2908 d2 = tile->tileComps[2].data[j];
2909 tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5);
2910 tile->tileComps[1].data[j] =
2911 (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5);
2912 tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5);
2913 ++j;
2917 // inverse reversible multiple component transform
2918 } else {
2919 cover(88);
2920 j = 0;
2921 for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
2922 for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
2923 d0 = tile->tileComps[0].data[j];
2924 d1 = tile->tileComps[1].data[j];
2925 d2 = tile->tileComps[2].data[j];
2926 tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
2927 tile->tileComps[0].data[j] = d2 + t;
2928 tile->tileComps[2].data[j] = d1 + t;
2929 ++j;
2935 //----- DC level shift
2936 for (comp = 0; comp < img.nComps; ++comp) {
2937 tileComp = &tile->tileComps[comp];
2939 // signed: clip
2940 if (tileComp->sgned) {
2941 cover(89);
2942 minVal = -(1 << (tileComp->prec - 1));
2943 maxVal = (1 << (tileComp->prec - 1)) - 1;
2944 dataPtr = tileComp->data;
2945 for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
2946 for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
2947 coeff = *dataPtr;
2948 if (tileComp->transform == 0) {
2949 cover(109);
2950 coeff >>= fracBits;
2952 if (coeff < minVal) {
2953 cover(110);
2954 coeff = minVal;
2955 } else if (coeff > maxVal) {
2956 cover(111);
2957 coeff = maxVal;
2959 *dataPtr++ = coeff;
2963 // unsigned: inverse DC level shift and clip
2964 } else {
2965 cover(90);
2966 maxVal = (1 << tileComp->prec) - 1;
2967 zeroVal = 1 << (tileComp->prec - 1);
2968 dataPtr = tileComp->data;
2969 for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
2970 for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
2971 coeff = *dataPtr;
2972 if (tileComp->transform == 0) {
2973 cover(112);
2974 coeff >>= fracBits;
2976 coeff += zeroVal;
2977 if (coeff < 0) {
2978 cover(113);
2979 coeff = 0;
2980 } else if (coeff > maxVal) {
2981 cover(114);
2982 coeff = maxVal;
2984 *dataPtr++ = coeff;
2990 return gTrue;
2993 GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) {
2994 Guint len, lenH;
2996 if (!readULong(&len) ||
2997 !readULong(boxType)) {
2998 return gFalse;
3000 if (len == 1) {
3001 if (!readULong(&lenH) || !readULong(&len)) {
3002 return gFalse;
3004 if (lenH) {
3005 error(getPos(), "JPX stream contains a box larger than 2^32 bytes");
3006 return gFalse;
3008 *boxLen = len;
3009 *dataLen = len - 16;
3010 } else if (len == 0) {
3011 *boxLen = 0;
3012 *dataLen = 0;
3013 } else {
3014 *boxLen = len;
3015 *dataLen = len - 8;
3017 return gTrue;
3020 int JPXStream::readMarkerHdr(int *segType, Guint *segLen) {
3021 int c;
3023 do {
3024 do {
3025 if ((c = str->getChar()) == EOF) {
3026 return gFalse;
3028 } while (c != 0xff);
3029 do {
3030 if ((c = str->getChar()) == EOF) {
3031 return gFalse;
3033 } while (c == 0xff);
3034 } while (c == 0x00);
3035 *segType = c;
3036 if ((c >= 0x30 && c <= 0x3f) ||
3037 c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) {
3038 *segLen = 0;
3039 return gTrue;
3041 return readUWord(segLen);
3044 GBool JPXStream::readUByte(Guint *x) {
3045 int c0;
3047 if ((c0 = str->getChar()) == EOF) {
3048 return gFalse;
3050 *x = (Guint)c0;
3051 return gTrue;
3054 GBool JPXStream::readByte(int *x) {
3055 int c0;
3057 if ((c0 = str->getChar()) == EOF) {
3058 return gFalse;
3060 *x = c0;
3061 if (c0 & 0x80) {
3062 *x |= -1 - 0xff;
3064 return gTrue;
3067 GBool JPXStream::readUWord(Guint *x) {
3068 int c0, c1;
3070 if ((c0 = str->getChar()) == EOF ||
3071 (c1 = str->getChar()) == EOF) {
3072 return gFalse;
3074 *x = (Guint)((c0 << 8) | c1);
3075 return gTrue;
3078 GBool JPXStream::readULong(Guint *x) {
3079 int c0, c1, c2, c3;
3081 if ((c0 = str->getChar()) == EOF ||
3082 (c1 = str->getChar()) == EOF ||
3083 (c2 = str->getChar()) == EOF ||
3084 (c3 = str->getChar()) == EOF) {
3085 return gFalse;
3087 *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
3088 return gTrue;
3091 GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) {
3092 int y, c, i;
3094 y = 0;
3095 for (i = 0; i < nBytes; ++i) {
3096 if ((c = str->getChar()) == EOF) {
3097 return gFalse;
3099 y = (y << 8) + c;
3101 if (signd) {
3102 if (y & (1 << (8 * nBytes - 1))) {
3103 y |= -1 << (8 * nBytes);
3106 *x = y;
3107 return gTrue;
3110 GBool JPXStream::readBits(int nBits, Guint *x) {
3111 int c;
3113 while (bitBufLen < nBits) {
3114 if (byteCount == 0 || (c = str->getChar()) == EOF) {
3115 return gFalse;
3117 --byteCount;
3118 if (bitBufSkip) {
3119 bitBuf = (bitBuf << 7) | (c & 0x7f);
3120 bitBufLen += 7;
3121 } else {
3122 bitBuf = (bitBuf << 8) | (c & 0xff);
3123 bitBufLen += 8;
3125 bitBufSkip = c == 0xff;
3127 *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1);
3128 bitBufLen -= nBits;
3129 return gTrue;
3132 void JPXStream::startBitBuf(Guint byteCountA) {
3133 bitBufLen = 0;
3134 bitBufSkip = gFalse;
3135 byteCount = byteCountA;
3138 Guint JPXStream::finishBitBuf() {
3139 if (bitBufSkip) {
3140 str->getChar();
3141 --byteCount;
3143 return byteCount;