Back to index

tetex-bin  3.0
JPXStream.cc
Go to the documentation of this file.
00001 //========================================================================
00002 //
00003 // JPXStream.cc
00004 //
00005 // Copyright 2002-2003 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014 
00015 #include "gmem.h"
00016 #include "Error.h"
00017 #include "JArithmeticDecoder.h"
00018 #include "JPXStream.h"
00019 
00020 //~ to do:
00021 //  - precincts
00022 //  - ROI
00023 //  - progression order changes
00024 //  - packed packet headers
00025 //  - support for palettes, channel maps, etc.
00026 //  - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
00027 //  - can we assume that QCC segments must come after the QCD segment?
00028 //  - skip EPH markers (readTilePartData)
00029 //  - handle tilePartToEOC in readTilePartData
00030 //  - deal with multiple codeword segments (readTilePartData,
00031 //    readCodeBlockData)
00032 //  - progression orders 2, 3, and 4
00033 //  - in coefficient decoding (readCodeBlockData):
00034 //    - termination pattern: terminate after every coding pass
00035 //    - error resilience segmentation symbol
00036 //    - selective arithmetic coding bypass
00037 //    - vertically causal context formation
00038 //    - coeffs longer than 31 bits (should just ignore the extra bits?)
00039 //  - handle boxes larger than 2^32 bytes
00040 //  - the fixed-point arithmetic won't handle 16-bit pixels
00041 
00042 //------------------------------------------------------------------------
00043 
00044 // number of contexts for the arithmetic decoder
00045 #define jpxNContexts        19
00046 
00047 #define jpxContextSigProp    0     // 0 - 8: significance prop and cleanup
00048 #define jpxContextSign       9     // 9 - 13: sign
00049 #define jpxContextMagRef    14     // 14 -16: magnitude refinement
00050 #define jpxContextRunLength 17     // cleanup: run length
00051 #define jpxContextUniform   18     // cleanup: first signif coeff
00052 
00053 //------------------------------------------------------------------------
00054 
00055 #define jpxPassSigProp       0
00056 #define jpxPassMagRef        1
00057 #define jpxPassCleanup       2
00058 
00059 //------------------------------------------------------------------------
00060 
00061 // arithmetic decoder context for the significance propagation and
00062 // cleanup passes:
00063 //     [horiz][vert][diag][subband]
00064 // where subband = 0 for HL
00065 //               = 1 for LH and LL
00066 //               = 2 for HH
00067 static Guint sigPropContext[3][3][5][3] = {
00068   {{{ 0, 0, 0 },   // horiz=0, vert=0, diag=0
00069     { 1, 1, 3 },   // horiz=0, vert=0, diag=1
00070     { 2, 2, 6 },   // horiz=0, vert=0, diag=2
00071     { 2, 2, 8 },   // horiz=0, vert=0, diag=3
00072     { 2, 2, 8 }},  // horiz=0, vert=0, diag=4
00073    {{ 5, 3, 1 },   // horiz=0, vert=1, diag=0
00074     { 6, 3, 4 },   // horiz=0, vert=1, diag=1
00075     { 6, 3, 7 },   // horiz=0, vert=1, diag=2
00076     { 6, 3, 8 },   // horiz=0, vert=1, diag=3
00077     { 6, 3, 8 }},  // horiz=0, vert=1, diag=4
00078    {{ 8, 4, 2 },   // horiz=0, vert=2, diag=0
00079     { 8, 4, 5 },   // horiz=0, vert=2, diag=1
00080     { 8, 4, 7 },   // horiz=0, vert=2, diag=2
00081     { 8, 4, 8 },   // horiz=0, vert=2, diag=3
00082     { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4
00083   {{{ 3, 5, 1 },   // horiz=1, vert=0, diag=0
00084     { 3, 6, 4 },   // horiz=1, vert=0, diag=1
00085     { 3, 6, 7 },   // horiz=1, vert=0, diag=2
00086     { 3, 6, 8 },   // horiz=1, vert=0, diag=3
00087     { 3, 6, 8 }},  // horiz=1, vert=0, diag=4
00088    {{ 7, 7, 2 },   // horiz=1, vert=1, diag=0
00089     { 7, 7, 5 },   // horiz=1, vert=1, diag=1
00090     { 7, 7, 7 },   // horiz=1, vert=1, diag=2
00091     { 7, 7, 8 },   // horiz=1, vert=1, diag=3
00092     { 7, 7, 8 }},  // horiz=1, vert=1, diag=4
00093    {{ 8, 7, 2 },   // horiz=1, vert=2, diag=0
00094     { 8, 7, 5 },   // horiz=1, vert=2, diag=1
00095     { 8, 7, 7 },   // horiz=1, vert=2, diag=2
00096     { 8, 7, 8 },   // horiz=1, vert=2, diag=3
00097     { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4
00098   {{{ 4, 8, 2 },   // horiz=2, vert=0, diag=0
00099     { 4, 8, 5 },   // horiz=2, vert=0, diag=1
00100     { 4, 8, 7 },   // horiz=2, vert=0, diag=2
00101     { 4, 8, 8 },   // horiz=2, vert=0, diag=3
00102     { 4, 8, 8 }},  // horiz=2, vert=0, diag=4
00103    {{ 7, 8, 2 },   // horiz=2, vert=1, diag=0
00104     { 7, 8, 5 },   // horiz=2, vert=1, diag=1
00105     { 7, 8, 7 },   // horiz=2, vert=1, diag=2
00106     { 7, 8, 8 },   // horiz=2, vert=1, diag=3
00107     { 7, 8, 8 }},  // horiz=2, vert=1, diag=4
00108    {{ 8, 8, 2 },   // horiz=2, vert=2, diag=0
00109     { 8, 8, 5 },   // horiz=2, vert=2, diag=1
00110     { 8, 8, 7 },   // horiz=2, vert=2, diag=2
00111     { 8, 8, 8 },   // horiz=2, vert=2, diag=3
00112     { 8, 8, 8 }}}  // horiz=2, vert=2, diag=4
00113 };
00114 
00115 // arithmetic decoder context and xor bit for the sign bit in the
00116 // significance propagation pass:
00117 //     [horiz][vert][k]
00118 // where horiz/vert are offset by 2 (i.e., range is -2 .. 2)
00119 // and k = 0 for the context
00120 //       = 1 for the xor bit
00121 static Guint signContext[5][5][2] = {
00122   {{ 13, 1 },  // horiz=-2, vert=-2
00123    { 13, 1 },  // horiz=-2, vert=-1
00124    { 12, 1 },  // horiz=-2, vert= 0
00125    { 11, 1 },  // horiz=-2, vert=+1
00126    { 11, 1 }}, // horiz=-2, vert=+2
00127   {{ 13, 1 },  // horiz=-1, vert=-2
00128    { 13, 1 },  // horiz=-1, vert=-1
00129    { 12, 1 },  // horiz=-1, vert= 0
00130    { 11, 1 },  // horiz=-1, vert=+1
00131    { 11, 1 }}, // horiz=-1, vert=+2
00132   {{ 10, 1 },  // horiz= 0, vert=-2
00133    { 10, 1 },  // horiz= 0, vert=-1
00134    {  9, 0 },  // horiz= 0, vert= 0
00135    { 10, 0 },  // horiz= 0, vert=+1
00136    { 10, 0 }}, // horiz= 0, vert=+2
00137   {{ 11, 0 },  // horiz=+1, vert=-2
00138    { 11, 0 },  // horiz=+1, vert=-1
00139    { 12, 0 },  // horiz=+1, vert= 0
00140    { 13, 0 },  // horiz=+1, vert=+1
00141    { 13, 0 }}, // horiz=+1, vert=+2
00142   {{ 11, 0 },  // horiz=+2, vert=-2
00143    { 11, 0 },  // horiz=+2, vert=-1
00144    { 12, 0 },  // horiz=+2, vert= 0
00145    { 13, 0 },  // horiz=+2, vert=+1
00146    { 13, 0 }}, // horiz=+2, vert=+2
00147 };
00148 
00149 //------------------------------------------------------------------------
00150 
00151 // constants used in the IDWT
00152 #define idwtAlpha  -1.586134342059924
00153 #define idwtBeta   -0.052980118572961
00154 #define idwtGamma   0.882911075530934
00155 #define idwtDelta   0.443506852043971
00156 #define idwtKappa   1.230174104914001
00157 #define idwtIKappa  (1.0 / idwtKappa)
00158 
00159 // number of bits to the right of the decimal point for the fixed
00160 // point arithmetic used in the IDWT
00161 #define fracBits 16
00162 
00163 //------------------------------------------------------------------------
00164 
00165 // floor(x / y)
00166 #define jpxFloorDiv(x, y) ((x) / (y))
00167 
00168 // floor(x / 2^y)
00169 #define jpxFloorDivPow2(x, y) ((x) >> (y))
00170 
00171 // ceil(x / y)
00172 #define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y))
00173 
00174 // ceil(x / 2^y)
00175 #define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y))
00176 
00177 //------------------------------------------------------------------------
00178 
00179 JPXStream::JPXStream(Stream *strA):
00180   FilterStream(strA)
00181 {
00182   nComps = 0;
00183   bpc = NULL;
00184   width = height = 0;
00185   haveCS = gFalse;
00186   havePalette = gFalse;
00187   haveCompMap = gFalse;
00188   haveChannelDefn = gFalse;
00189 
00190   img.tiles = NULL;
00191   bitBuf = 0;
00192   bitBufLen = 0;
00193   bitBufSkip = gFalse;
00194   byteCount = 0;
00195 }
00196 
00197 JPXStream::~JPXStream() {
00198   JPXTile *tile;
00199   JPXTileComp *tileComp;
00200   JPXResLevel *resLevel;
00201   JPXPrecinct *precinct;
00202   JPXSubband *subband;
00203   JPXCodeBlock *cb;
00204   Guint comp, i, k, r, pre, sb;
00205 
00206   gfree(bpc);
00207   if (havePalette) {
00208     gfree(palette.bpc);
00209     gfree(palette.c);
00210   }
00211   if (haveCompMap) {
00212     gfree(compMap.comp);
00213     gfree(compMap.type);
00214     gfree(compMap.pComp);
00215   }
00216   if (haveChannelDefn) {
00217     gfree(channelDefn.idx);
00218     gfree(channelDefn.type);
00219     gfree(channelDefn.assoc);
00220   }
00221 
00222   if (img.tiles) {
00223     for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
00224       tile = &img.tiles[i];
00225       if (tile->tileComps) {
00226        for (comp = 0; comp < img.nComps; ++comp) {
00227          tileComp = &tile->tileComps[comp];
00228          gfree(tileComp->quantSteps);
00229          gfree(tileComp->data);
00230          gfree(tileComp->buf);
00231          if (tileComp->resLevels) {
00232            for (r = 0; r <= tileComp->nDecompLevels; ++r) {
00233              resLevel = &tileComp->resLevels[r];
00234              if (resLevel->precincts) {
00235               for (pre = 0; pre < 1; ++pre) {
00236                 precinct = &resLevel->precincts[pre];
00237                 if (precinct->subbands) {
00238                   for (sb = 0; sb < (r == 0 ? 1 : 3); ++sb) {
00239                     subband = &precinct->subbands[sb];
00240                     gfree(subband->inclusion);
00241                     gfree(subband->zeroBitPlane);
00242                     if (subband->cbs) {
00243                      for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
00244                        cb = &subband->cbs[k];
00245                        gfree(cb->coeffs);
00246                        if (cb->stats) {
00247                          delete cb->stats;
00248                        }
00249                      }
00250                      gfree(subband->cbs);
00251                     }
00252                   }
00253                   gfree(precinct->subbands);
00254                 }
00255               }
00256               gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
00257              }
00258            }
00259            gfree(img.tiles[i].tileComps[comp].resLevels);
00260          }
00261        }
00262        gfree(img.tiles[i].tileComps);
00263       }
00264     }
00265     gfree(img.tiles);
00266   }
00267   delete str;
00268 }
00269 
00270 void JPXStream::reset() {
00271   str->reset();
00272   if (readBoxes()) {
00273     curY = img.yOffset;
00274   } else {
00275     // readBoxes reported an error, so we go immediately to EOF
00276     curY = img.ySize;
00277   }
00278   curX = img.xOffset;
00279   curComp = 0;
00280   readBufLen = 0;
00281 }
00282 
00283 int JPXStream::getChar() {
00284   int c;
00285 
00286   if (readBufLen < 8) {
00287     fillReadBuf();
00288   }
00289   if (readBufLen == 8) {
00290     c = readBuf & 0xff;
00291     readBufLen = 0;
00292   } else if (readBufLen > 8) {
00293     c = (readBuf >> (readBufLen - 8)) & 0xff;
00294     readBufLen -= 8;
00295   } else if (readBufLen == 0) {
00296     c = EOF;
00297   } else {
00298     c = (readBuf << (8 - readBufLen)) & 0xff;
00299     readBufLen = 0;
00300   }
00301   return c;
00302 }
00303 
00304 int JPXStream::lookChar() {
00305   int c;
00306 
00307   if (readBufLen < 8) {
00308     fillReadBuf();
00309   }
00310   if (readBufLen == 8) {
00311     c = readBuf & 0xff;
00312   } else if (readBufLen > 8) {
00313     c = (readBuf >> (readBufLen - 8)) & 0xff;
00314   } else if (readBufLen == 0) {
00315     c = EOF;
00316   } else {
00317     c = (readBuf << (8 - readBufLen)) & 0xff;
00318   }
00319   return c;
00320 }
00321 
00322 void JPXStream::fillReadBuf() {
00323   JPXTileComp *tileComp;
00324   Guint tileIdx, tx, ty;
00325   int pix, pixBits;
00326 
00327   do {
00328     if (curY >= img.ySize) {
00329       return;
00330     }
00331     tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles
00332               + (curX - img.xTileOffset) / img.xTileSize;
00333 #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
00334     tileComp = &img.tiles[tileIdx].tileComps[curComp];
00335 #else
00336     tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp];
00337 #endif
00338     tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep);
00339     ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep);
00340     pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx];
00341     pixBits = tileComp->prec;
00342 #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
00343     if (++curComp == img.nComps) {
00344 #else
00345     if (havePalette) {
00346       if (pix >= 0 && pix < palette.nEntries) {
00347        pix = palette.c[pix * palette.nComps + curComp];
00348       } else {
00349        pix = 
00350       pixBits = palette.bpc[curComp];
00351     }
00352     if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) {
00353 #endif
00354       curComp = 0;
00355       if (++curX == img.xSize) {
00356        curX = img.xOffset;
00357        ++curY;
00358       }
00359     }
00360     if (pixBits == 8) {
00361       readBuf = (readBuf << 8) | (pix & 0xff);
00362     } else {
00363       readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1));
00364     }
00365     readBufLen += pixBits;
00366   } while (readBufLen < 8);
00367 }
00368 
00369 GString *JPXStream::getPSFilter(int psLevel, char *indent) {
00370   return NULL;
00371 }
00372 
00373 GBool JPXStream::isBinary(GBool last) {
00374   return str->isBinary(gTrue);
00375 }
00376 
00377 GBool JPXStream::readBoxes() {
00378   Guint boxType, boxLen, dataLen;
00379   Guint bpc1, compression, unknownColorspace, ipr;
00380   Guint i, j;
00381 
00382   haveImgHdr = gFalse;
00383 
00384   // check for a naked JPEG 2000 codestream (without the JP2/JPX
00385   // wrapper) -- this appears to be a violation of the PDF spec, but
00386   // Acrobat allows it
00387   if (str->lookChar() == 0xff) {
00388     error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
00389     readCodestream(0);
00390     nComps = img.nComps;
00391     bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
00392     for (i = 0; i < nComps; ++i) {
00393       bpc[i] = img.tiles[0].tileComps[i].prec;
00394     }
00395     width = img.xSize - img.xOffset;
00396     height = img.ySize - img.yOffset;
00397     return gTrue;
00398   }
00399 
00400   while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
00401     switch (boxType) {
00402     case 0x6a703268:        // JP2 header
00403       // this is a grouping box ('superbox') which has no real
00404       // contents and doesn't appear to be used consistently, i.e.,
00405       // some things which should be subboxes of the JP2 header box
00406       // show up outside of it - so we simply ignore the JP2 header
00407       // box
00408       break;
00409     case 0x69686472:        // image header
00410       if (!readULong(&height) ||
00411          !readULong(&width) ||
00412          !readUWord(&nComps) ||
00413          !readUByte(&bpc1) ||
00414          !readUByte(&compression) ||
00415          !readUByte(&unknownColorspace) ||
00416          !readUByte(&ipr)) {
00417        error(getPos(), "Unexpected EOF in JPX stream");
00418        return gFalse;
00419       }
00420       if (compression != 7) {
00421        error(getPos(), "Unknown compression type in JPX stream");
00422        return gFalse;
00423       }
00424       bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
00425       for (i = 0; i < nComps; ++i) {
00426        bpc[i] = bpc1;
00427       }
00428       haveImgHdr = gTrue;
00429       break;
00430     case 0x62706363:        // bits per component
00431       if (!haveImgHdr) {
00432        error(getPos(), "Found bits per component box before image header box in JPX stream");
00433        return gFalse;
00434       }
00435       if (dataLen != nComps) {
00436        error(getPos(), "Invalid bits per component box in JPX stream");
00437        return gFalse;
00438       }
00439       for (i = 0; i < nComps; ++i) {
00440        if (!readUByte(&bpc[i])) {
00441          error(getPos(), "Unexpected EOF in JPX stream");
00442          return gFalse;
00443        }
00444       }
00445       break;
00446     case 0x636F6C72:        // color specification
00447       if (!readColorSpecBox(dataLen)) {
00448        return gFalse;
00449       }
00450       break;
00451     case 0x70636c72:        // palette
00452       if (!readUWord(&palette.nEntries) ||
00453          !readUByte(&palette.nComps)) {
00454        error(getPos(), "Unexpected EOF in JPX stream");
00455        return gFalse;
00456       }
00457       palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint));
00458       palette.c =
00459           (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int));
00460       for (i = 0; i < palette.nComps; ++i) {
00461        if (!readUByte(&palette.bpc[i])) {
00462          error(getPos(), "Unexpected EOF in JPX stream");
00463          return gFalse;
00464        }
00465        ++palette.bpc[i];
00466       }
00467       for (i = 0; i < palette.nEntries; ++i) {
00468        for (j = 0; j < palette.nComps; ++j) {
00469          if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3,
00470                        (palette.bpc[j] & 0x80) ? gTrue : gFalse,
00471                        &palette.c[i * palette.nComps + j])) {
00472            error(getPos(), "Unexpected EOF in JPX stream");
00473            return gFalse;
00474          }
00475        }
00476       }
00477       havePalette = gTrue;
00478       break;
00479     case 0x636d6170:        // component mapping
00480       compMap.nChannels = dataLen / 4;
00481       compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
00482       compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
00483       compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
00484       for (i = 0; i < compMap.nChannels; ++i) {
00485        if (!readUWord(&compMap.comp[i]) ||
00486            !readUByte(&compMap.type[i]) ||
00487            !readUByte(&compMap.pComp[i])) {
00488          error(getPos(), "Unexpected EOF in JPX stream");
00489          return gFalse;
00490        }
00491       }
00492       haveCompMap = gTrue;
00493       break;
00494     case 0x63646566:        // channel definition
00495       if (!readUWord(&channelDefn.nChannels)) {
00496        error(getPos(), "Unexpected EOF in JPX stream");
00497        return gFalse;
00498       }
00499       channelDefn.idx =
00500          (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
00501       channelDefn.type =
00502          (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
00503       channelDefn.assoc =
00504          (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
00505       for (i = 0; i < channelDefn.nChannels; ++i) {
00506        if (!readUWord(&channelDefn.idx[i]) ||
00507            !readUWord(&channelDefn.type[i]) ||
00508            !readUWord(&channelDefn.assoc[i])) {
00509          error(getPos(), "Unexpected EOF in JPX stream");
00510          return gFalse;
00511        }
00512       }
00513       haveChannelDefn = gTrue;
00514       break;
00515     case 0x6A703263:        // contiguous codestream
00516       if (!bpc) {
00517        error(getPos(), "JPX stream is missing the image header box");
00518        return gFalse;
00519       }
00520       if (!haveCS) {
00521        error(getPos(), "JPX stream has no supported color spec");
00522        return gFalse;
00523       }
00524       if (!readCodestream(dataLen)) {
00525        return gFalse;
00526       }
00527       break;
00528     default:
00529       for (i = 0; i < dataLen; ++i) {
00530        if (str->getChar() == EOF) {
00531          error(getPos(), "Unexpected EOF in JPX stream");
00532          return gFalse;
00533        }
00534       }
00535       break;
00536     }
00537   }
00538   return gTrue;
00539 }
00540 
00541 GBool JPXStream::readColorSpecBox(Guint dataLen) {
00542   JPXColorSpec newCS;
00543   Guint csApprox, csEnum;
00544   Guint i;
00545   GBool ok;
00546 
00547   ok = gFalse;
00548   if (!readUByte(&newCS.meth) ||
00549       !readByte(&newCS.prec) ||
00550       !readUByte(&csApprox)) {
00551     goto err;
00552   }
00553   switch (newCS.meth) {
00554   case 1:                   // enumerated colorspace
00555     if (!readULong(&csEnum)) {
00556       goto err;
00557     }
00558     newCS.enumerated.type = (JPXColorSpaceType)csEnum;
00559     switch (newCS.enumerated.type) {
00560     case jpxCSBiLevel:
00561       ok = gTrue;
00562       break;
00563     case jpxCSYCbCr1:
00564       ok = gTrue;
00565       break;
00566     case jpxCSYCbCr2:
00567       ok = gTrue;
00568       break;
00569     case jpxCSYCBCr3:
00570       ok = gTrue;
00571       break;
00572     case jpxCSPhotoYCC:
00573       ok = gTrue;
00574       break;
00575     case jpxCSCMY:
00576       ok = gTrue;
00577       break;
00578     case jpxCSCMYK:
00579       ok = gTrue;
00580       break;
00581     case jpxCSYCCK:
00582       ok = gTrue;
00583       break;
00584     case jpxCSCIELab:
00585       if (dataLen == 3 + 7*4) {
00586        if (!readULong(&newCS.enumerated.cieLab.rl) ||
00587            !readULong(&newCS.enumerated.cieLab.ol) ||
00588            !readULong(&newCS.enumerated.cieLab.ra) ||
00589            !readULong(&newCS.enumerated.cieLab.oa) ||
00590            !readULong(&newCS.enumerated.cieLab.rb) ||
00591            !readULong(&newCS.enumerated.cieLab.ob) ||
00592            !readULong(&newCS.enumerated.cieLab.il)) {
00593          goto err;
00594        }
00595       } else if (dataLen == 3) {
00596        //~ this assumes the 8-bit case
00597        newCS.enumerated.cieLab.rl = 100;
00598        newCS.enumerated.cieLab.ol = 0;
00599        newCS.enumerated.cieLab.ra = 255;
00600        newCS.enumerated.cieLab.oa = 128;
00601        newCS.enumerated.cieLab.rb = 255;
00602        newCS.enumerated.cieLab.ob = 96;
00603        newCS.enumerated.cieLab.il = 0x00443530;
00604       } else {
00605        goto err;
00606       }
00607       ok = gTrue;
00608       break;
00609     case jpxCSsRGB:
00610       ok = gTrue;
00611       break;
00612     case jpxCSGrayscale:
00613       ok = gTrue;
00614       break;
00615     case jpxCSBiLevel2:
00616       ok = gTrue;
00617       break;
00618     case jpxCSCIEJab:
00619       // not allowed in PDF
00620       goto err;
00621     case jpxCSCISesRGB:
00622       ok = gTrue;
00623       break;
00624     case jpxCSROMMRGB:
00625       ok = gTrue;
00626       break;
00627     case jpxCSsRGBYCbCr:
00628       ok = gTrue;
00629       break;
00630     case jpxCSYPbPr1125:
00631       ok = gTrue;
00632       break;
00633     case jpxCSYPbPr1250:
00634       ok = gTrue;
00635       break;
00636     default:
00637       goto err;
00638     }
00639     break;
00640   case 2:                   // restricted ICC profile
00641   case 3:                   // any ICC profile (JPX)
00642   case 4:                   // vendor color (JPX)
00643     for (i = 0; i < dataLen - 3; ++i) {
00644       if (str->getChar() == EOF) {
00645        goto err;
00646       }
00647     }
00648     break;
00649   }
00650 
00651   if (ok && (!haveCS || newCS.prec > cs.prec)) {
00652     cs = newCS;
00653     haveCS = gTrue;
00654   }
00655 
00656   return gTrue;
00657 
00658  err:
00659   error(getPos(), "Error in JPX color spec");
00660   return gFalse;
00661 }
00662 
00663 GBool JPXStream::readCodestream(Guint len) {
00664   JPXTile *tile;
00665   JPXTileComp *tileComp;
00666   int segType;
00667   GBool haveSIZ, haveCOD, haveQCD, haveSOT;
00668   Guint precinctSize, style;
00669   Guint segLen, capabilities, comp, i, j, r;
00670 
00671   //----- main header
00672   haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
00673   do {
00674     if (!readMarkerHdr(&segType, &segLen)) {
00675       error(getPos(), "Error in JPX codestream");
00676       return gFalse;
00677     }
00678     switch (segType) {
00679     case 0x4f:                     // SOC - start of codestream
00680       // marker only
00681       break;
00682     case 0x51:                     // SIZ - image and tile size
00683       if (!readUWord(&capabilities) ||
00684          !readULong(&img.xSize) ||
00685          !readULong(&img.ySize) ||
00686          !readULong(&img.xOffset) ||
00687          !readULong(&img.yOffset) ||
00688          !readULong(&img.xTileSize) ||
00689          !readULong(&img.yTileSize) ||
00690          !readULong(&img.xTileOffset) ||
00691          !readULong(&img.yTileOffset) ||
00692          !readUWord(&img.nComps)) {
00693        error(getPos(), "Error in JPX SIZ marker segment");
00694        return gFalse;
00695       }
00696       if (haveImgHdr && img.nComps != nComps) {
00697        error(getPos(), "Different number of components in JPX SIZ marker segment");
00698        return gFalse;
00699       }
00700       img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1)
00701                    / img.xTileSize;
00702       img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
00703                    / img.yTileSize;
00704       img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles *
00705                                  sizeof(JPXTile));
00706       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
00707        img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps *
00708                                                  sizeof(JPXTileComp));
00709        for (comp = 0; comp < img.nComps; ++comp) {
00710          img.tiles[i].tileComps[comp].quantSteps = NULL;
00711          img.tiles[i].tileComps[comp].data = NULL;
00712          img.tiles[i].tileComps[comp].buf = NULL;
00713          img.tiles[i].tileComps[comp].resLevels = NULL;
00714        }
00715       }
00716       for (comp = 0; comp < img.nComps; ++comp) {
00717        if (!readUByte(&img.tiles[0].tileComps[comp].prec) ||
00718            !readUByte(&img.tiles[0].tileComps[comp].hSep) ||
00719            !readUByte(&img.tiles[0].tileComps[comp].vSep)) {
00720          error(getPos(), "Error in JPX SIZ marker segment");
00721          return gFalse;
00722        }
00723        img.tiles[0].tileComps[comp].sgned =
00724            (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse;
00725        img.tiles[0].tileComps[comp].prec =
00726            (img.tiles[0].tileComps[comp].prec & 0x7f) + 1;
00727        for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
00728          img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp];
00729        }
00730       }
00731       haveSIZ = gTrue;
00732       break;
00733     case 0x52:                     // COD - coding style default
00734       if (!readUByte(&img.tiles[0].tileComps[0].style) ||
00735          !readUByte(&img.tiles[0].progOrder) ||
00736          !readUWord(&img.tiles[0].nLayers) ||
00737          !readUByte(&img.tiles[0].multiComp) ||
00738          !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) ||
00739          !readUByte(&img.tiles[0].tileComps[0].codeBlockW) ||
00740          !readUByte(&img.tiles[0].tileComps[0].codeBlockH) ||
00741          !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) ||
00742          !readUByte(&img.tiles[0].tileComps[0].transform)) {
00743        error(getPos(), "Error in JPX COD marker segment");
00744        return gFalse;
00745       }
00746       img.tiles[0].tileComps[0].codeBlockW += 2;
00747       img.tiles[0].tileComps[0].codeBlockH += 2;
00748       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
00749        if (i != 0) {
00750          img.tiles[i].progOrder = img.tiles[0].progOrder;
00751          img.tiles[i].nLayers = img.tiles[0].nLayers;
00752          img.tiles[i].multiComp = img.tiles[0].multiComp;
00753        }
00754        for (comp = 0; comp < img.nComps; ++comp) {
00755          if (!(i == 0 && comp == 0)) {
00756            img.tiles[i].tileComps[comp].style =
00757                img.tiles[0].tileComps[0].style;
00758            img.tiles[i].tileComps[comp].nDecompLevels =
00759                img.tiles[0].tileComps[0].nDecompLevels;
00760            img.tiles[i].tileComps[comp].codeBlockW =
00761                img.tiles[0].tileComps[0].codeBlockW;
00762            img.tiles[i].tileComps[comp].codeBlockH =
00763                img.tiles[0].tileComps[0].codeBlockH;
00764            img.tiles[i].tileComps[comp].codeBlockStyle =
00765                img.tiles[0].tileComps[0].codeBlockStyle;
00766            img.tiles[i].tileComps[comp].transform =
00767                img.tiles[0].tileComps[0].transform;
00768          }
00769          img.tiles[i].tileComps[comp].resLevels =
00770              (JPXResLevel *)gmalloc(
00771                    (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
00772                    sizeof(JPXResLevel));
00773          for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
00774            img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
00775          }
00776        }
00777       }
00778       for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
00779        if (img.tiles[0].tileComps[0].style & 0x01) {
00780          if (!readUByte(&precinctSize)) {
00781            error(getPos(), "Error in JPX COD marker segment");
00782            return gFalse;
00783          }
00784          img.tiles[0].tileComps[0].resLevels[r].precinctWidth =
00785              precinctSize & 0x0f;
00786          img.tiles[0].tileComps[0].resLevels[r].precinctHeight =
00787              (precinctSize >> 4) & 0x0f;
00788        } else {
00789          img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15;
00790          img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15;
00791        }
00792       }
00793       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
00794        for (comp = 0; comp < img.nComps; ++comp) {
00795          if (!(i == 0 && comp == 0)) {
00796            for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
00797              img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
00798                 img.tiles[0].tileComps[0].resLevels[r].precinctWidth;
00799              img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
00800                 img.tiles[0].tileComps[0].resLevels[r].precinctHeight;
00801            }
00802          }
00803        }
00804       }
00805       haveCOD = gTrue;
00806       break;
00807     case 0x53:                     // COC - coding style component
00808       if (!haveCOD) {
00809        error(getPos(), "JPX COC marker segment before COD segment");
00810        return gFalse;
00811       }
00812       if ((img.nComps > 256 && !readUWord(&comp)) ||
00813          (img.nComps <= 256 && !readUByte(&comp)) ||
00814          comp >= img.nComps ||
00815          !readUByte(&style) ||
00816          !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) ||
00817          !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) ||
00818          !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) ||
00819          !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) ||
00820          !readUByte(&img.tiles[0].tileComps[comp].transform)) {
00821        error(getPos(), "Error in JPX COC marker segment");
00822        return gFalse;
00823       }
00824       img.tiles[0].tileComps[comp].style =
00825          (img.tiles[0].tileComps[comp].style & ~1) | (style & 1);
00826       img.tiles[0].tileComps[comp].codeBlockW += 2;
00827       img.tiles[0].tileComps[comp].codeBlockH += 2;
00828       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
00829        if (i != 0) {
00830          img.tiles[i].tileComps[comp].style =
00831              img.tiles[0].tileComps[comp].style;
00832          img.tiles[i].tileComps[comp].nDecompLevels =
00833              img.tiles[0].tileComps[comp].nDecompLevels;
00834          img.tiles[i].tileComps[comp].codeBlockW =
00835              img.tiles[0].tileComps[comp].codeBlockW;
00836          img.tiles[i].tileComps[comp].codeBlockH =
00837              img.tiles[0].tileComps[comp].codeBlockH;
00838          img.tiles[i].tileComps[comp].codeBlockStyle =
00839              img.tiles[0].tileComps[comp].codeBlockStyle;
00840          img.tiles[i].tileComps[comp].transform =
00841              img.tiles[0].tileComps[comp].transform;
00842        }
00843        img.tiles[i].tileComps[comp].resLevels =
00844            (JPXResLevel *)grealloc(
00845                    img.tiles[i].tileComps[comp].resLevels,
00846                    (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
00847                      sizeof(JPXResLevel));
00848        for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
00849          img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
00850        }
00851       }
00852       for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) {
00853        if (img.tiles[0].tileComps[comp].style & 0x01) {
00854          if (!readUByte(&precinctSize)) {
00855            error(getPos(), "Error in JPX COD marker segment");
00856            return gFalse;
00857          }
00858          img.tiles[0].tileComps[comp].resLevels[r].precinctWidth =
00859              precinctSize & 0x0f;
00860          img.tiles[0].tileComps[comp].resLevels[r].precinctHeight =
00861              (precinctSize >> 4) & 0x0f;
00862        } else {
00863          img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15;
00864          img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15;
00865        }
00866       }
00867       for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
00868        for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
00869          img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
00870              img.tiles[0].tileComps[comp].resLevels[r].precinctWidth;
00871          img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
00872              img.tiles[0].tileComps[comp].resLevels[r].precinctHeight;
00873        }
00874       }
00875       break;
00876     case 0x5c:                     // QCD - quantization default
00877       if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
00878        error(getPos(), "Error in JPX QCD marker segment");
00879        return gFalse;
00880       }
00881       if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
00882        img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
00883        img.tiles[0].tileComps[0].quantSteps =
00884            (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
00885                            img.tiles[0].tileComps[0].nQuantSteps *
00886                              sizeof(Guint));
00887        for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
00888          if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
00889            error(getPos(), "Error in JPX QCD marker segment");
00890            return gFalse;
00891          }
00892        }
00893       } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
00894        img.tiles[0].tileComps[0].nQuantSteps = 1;
00895        img.tiles[0].tileComps[0].quantSteps =
00896            (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
00897                            img.tiles[0].tileComps[0].nQuantSteps *
00898                              sizeof(Guint));
00899        if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
00900          error(getPos(), "Error in JPX QCD marker segment");
00901          return gFalse;
00902        }
00903       } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
00904        img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
00905        img.tiles[0].tileComps[0].quantSteps =
00906            (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
00907                            img.tiles[0].tileComps[0].nQuantSteps *
00908                              sizeof(Guint));
00909        for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
00910          if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
00911            error(getPos(), "Error in JPX QCD marker segment");
00912            return gFalse;
00913          }
00914        }
00915       } else {
00916        error(getPos(), "Error in JPX QCD marker segment");
00917        return gFalse;
00918       }
00919       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
00920        for (comp = 0; comp < img.nComps; ++comp) {
00921          if (!(i == 0 && comp == 0)) {
00922            img.tiles[i].tileComps[comp].quantStyle =
00923                img.tiles[0].tileComps[0].quantStyle;
00924            img.tiles[i].tileComps[comp].nQuantSteps =
00925                img.tiles[0].tileComps[0].nQuantSteps;
00926            img.tiles[i].tileComps[comp].quantSteps = 
00927                (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
00928                               img.tiles[0].tileComps[0].nQuantSteps *
00929                                 sizeof(Guint));
00930            for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
00931              img.tiles[i].tileComps[comp].quantSteps[j] =
00932                 img.tiles[0].tileComps[0].quantSteps[j];
00933            }
00934          }
00935        }
00936       }
00937       haveQCD = gTrue;
00938       break;
00939     case 0x5d:                     // QCC - quantization component
00940       if (!haveQCD) {
00941        error(getPos(), "JPX QCC marker segment before QCD segment");
00942        return gFalse;
00943       }
00944       if ((img.nComps > 256 && !readUWord(&comp)) ||
00945          (img.nComps <= 256 && !readUByte(&comp)) ||
00946          comp >= img.nComps ||
00947          !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) {
00948        error(getPos(), "Error in JPX QCC marker segment");
00949        return gFalse;
00950       }
00951       if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) {
00952        img.tiles[0].tileComps[comp].nQuantSteps =
00953            segLen - (img.nComps > 256 ? 5 : 4);
00954        img.tiles[0].tileComps[comp].quantSteps =
00955            (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
00956                            img.tiles[0].tileComps[comp].nQuantSteps *
00957                              sizeof(Guint));
00958        for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
00959          if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
00960            error(getPos(), "Error in JPX QCC marker segment");
00961            return gFalse;
00962          }
00963        }
00964       } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
00965        img.tiles[0].tileComps[comp].nQuantSteps = 1;
00966        img.tiles[0].tileComps[comp].quantSteps =
00967            (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
00968                            img.tiles[0].tileComps[comp].nQuantSteps *
00969                              sizeof(Guint));
00970        if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
00971          error(getPos(), "Error in JPX QCC marker segment");
00972          return gFalse;
00973        }
00974       } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) {
00975        img.tiles[0].tileComps[comp].nQuantSteps =
00976            (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
00977        img.tiles[0].tileComps[comp].quantSteps =
00978            (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
00979                            img.tiles[0].tileComps[comp].nQuantSteps *
00980                              sizeof(Guint));
00981        for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
00982          if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
00983            error(getPos(), "Error in JPX QCD marker segment");
00984            return gFalse;
00985          }
00986        }
00987       } else {
00988        error(getPos(), "Error in JPX QCC marker segment");
00989        return gFalse;
00990       }
00991       for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
00992        img.tiles[i].tileComps[comp].quantStyle =
00993            img.tiles[0].tileComps[comp].quantStyle;
00994        img.tiles[i].tileComps[comp].nQuantSteps =
00995            img.tiles[0].tileComps[comp].nQuantSteps;
00996        img.tiles[i].tileComps[comp].quantSteps = 
00997            (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
00998                            img.tiles[0].tileComps[comp].nQuantSteps *
00999                              sizeof(Guint));
01000        for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
01001          img.tiles[i].tileComps[comp].quantSteps[j] =
01002              img.tiles[0].tileComps[comp].quantSteps[j];
01003        }
01004       }
01005       break;
01006     case 0x5e:                     // RGN - region of interest
01007 #if 1 //~ ROI is unimplemented
01008       fprintf(stderr, "RGN\n");
01009       for (i = 0; i < segLen - 2; ++i) {
01010        if (str->getChar() == EOF) {
01011          error(getPos(), "Error in JPX PPM marker segment");
01012          return gFalse;
01013        }
01014       }
01015 #else
01016       if ((img.nComps > 256 && !readUWord(&comp)) ||
01017          (img.nComps <= 256 && !readUByte(&comp)) ||
01018          comp >= img.nComps ||
01019          !readUByte(&compInfo[comp].defROI.style) ||
01020          !readUByte(&compInfo[comp].defROI.shift)) {
01021        error(getPos(), "Error in JPX RGN marker segment");
01022        return gFalse;
01023       }
01024 #endif
01025       break;
01026     case 0x5f:                     // POC - progression order change
01027 #if 1 //~ progression order changes are unimplemented
01028       fprintf(stderr, "POC\n");
01029       for (i = 0; i < segLen - 2; ++i) {
01030        if (str->getChar() == EOF) {
01031          error(getPos(), "Error in JPX PPM marker segment");
01032          return gFalse;
01033        }
01034       }
01035 #else
01036       nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
01037       progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder));
01038       for (i = 0; i < nProgs; ++i) {
01039        if (!readUByte(&progs[i].startRes) ||
01040            !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
01041            !(img.nComps <= 256 && readUByte(&progs[i].startComp)) ||
01042            !readUWord(&progs[i].endLayer) ||
01043            !readUByte(&progs[i].endRes) ||
01044            !(img.nComps > 256 && readUWord(&progs[i].endComp)) ||
01045            !(img.nComps <= 256 && readUByte(&progs[i].endComp)) ||
01046            !readUByte(&progs[i].progOrder)) {
01047          error(getPos(), "Error in JPX POC marker segment");
01048          return gFalse;
01049        }
01050       }
01051 #endif
01052       break;
01053     case 0x60:                     // PPM - packed packet headers, main header
01054 #if 1 //~ packed packet headers are unimplemented
01055       fprintf(stderr, "PPM\n");
01056       for (i = 0; i < segLen - 2; ++i) {
01057        if (str->getChar() == EOF) {
01058          error(getPos(), "Error in JPX PPM marker segment");
01059          return gFalse;
01060        }
01061       }
01062 #endif
01063       break;
01064     case 0x55:                     // TLM - tile-part lengths
01065       // skipped
01066       for (i = 0; i < segLen - 2; ++i) {
01067        if (str->getChar() == EOF) {
01068          error(getPos(), "Error in JPX TLM marker segment");
01069          return gFalse;
01070        }
01071       }
01072       break;
01073     case 0x57:                     // PLM - packet length, main header
01074       // skipped
01075       for (i = 0; i < segLen - 2; ++i) {
01076        if (str->getChar() == EOF) {
01077          error(getPos(), "Error in JPX PLM marker segment");
01078          return gFalse;
01079        }
01080       }
01081       break;
01082     case 0x63:                     // CRG - component registration
01083       // skipped
01084       for (i = 0; i < segLen - 2; ++i) {
01085        if (str->getChar() == EOF) {
01086          error(getPos(), "Error in JPX CRG marker segment");
01087          return gFalse;
01088        }
01089       }
01090       break;
01091     case 0x64:                     // COM - comment
01092       // skipped
01093       for (i = 0; i < segLen - 2; ++i) {
01094        if (str->getChar() == EOF) {
01095          error(getPos(), "Error in JPX COM marker segment");
01096          return gFalse;
01097        }
01098       }
01099       break;
01100     case 0x90:                     // SOT - start of tile
01101       haveSOT = gTrue;
01102       break;
01103     default:
01104       error(getPos(), "Unknown marker segment %02x in JPX stream", segType);
01105       for (i = 0; i < segLen - 2; ++i) {
01106        if (str->getChar() == EOF) {
01107          break;
01108        }
01109       }
01110       break;
01111     }
01112   } while (!haveSOT);
01113 
01114   if (!haveSIZ) {
01115     error(getPos(), "Missing SIZ marker segment in JPX stream");
01116     return gFalse;
01117   }
01118   if (!haveCOD) {
01119     error(getPos(), "Missing COD marker segment in JPX stream");
01120     return gFalse;
01121   }
01122   if (!haveQCD) {
01123     error(getPos(), "Missing QCD marker segment in JPX stream");
01124     return gFalse;
01125   }
01126 
01127   //----- read the tile-parts
01128   while (1) {
01129     if (!readTilePart()) {
01130       return gFalse;
01131     }
01132     if (!readMarkerHdr(&segType, &segLen)) {
01133       error(getPos(), "Error in JPX codestream");
01134       return gFalse;
01135     }
01136     if (segType != 0x90) {  // SOT - start of tile
01137       break;
01138     }
01139   }
01140 
01141   if (segType != 0xd9) {    // EOC - end of codestream
01142     error(getPos(), "Missing EOC marker in JPX codestream");
01143     return gFalse;
01144   }
01145 
01146   //----- finish decoding the image
01147   for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
01148     tile = &img.tiles[i];
01149     for (comp = 0; comp < img.nComps; ++comp) {
01150       tileComp = &tile->tileComps[comp];
01151       inverseTransform(tileComp);
01152     }
01153     if (!inverseMultiCompAndDC(tile)) {
01154       return gFalse;
01155     }
01156   }
01157 
01158   //~ can free memory below tileComps here, and also tileComp.buf
01159 
01160   return gTrue;
01161 }
01162 
01163 GBool JPXStream::readTilePart() {
01164   JPXTile *tile;
01165   JPXTileComp *tileComp;
01166   JPXResLevel *resLevel;
01167   JPXPrecinct *precinct;
01168   JPXSubband *subband;
01169   JPXCodeBlock *cb;
01170   GBool haveSOD;
01171   Guint tileIdx, tilePartLen, tilePartIdx, nTileParts;
01172   GBool tilePartToEOC;
01173   Guint precinctSize, style;
01174   Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
01175   Guint i, j, k, cbX, cbY, r, pre, sb, cbi;
01176   int segType, level;
01177 
01178   // process the SOT marker segment
01179   if (!readUWord(&tileIdx) ||
01180       !readULong(&tilePartLen) ||
01181       !readUByte(&tilePartIdx) ||
01182       !readUByte(&nTileParts)) {
01183     error(getPos(), "Error in JPX SOT marker segment");
01184     return gFalse;
01185   }
01186 
01187   if (tileIdx >= img.nXTiles * img.nYTiles) {
01188     error(getPos(), "Weird tile index in JPX stream");
01189     return gFalse;
01190   }
01191 
01192   tilePartToEOC = tilePartLen == 0;
01193   tilePartLen -= 12; // subtract size of SOT segment
01194 
01195   haveSOD = gFalse;
01196   do {
01197     if (!readMarkerHdr(&segType, &segLen)) {
01198       error(getPos(), "Error in JPX tile-part codestream");
01199       return gFalse;
01200     }
01201     tilePartLen -= 2 + segLen;
01202     switch (segType) {
01203     case 0x52:                     // COD - coding style default
01204       if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
01205          !readUByte(&img.tiles[tileIdx].progOrder) ||
01206          !readUWord(&img.tiles[tileIdx].nLayers) ||
01207          !readUByte(&img.tiles[tileIdx].multiComp) ||
01208          !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) ||
01209          !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) ||
01210          !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) ||
01211          !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) ||
01212          !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) {
01213        error(getPos(), "Error in JPX COD marker segment");
01214        return gFalse;
01215       }
01216       img.tiles[tileIdx].tileComps[0].codeBlockW += 2;
01217       img.tiles[tileIdx].tileComps[0].codeBlockH += 2;
01218       for (comp = 0; comp < img.nComps; ++comp) {
01219        if (comp != 0) {
01220          img.tiles[tileIdx].tileComps[comp].style =
01221              img.tiles[tileIdx].tileComps[0].style;
01222          img.tiles[tileIdx].tileComps[comp].nDecompLevels =
01223              img.tiles[tileIdx].tileComps[0].nDecompLevels;
01224          img.tiles[tileIdx].tileComps[comp].codeBlockW =
01225              img.tiles[tileIdx].tileComps[0].codeBlockW;
01226          img.tiles[tileIdx].tileComps[comp].codeBlockH =
01227              img.tiles[tileIdx].tileComps[0].codeBlockH;
01228          img.tiles[tileIdx].tileComps[comp].codeBlockStyle =
01229              img.tiles[tileIdx].tileComps[0].codeBlockStyle;
01230          img.tiles[tileIdx].tileComps[comp].transform =
01231              img.tiles[tileIdx].tileComps[0].transform;
01232        }
01233        img.tiles[tileIdx].tileComps[comp].resLevels =
01234            (JPXResLevel *)grealloc(
01235                    img.tiles[tileIdx].tileComps[comp].resLevels,
01236                    (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
01237                      sizeof(JPXResLevel));
01238        for (r = 0;
01239             r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
01240             ++r) {
01241          img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
01242        }
01243       }
01244       for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) {
01245        if (img.tiles[tileIdx].tileComps[0].style & 0x01) {
01246          if (!readUByte(&precinctSize)) {
01247            error(getPos(), "Error in JPX COD marker segment");
01248            return gFalse;
01249          }
01250          img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth =
01251              precinctSize & 0x0f;
01252          img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight =
01253              (precinctSize >> 4) & 0x0f;
01254        } else {
01255          img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15;
01256          img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15;
01257        }
01258       }
01259       for (comp = 1; comp < img.nComps; ++comp) {
01260        for (r = 0;
01261             r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
01262             ++r) {
01263          img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
01264              img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth;
01265          img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
01266              img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight;
01267        }
01268       }
01269       break;
01270     case 0x53:                     // COC - coding style component
01271       if ((img.nComps > 256 && !readUWord(&comp)) ||
01272          (img.nComps <= 256 && !readUByte(&comp)) ||
01273          comp >= img.nComps ||
01274          !readUByte(&style) ||
01275          !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) ||
01276          !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) ||
01277          !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) ||
01278          !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) ||
01279          !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) {
01280        error(getPos(), "Error in JPX COC marker segment");
01281        return gFalse;
01282       }
01283       img.tiles[tileIdx].tileComps[comp].style =
01284          (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1);
01285       img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
01286       img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
01287       img.tiles[tileIdx].tileComps[comp].resLevels =
01288          (JPXResLevel *)grealloc(
01289                    img.tiles[tileIdx].tileComps[comp].resLevels,
01290                    (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
01291                      sizeof(JPXResLevel));
01292       for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
01293        img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
01294       }
01295       for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
01296        if (img.tiles[tileIdx].tileComps[comp].style & 0x01) {
01297          if (!readUByte(&precinctSize)) {
01298            error(getPos(), "Error in JPX COD marker segment");
01299            return gFalse;
01300          }
01301          img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
01302              precinctSize & 0x0f;
01303          img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
01304              (precinctSize >> 4) & 0x0f;
01305        } else {
01306          img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15;
01307          img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15;
01308        }
01309       }
01310       break;
01311     case 0x5c:                     // QCD - quantization default
01312       if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
01313        error(getPos(), "Error in JPX QCD marker segment");
01314        return gFalse;
01315       }
01316       if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) {
01317        img.tiles[tileIdx].tileComps[0].nQuantSteps =
01318            segLen - 3;
01319        img.tiles[tileIdx].tileComps[0].quantSteps =
01320            (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
01321                            img.tiles[tileIdx].tileComps[0].nQuantSteps *
01322                              sizeof(Guint));
01323        for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
01324          if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
01325            error(getPos(), "Error in JPX QCD marker segment");
01326            return gFalse;
01327          }
01328        }
01329       } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
01330        img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
01331        img.tiles[tileIdx].tileComps[0].quantSteps =
01332            (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
01333                            img.tiles[tileIdx].tileComps[0].nQuantSteps *
01334                              sizeof(Guint));
01335        if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
01336          error(getPos(), "Error in JPX QCD marker segment");
01337          return gFalse;
01338        }
01339       } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
01340        img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
01341        img.tiles[tileIdx].tileComps[0].quantSteps =
01342            (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
01343                            img.tiles[tileIdx].tileComps[0].nQuantSteps *
01344                              sizeof(Guint));
01345        for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
01346          if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
01347            error(getPos(), "Error in JPX QCD marker segment");
01348            return gFalse;
01349          }
01350        }
01351       } else {
01352        error(getPos(), "Error in JPX QCD marker segment");
01353        return gFalse;
01354       }
01355       for (comp = 1; comp < img.nComps; ++comp) {
01356        img.tiles[tileIdx].tileComps[comp].quantStyle =
01357            img.tiles[tileIdx].tileComps[0].quantStyle;
01358        img.tiles[tileIdx].tileComps[comp].nQuantSteps =
01359            img.tiles[tileIdx].tileComps[0].nQuantSteps;
01360        img.tiles[tileIdx].tileComps[comp].quantSteps = 
01361            (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
01362                            img.tiles[tileIdx].tileComps[0].nQuantSteps *
01363                              sizeof(Guint));
01364        for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
01365          img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
01366              img.tiles[tileIdx].tileComps[0].quantSteps[j];
01367        }
01368       }
01369       break;
01370     case 0x5d:                     // QCC - quantization component
01371       if ((img.nComps > 256 && !readUWord(&comp)) ||
01372          (img.nComps <= 256 && !readUByte(&comp)) ||
01373          comp >= img.nComps ||
01374          !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) {
01375        error(getPos(), "Error in JPX QCC marker segment");
01376        return gFalse;
01377       }
01378       if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) {
01379        img.tiles[tileIdx].tileComps[comp].nQuantSteps =
01380            segLen - (img.nComps > 256 ? 5 : 4);
01381        img.tiles[tileIdx].tileComps[comp].quantSteps =
01382            (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
01383                            img.tiles[tileIdx].tileComps[comp].nQuantSteps *
01384                              sizeof(Guint));
01385        for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
01386          if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
01387            error(getPos(), "Error in JPX QCC marker segment");
01388            return gFalse;
01389          }
01390        }
01391       } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
01392                == 0x01) {
01393        img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
01394        img.tiles[tileIdx].tileComps[comp].quantSteps =
01395            (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
01396                            img.tiles[tileIdx].tileComps[comp].nQuantSteps *
01397                              sizeof(Guint));
01398        if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
01399          error(getPos(), "Error in JPX QCC marker segment");
01400          return gFalse;
01401        }
01402       } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
01403                == 0x02) {
01404        img.tiles[tileIdx].tileComps[comp].nQuantSteps =
01405            (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
01406        img.tiles[tileIdx].tileComps[comp].quantSteps =
01407            (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
01408                            img.tiles[tileIdx].tileComps[comp].nQuantSteps *
01409                              sizeof(Guint));
01410        for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
01411          if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
01412            error(getPos(), "Error in JPX QCD marker segment");
01413            return gFalse;
01414          }
01415        }
01416       } else {
01417        error(getPos(), "Error in JPX QCC marker segment");
01418        return gFalse;
01419       }
01420       break;
01421     case 0x5e:                     // RGN - region of interest
01422 #if 1 //~ ROI is unimplemented
01423       fprintf(stderr, "RGN\n");
01424       for (i = 0; i < segLen - 2; ++i) {
01425        if (str->getChar() == EOF) {
01426          error(getPos(), "Error in JPX PPM marker segment");
01427          return gFalse;
01428        }
01429       }
01430 #else
01431       if ((img.nComps > 256 && !readUWord(&comp)) ||
01432          (img.nComps <= 256 && !readUByte(&comp)) ||
01433          comp >= img.nComps ||
01434          !readUByte(&compInfo[comp].roi.style) ||
01435          !readUByte(&compInfo[comp].roi.shift)) {
01436        error(getPos(), "Error in JPX RGN marker segment");
01437        return gFalse;
01438       }
01439 #endif
01440       break;
01441     case 0x5f:                     // POC - progression order change
01442 #if 1 //~ progression order changes are unimplemented
01443       fprintf(stderr, "POC\n");
01444       for (i = 0; i < segLen - 2; ++i) {
01445        if (str->getChar() == EOF) {
01446          error(getPos(), "Error in JPX PPM marker segment");
01447          return gFalse;
01448        }
01449       }
01450 #else
01451       nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
01452       tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder));
01453       for (i = 0; i < nTileProgs; ++i) {
01454        if (!readUByte(&tileProgs[i].startRes) ||
01455            !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
01456            !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) ||
01457            !readUWord(&tileProgs[i].endLayer) ||
01458            !readUByte(&tileProgs[i].endRes) ||
01459            !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) ||
01460            !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) ||
01461            !readUByte(&tileProgs[i].progOrder)) {
01462          error(getPos(), "Error in JPX POC marker segment");
01463          return gFalse;
01464        }
01465       }
01466 #endif
01467       break;
01468     case 0x61:                     // PPT - packed packet headers, tile-part hdr
01469 #if 1 //~ packed packet headers are unimplemented
01470       fprintf(stderr, "PPT\n");
01471       for (i = 0; i < segLen - 2; ++i) {
01472        if (str->getChar() == EOF) {
01473          error(getPos(), "Error in JPX PPT marker segment");
01474          return gFalse;
01475        }
01476       }
01477 #endif
01478     case 0x58:                     // PLT - packet length, tile-part header
01479       // skipped
01480       for (i = 0; i < segLen - 2; ++i) {
01481        if (str->getChar() == EOF) {
01482          error(getPos(), "Error in JPX PLT marker segment");
01483          return gFalse;
01484        }
01485       }
01486       break;
01487     case 0x64:                     // COM - comment
01488       // skipped
01489       for (i = 0; i < segLen - 2; ++i) {
01490        if (str->getChar() == EOF) {
01491          error(getPos(), "Error in JPX COM marker segment");
01492          return gFalse;
01493        }
01494       }
01495       break;
01496     case 0x93:                     // SOD - start of data
01497       haveSOD = gTrue;
01498       break;
01499     default:
01500       error(getPos(), "Unknown marker segment %02x in JPX tile-part stream",
01501            segType);
01502       for (i = 0; i < segLen - 2; ++i) {
01503        if (str->getChar() == EOF) {
01504          break;
01505        }
01506       }
01507       break;
01508     }
01509   } while (!haveSOD);
01510 
01511   //----- initialize the tile, precincts, and code-blocks
01512   if (tilePartIdx == 0) {
01513     tile = &img.tiles[tileIdx];
01514     i = tileIdx / img.nXTiles;
01515     j = tileIdx % img.nXTiles;
01516     if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
01517       tile->x0 = img.xOffset;
01518     }
01519     if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) {
01520       tile->y0 = img.yOffset;
01521     }
01522     if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) {
01523       tile->x1 = img.xSize;
01524     }
01525     if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) {
01526       tile->y1 = img.ySize;
01527     }
01528     tile->comp = 0;
01529     tile->res = 0;
01530     tile->precinct = 0;
01531     tile->layer = 0;
01532     tile->maxNDecompLevels = 0;
01533     for (comp = 0; comp < img.nComps; ++comp) {
01534       tileComp = &tile->tileComps[comp];
01535       if (tileComp->nDecompLevels > tile->maxNDecompLevels) {
01536        tile->maxNDecompLevels = tileComp->nDecompLevels;
01537       }
01538       tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep);
01539       tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep);
01540       tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
01541       tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
01542       tileComp->cbW = 1 << tileComp->codeBlockW;
01543       tileComp->cbH = 1 << tileComp->codeBlockH;
01544       tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) *
01545                                   (tileComp->y1 - tileComp->y0) *
01546                                   sizeof(int));
01547       if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
01548        n = tileComp->x1 - tileComp->x0;
01549       } else {
01550        n = tileComp->y1 - tileComp->y0;
01551       }
01552       tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int));
01553       for (r = 0; r <= tileComp->nDecompLevels; ++r) {
01554        resLevel = &tileComp->resLevels[r];
01555        k = r == 0 ? tileComp->nDecompLevels
01556                   : tileComp->nDecompLevels - r + 1;
01557        resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
01558        resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
01559        resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
01560        resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
01561        if (r == 0) {
01562          resLevel->bx0[0] = resLevel->x0;
01563          resLevel->by0[0] = resLevel->y0;
01564          resLevel->bx1[0] = resLevel->x1;
01565          resLevel->by1[0] = resLevel->y1;
01566        } else {
01567          resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
01568          resLevel->by0[0] = resLevel->y0;
01569          resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
01570          resLevel->by1[0] = resLevel->y1;
01571          resLevel->bx0[1] = resLevel->x0;
01572          resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
01573          resLevel->bx1[1] = resLevel->x1;
01574          resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
01575          resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
01576          resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
01577          resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
01578          resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
01579        }
01580        resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct));
01581        for (pre = 0; pre < 1; ++pre) {
01582          precinct = &resLevel->precincts[pre];
01583          precinct->x0 = resLevel->x0;
01584          precinct->y0 = resLevel->y0;
01585          precinct->x1 = resLevel->x1;
01586          precinct->y1 = resLevel->y1;
01587          nSBs = r == 0 ? 1 : 3;
01588          precinct->subbands =
01589              (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband));
01590          for (sb = 0; sb < nSBs; ++sb) {
01591            subband = &precinct->subbands[sb];
01592            subband->x0 = resLevel->bx0[sb];
01593            subband->y0 = resLevel->by0[sb];
01594            subband->x1 = resLevel->bx1[sb];
01595            subband->y1 = resLevel->by1[sb];
01596            subband->nXCBs = jpxCeilDivPow2(subband->x1,
01597                                        tileComp->codeBlockW)
01598                             - jpxFloorDivPow2(subband->x0,
01599                                           tileComp->codeBlockW);
01600            subband->nYCBs = jpxCeilDivPow2(subband->y1,
01601                                        tileComp->codeBlockH)
01602                             - jpxFloorDivPow2(subband->y0,
01603                                           tileComp->codeBlockH);
01604            n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
01605                                                : subband->nYCBs;
01606            for (subband->maxTTLevel = 0, --n;
01607                n;
01608                ++subband->maxTTLevel, n >>= 1) ;
01609            n = 0;
01610            for (level = subband->maxTTLevel; level >= 0; --level) {
01611              nx = jpxCeilDivPow2(subband->nXCBs, level);
01612              ny = jpxCeilDivPow2(subband->nYCBs, level);
01613              n += nx * ny;
01614            }
01615            subband->inclusion =
01616                (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
01617            subband->zeroBitPlane =
01618                (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
01619            for (k = 0; k < n; ++k) {
01620              subband->inclusion[k].finished = gFalse;
01621              subband->inclusion[k].val = 0;
01622              subband->zeroBitPlane[k].finished = gFalse;
01623              subband->zeroBitPlane[k].val = 0;
01624            }
01625            subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs *
01626                                              subband->nYCBs *
01627                                              sizeof(JPXCodeBlock));
01628            sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
01629            sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
01630            cb = subband->cbs;
01631            for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
01632              for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
01633               cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
01634               cb->x1 = cb->x0 + tileComp->cbW;
01635               if (subband->x0 > cb->x0) {
01636                 cb->x0 = subband->x0;
01637               }
01638               if (subband->x1 < cb->x1) {
01639                 cb->x1 = subband->x1;
01640               }
01641               cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
01642               cb->y1 = cb->y0 + tileComp->cbH;
01643               if (subband->y0 > cb->y0) {
01644                 cb->y0 = subband->y0;
01645               }
01646               if (subband->y1 < cb->y1) {
01647                 cb->y1 = subband->y1;
01648               }
01649               cb->seen = gFalse;
01650               cb->lBlock = 3;
01651               cb->nextPass = jpxPassCleanup;
01652               cb->nZeroBitPlanes = 0;
01653               cb->coeffs =
01654                   (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW
01655                                           + tileComp->codeBlockH))
01656                                    * sizeof(JPXCoeff));
01657               for (cbi = 0;
01658                    cbi < (Guint)(1 << (tileComp->codeBlockW
01659                                     + tileComp->codeBlockH));
01660                    ++cbi) {
01661                 cb->coeffs[cbi].flags = 0;
01662                 cb->coeffs[cbi].len = 0;
01663                 cb->coeffs[cbi].mag = 0;
01664               }
01665               cb->stats = new JArithmeticDecoderStats(jpxNContexts);
01666               cb->stats->setEntry(jpxContextSigProp, 4, 0);
01667               cb->stats->setEntry(jpxContextRunLength, 3, 0);
01668               cb->stats->setEntry(jpxContextUniform, 46, 0);
01669               ++cb;
01670              }
01671            }
01672          }
01673        }
01674       }
01675     }
01676   }
01677 
01678   return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
01679 }
01680 
01681 GBool JPXStream::readTilePartData(Guint tileIdx,
01682                               Guint tilePartLen, GBool tilePartToEOC) {
01683   JPXTile *tile;
01684   JPXTileComp *tileComp;
01685   JPXResLevel *resLevel;
01686   JPXPrecinct *precinct;
01687   JPXSubband *subband;
01688   JPXCodeBlock *cb;
01689   Guint ttVal;
01690   Guint bits, cbX, cbY, nx, ny, i, j, n, sb;
01691   int level;
01692 
01693   tile = &img.tiles[tileIdx];
01694 
01695   // read all packets from this tile-part
01696   while (1) {
01697     if (tilePartToEOC) {
01698       //~ peek for an EOC marker
01699     } else if (tilePartLen == 0) {
01700       break;
01701     }
01702 
01703     tileComp = &tile->tileComps[tile->comp];
01704     resLevel = &tileComp->resLevels[tile->res];
01705     precinct = &resLevel->precincts[tile->precinct];
01706 
01707     //----- packet header
01708 
01709     // zero-length flag
01710     if (!readBits(1, &bits)) {
01711       goto err;
01712     }
01713     if (!bits) {
01714       // packet is empty -- clear all code-block inclusion flags
01715       for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
01716        subband = &precinct->subbands[sb];
01717        for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
01718          for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
01719            cb = &subband->cbs[cbY * subband->nXCBs + cbX];
01720            cb->included = gFalse;
01721          }
01722        }
01723       }
01724     } else {
01725 
01726       for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
01727        subband = &precinct->subbands[sb];
01728        for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
01729          for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
01730            cb = &subband->cbs[cbY * subband->nXCBs + cbX];
01731 
01732            // skip code-blocks with no coefficients
01733            if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
01734              cb->included = gFalse;
01735              continue;
01736            }
01737 
01738            // code-block inclusion
01739            if (cb->seen) {
01740              if (!readBits(1, &cb->included)) {
01741               goto err;
01742              }
01743            } else {
01744              ttVal = 0;
01745              i = 0;
01746              for (level = subband->maxTTLevel; level >= 0; --level) {
01747               nx = jpxCeilDivPow2(subband->nXCBs, level);
01748               ny = jpxCeilDivPow2(subband->nYCBs, level);
01749               j = i + (cbY >> level) * nx + (cbX >> level);
01750               if (!subband->inclusion[j].finished &&
01751                   !subband->inclusion[j].val) {
01752                 subband->inclusion[j].val = ttVal;
01753               } else {
01754                 ttVal = subband->inclusion[j].val;
01755               }
01756               while (!subband->inclusion[j].finished &&
01757                      ttVal <= tile->layer) {
01758                 if (!readBits(1, &bits)) {
01759                   goto err;
01760                 }
01761                 if (bits == 1) {
01762                   subband->inclusion[j].finished = gTrue;
01763                 } else {
01764                   ++ttVal;
01765                 }
01766               }
01767               subband->inclusion[j].val = ttVal;
01768               if (ttVal > tile->layer) {
01769                 break;
01770               }
01771               i += nx * ny;
01772              }
01773              cb->included = level < 0;
01774            }
01775 
01776            if (cb->included) {
01777 
01778              // zero bit-plane count
01779              if (!cb->seen) {
01780               ttVal = 0;
01781               i = 0;
01782               for (level = subband->maxTTLevel; level >= 0; --level) {
01783                 nx = jpxCeilDivPow2(subband->nXCBs, level);
01784                 ny = jpxCeilDivPow2(subband->nYCBs, level);
01785                 j = i + (cbY >> level) * nx + (cbX >> level);
01786                 if (!subband->zeroBitPlane[j].finished &&
01787                     !subband->zeroBitPlane[j].val) {
01788                   subband->zeroBitPlane[j].val = ttVal;
01789                 } else {
01790                   ttVal = subband->zeroBitPlane[j].val;
01791                 }
01792                 while (!subband->zeroBitPlane[j].finished) {
01793                   if (!readBits(1, &bits)) {
01794                     goto err;
01795                   }
01796                   if (bits == 1) {
01797                     subband->zeroBitPlane[j].finished = gTrue;
01798                   } else {
01799                     ++ttVal;
01800                   }
01801                 }
01802                 subband->zeroBitPlane[j].val = ttVal;
01803                 i += nx * ny;
01804               }
01805               cb->nZeroBitPlanes = ttVal;
01806              }
01807 
01808              // number of coding passes
01809              if (!readBits(1, &bits)) {
01810               goto err;
01811              }
01812              if (bits == 0) {
01813               cb->nCodingPasses = 1;
01814              } else {
01815               if (!readBits(1, &bits)) {
01816                 goto err;
01817               }
01818               if (bits == 0) {
01819                 cb->nCodingPasses = 2;
01820               } else {
01821                 if (!readBits(2, &bits)) {
01822                   goto err;
01823                 }
01824                 if (bits < 3) {
01825                   cb->nCodingPasses = 3 + bits;
01826                 } else {
01827                   if (!readBits(5, &bits)) {
01828                     goto err;
01829                   }
01830                   if (bits < 31) {
01831                     cb->nCodingPasses = 6 + bits;
01832                   } else {
01833                     if (!readBits(7, &bits)) {
01834                      goto err;
01835                     }
01836                     cb->nCodingPasses = 37 + bits;
01837                   }
01838                 }
01839               }
01840              }
01841 
01842              // update Lblock
01843              while (1) {
01844               if (!readBits(1, &bits)) {
01845                 goto err;
01846               }
01847               if (!bits) {
01848                 break;
01849               }
01850               ++cb->lBlock;
01851              }
01852 
01853              // length of compressed data
01854              //~ deal with multiple codeword segments
01855              for (n = cb->lBlock, i = cb->nCodingPasses >> 1;
01856                  i;
01857                  ++n, i >>= 1) ;
01858              if (!readBits(n, &cb->dataLen)) {
01859               goto err;
01860              }
01861            }
01862          }
01863        }
01864       }
01865     }
01866     tilePartLen -= byteCount;
01867     clearBitBuf();
01868 
01869     //----- packet data
01870 
01871     for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) {
01872       subband = &precinct->subbands[sb];
01873       for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
01874        for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
01875          cb = &subband->cbs[cbY * subband->nXCBs + cbX];
01876          if (cb->included) {
01877            if (!readCodeBlockData(tileComp, resLevel, precinct, subband,
01878                                tile->res, sb, cb)) {
01879              return gFalse;
01880            }
01881            tilePartLen -= cb->dataLen;
01882            cb->seen = gTrue;
01883          }
01884        }
01885       }
01886     }
01887 
01888     //----- next packet
01889 
01890     switch (tile->progOrder) {
01891     case 0: // layer, resolution level, component, precinct
01892       if (++tile->comp == img.nComps) {
01893        tile->comp = 0;
01894        if (++tile->res == tile->maxNDecompLevels + 1) {
01895          tile->res = 0;
01896          if (++tile->layer == tile->nLayers) {
01897            tile->layer = 0;
01898          }
01899        }
01900       }
01901       break;
01902     case 1: // resolution level, layer, component, precinct
01903       if (++tile->comp == img.nComps) {
01904        tile->comp = 0;
01905        if (++tile->layer == tile->nLayers) {
01906          tile->layer = 0;
01907          if (++tile->res == tile->maxNDecompLevels + 1) {
01908            tile->res = 0;
01909          }
01910        }
01911       }
01912       break;
01913     case 2: // resolution level, precinct, component, layer
01914       //~ this isn't correct -- see B.12.1.3
01915       if (++tile->layer == tile->nLayers) {
01916        tile->layer = 0;
01917        if (++tile->comp == img.nComps) {
01918          tile->comp = 0;
01919          if (++tile->res == tile->maxNDecompLevels + 1) {
01920            tile->res = 0;
01921          }
01922        }
01923       }
01924       break;
01925     case 3: // precinct, component, resolution level, layer
01926       //~ this isn't correct -- see B.12.1.4
01927       if (++tile->layer == tile->nLayers) {
01928        tile->layer = 0;
01929        if (++tile->res == tile->maxNDecompLevels + 1) {
01930          tile->res = 0;
01931          if (++tile->comp == img.nComps) {
01932            tile->comp = 0;
01933          }
01934        }
01935       }
01936       break;
01937     case 4: // component, precinct, resolution level, layer
01938       //~ this isn't correct -- see B.12.1.5
01939       if (++tile->layer == tile->nLayers) {
01940        tile->layer = 0;
01941        if (++tile->res == tile->maxNDecompLevels + 1) {
01942          tile->res = 0;
01943          if (++tile->comp == img.nComps) {
01944            tile->comp = 0;
01945          }
01946        }
01947       }
01948       break;
01949     }
01950   }
01951 
01952   return gTrue;
01953 
01954  err:
01955   error(getPos(), "Error in JPX stream");
01956   return gFalse;
01957 }
01958 
01959 GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
01960                                JPXResLevel *resLevel,
01961                                JPXPrecinct *precinct,
01962                                JPXSubband *subband,
01963                                Guint res, Guint sb,
01964                                JPXCodeBlock *cb) {
01965   JPXCoeff *coeff0, *coeff1, *coeff;
01966   JArithmeticDecoder *arithDecoder;
01967   Guint horiz, vert, diag, all, cx, xorBit;
01968   int horizSign, vertSign;
01969   Guint i, x, y0, y1, y2;
01970 
01971   arithDecoder = new JArithmeticDecoder();
01972   arithDecoder->setStream(str, cb->dataLen);
01973   arithDecoder->start();
01974 
01975   for (i = 0; i < cb->nCodingPasses; ++i) {
01976     switch (cb->nextPass) {
01977 
01978     //----- significance propagation pass
01979     case jpxPassSigProp:
01980       for (y0 = cb->y0, coeff0 = cb->coeffs;
01981           y0 < cb->y1;
01982           y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
01983        for (x = cb->x0, coeff1 = coeff0;
01984             x < cb->x1;
01985             ++x, ++coeff1) {
01986          for (y1 = 0, coeff = coeff1;
01987               y1 < 4 && y0+y1 < cb->y1;
01988               ++y1, coeff += tileComp->cbW) {
01989            if (!(coeff->flags & jpxCoeffSignificant)) {
01990              horiz = vert = diag = 0;
01991              horizSign = vertSign = 2;
01992              if (x > cb->x0) {
01993               if (coeff[-1].flags & jpxCoeffSignificant) {
01994                 ++horiz;
01995                 horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
01996               }
01997               if (y0+y1 > cb->y0) {
01998                 diag += (coeff[-tileComp->cbW - 1].flags
01999                         >> jpxCoeffSignificantB) & 1;
02000               }
02001               if (y0+y1 < cb->y1 - 1) {
02002                 diag += (coeff[tileComp->cbW - 1].flags
02003                         >> jpxCoeffSignificantB) & 1;
02004               }
02005              }
02006              if (x < cb->x1 - 1) {
02007               if (coeff[1].flags & jpxCoeffSignificant) {
02008                 ++horiz;
02009                 horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
02010               }
02011               if (y0+y1 > cb->y0) {
02012                 diag += (coeff[-tileComp->cbW + 1].flags
02013                         >> jpxCoeffSignificantB) & 1;
02014               }
02015               if (y0+y1 < cb->y1 - 1) {
02016                 diag += (coeff[tileComp->cbW + 1].flags
02017                         >> jpxCoeffSignificantB) & 1;
02018               }
02019              }
02020              if (y0+y1 > cb->y0) {
02021               if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
02022                 ++vert;
02023                 vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
02024                             ? -1 : 1;
02025               }
02026              }
02027              if (y0+y1 < cb->y1 - 1) {
02028               if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
02029                 ++vert;
02030                 vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
02031                             ? -1 : 1;
02032               }
02033              }
02034              cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
02035              if (cx != 0) {
02036               if (arithDecoder->decodeBit(cx, cb->stats)) {
02037                 coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
02038                 coeff->mag = (coeff->mag << 1) | 1;
02039                 cx = signContext[horizSign][vertSign][0];
02040                 xorBit = signContext[horizSign][vertSign][1];
02041                 if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
02042                   coeff->flags |= jpxCoeffSign;
02043                 }
02044               }
02045               ++coeff->len;
02046               coeff->flags |= jpxCoeffTouched;
02047              }
02048            }
02049          }
02050        }
02051       }
02052       ++cb->nextPass;
02053       break;
02054 
02055     //----- magnitude refinement pass
02056     case jpxPassMagRef:
02057       for (y0 = cb->y0, coeff0 = cb->coeffs;
02058           y0 < cb->y1;
02059           y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
02060        for (x = cb->x0, coeff1 = coeff0;
02061             x < cb->x1;
02062             ++x, ++coeff1) {
02063          for (y1 = 0, coeff = coeff1;
02064               y1 < 4 && y0+y1 < cb->y1;
02065               ++y1, coeff += tileComp->cbW) {
02066            if ((coeff->flags & jpxCoeffSignificant) &&
02067               !(coeff->flags & jpxCoeffTouched)) {
02068              if (coeff->flags & jpxCoeffFirstMagRef) {
02069               all = 0;
02070               if (x > cb->x0) {
02071                 all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
02072                 if (y0+y1 > cb->y0) {
02073                   all += (coeff[-tileComp->cbW - 1].flags
02074                          >> jpxCoeffSignificantB) & 1;
02075                 }
02076                 if (y0+y1 < cb->y1 - 1) {
02077                   all += (coeff[tileComp->cbW - 1].flags
02078                          >> jpxCoeffSignificantB) & 1;
02079                 }
02080               }
02081               if (x < cb->x1 - 1) {
02082                 all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
02083                 if (y0+y1 > cb->y0) {
02084                   all += (coeff[-tileComp->cbW + 1].flags
02085                          >> jpxCoeffSignificantB) & 1;
02086                 }
02087                 if (y0+y1 < cb->y1 - 1) {
02088                   all += (coeff[tileComp->cbW + 1].flags
02089                          >> jpxCoeffSignificantB) & 1;
02090                 }
02091               }
02092               if (y0+y1 > cb->y0) {
02093                 all += (coeff[-tileComp->cbW].flags
02094                        >> jpxCoeffSignificantB) & 1;
02095               }
02096               if (y0+y1 < cb->y1 - 1) {
02097                 all += (coeff[tileComp->cbW].flags
02098                        >> jpxCoeffSignificantB) & 1;
02099               }
02100               cx = all ? 15 : 14;
02101              } else {
02102               cx = 16;
02103              }
02104              coeff->mag = (coeff->mag << 1) |
02105                          arithDecoder->decodeBit(cx, cb->stats);
02106              ++coeff->len;
02107              coeff->flags |= jpxCoeffTouched;
02108              coeff->flags &= ~jpxCoeffFirstMagRef;
02109            }
02110          }
02111        }
02112       }
02113       ++cb->nextPass;
02114       break;
02115 
02116     //----- cleanup pass
02117     case jpxPassCleanup:
02118       for (y0 = cb->y0, coeff0 = cb->coeffs;
02119           y0 < cb->y1;
02120           y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
02121        for (x = cb->x0, coeff1 = coeff0;
02122             x < cb->x1;
02123             ++x, ++coeff1) {
02124          y1 = 0;
02125          if (y0 + 3 < cb->y1 &&
02126              !(coeff1->flags & jpxCoeffTouched) &&
02127              !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) &&
02128              !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
02129              !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
02130              (x == cb->x0 || y0 == cb->y0 ||
02131               !(coeff1[-tileComp->cbW - 1].flags
02132                & jpxCoeffSignificant)) &&
02133              (y0 == cb->y0 ||
02134               !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) &&
02135              (x == cb->x1 - 1 || y0 == cb->y0 ||
02136               !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) &&
02137              (x == cb->x0 ||
02138               (!(coeff1[-1].flags & jpxCoeffSignificant) &&
02139               !(coeff1[tileComp->cbW - 1].flags
02140                 & jpxCoeffSignificant) &&
02141               !(coeff1[2 * tileComp->cbW - 1].flags
02142                 & jpxCoeffSignificant) && 
02143               !(coeff1[3 * tileComp->cbW - 1].flags
02144                 & jpxCoeffSignificant))) &&
02145              (x == cb->x1 - 1 ||
02146               (!(coeff1[1].flags & jpxCoeffSignificant) &&
02147               !(coeff1[tileComp->cbW + 1].flags
02148                 & jpxCoeffSignificant) &&
02149               !(coeff1[2 * tileComp->cbW + 1].flags
02150                 & jpxCoeffSignificant) &&
02151               !(coeff1[3 * tileComp->cbW + 1].flags
02152                 & jpxCoeffSignificant))) &&
02153              (x == cb->x0 || y0+4 == cb->y1 ||
02154               !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) &&
02155              (y0+4 == cb->y1 ||
02156               !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) &&
02157              (x == cb->x1 - 1 || y0+4 == cb->y1 ||
02158               !(coeff1[4 * tileComp->cbW + 1].flags
02159                & jpxCoeffSignificant))) {
02160            if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
02161              y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats);
02162              y1 = (y1 << 1) |
02163                  arithDecoder->decodeBit(jpxContextUniform, cb->stats);
02164              for (y2 = 0, coeff = coeff1;
02165                  y2 < y1;
02166                  ++y2, coeff += tileComp->cbW) {
02167               ++coeff->len;
02168              }
02169              coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
02170              coeff->mag = (coeff->mag << 1) | 1;
02171              ++coeff->len;
02172              cx = signContext[2][2][0];
02173              xorBit = signContext[2][2][1];
02174              if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
02175               coeff->flags |= jpxCoeffSign;
02176              }
02177              ++y1;
02178            } else {
02179              for (y1 = 0, coeff = coeff1;
02180                  y1 < 4;
02181                  ++y1, coeff += tileComp->cbW) {
02182               ++coeff->len;
02183              }
02184              y1 = 4;
02185            }
02186          }
02187          for (coeff = &coeff1[y1 << tileComp->codeBlockW];
02188               y1 < 4 && y0 + y1 < cb->y1;
02189               ++y1, coeff += tileComp->cbW) {
02190            if (!(coeff->flags & jpxCoeffTouched)) {
02191              horiz = vert = diag = 0;
02192              horizSign = vertSign = 2;
02193              if (x > cb->x0) {
02194               if (coeff[-1].flags & jpxCoeffSignificant) {
02195                 ++horiz;
02196                 horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
02197               }
02198               if (y0+y1 > cb->y0) {
02199                 diag += (coeff[-tileComp->cbW - 1].flags
02200                         >> jpxCoeffSignificantB) & 1;
02201               }
02202               if (y0+y1 < cb->y1 - 1) {
02203                 diag += (coeff[tileComp->cbW - 1].flags
02204                         >> jpxCoeffSignificantB) & 1;
02205               }
02206              }
02207              if (x < cb->x1 - 1) {
02208               if (coeff[1].flags & jpxCoeffSignificant) {
02209                 ++horiz;
02210                 horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
02211               }
02212               if (y0+y1 > cb->y0) {
02213                 diag += (coeff[-tileComp->cbW + 1].flags
02214                         >> jpxCoeffSignificantB) & 1;
02215               }
02216               if (y0+y1 < cb->y1 - 1) {
02217                 diag += (coeff[tileComp->cbW + 1].flags
02218                         >> jpxCoeffSignificantB) & 1;
02219               }
02220              }
02221              if (y0+y1 > cb->y0) {
02222               if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
02223                 ++vert;
02224                 vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
02225                             ? -1 : 1;
02226               }
02227              }
02228              if (y0+y1 < cb->y1 - 1) {
02229               if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
02230                 ++vert;
02231                 vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
02232                             ? -1 : 1;
02233               }
02234              }
02235              cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
02236              if (arithDecoder->decodeBit(cx, cb->stats)) {
02237               coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
02238               coeff->mag = (coeff->mag << 1) | 1;
02239               cx = signContext[horizSign][vertSign][0];
02240               xorBit = signContext[horizSign][vertSign][1];
02241               if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
02242                 coeff->flags |= jpxCoeffSign;
02243               }
02244              }
02245              ++coeff->len;
02246            } else {
02247              coeff->flags &= ~jpxCoeffTouched;
02248            }
02249          }
02250        }
02251       }
02252       cb->nextPass = jpxPassSigProp;
02253       break;
02254     }
02255   }
02256 
02257   delete arithDecoder;
02258   return gTrue;
02259 }
02260 
02261 // Inverse quantization, and wavelet transform (IDWT).  This also does
02262 // the initial shift to convert to fixed point format.
02263 void JPXStream::inverseTransform(JPXTileComp *tileComp) {
02264   JPXResLevel *resLevel;
02265   JPXPrecinct *precinct;
02266   JPXSubband *subband;
02267   JPXCodeBlock *cb;
02268   JPXCoeff *coeff0, *coeff;
02269   Guint qStyle, guard, eps, shift, shift2;
02270   double mu;
02271   int val;
02272   int *dataPtr;
02273   Guint nx0, ny0, nx1, ny1;
02274   Guint r, cbX, cbY, x, y;
02275 
02276   //----- (NL)LL subband (resolution level 0)
02277 
02278   resLevel = &tileComp->resLevels[0];
02279   precinct = &resLevel->precincts[0];
02280   subband = &precinct->subbands[0];
02281 
02282   // i-quant parameters
02283   qStyle = tileComp->quantStyle & 0x1f;
02284   guard = (tileComp->quantStyle >> 5) & 7;
02285   if (qStyle == 0) {
02286     eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
02287     shift = guard + eps - 1;
02288     mu = 0; // make gcc happy
02289   } else {
02290     shift = guard - 1 + tileComp->prec;
02291     mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
02292   }
02293   if (tileComp->transform == 0) {
02294     shift += fracBits;
02295   }
02296 
02297   // copy (NL)LL into the upper-left corner of the data array, doing
02298   // the fixed point adjustment and dequantization along the way
02299   cb = subband->cbs;
02300   for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
02301     for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
02302       for (y = cb->y0, coeff0 = cb->coeffs;
02303           y < cb->y1;
02304           ++y, coeff0 += tileComp->cbW) {
02305        dataPtr = &tileComp->data[(y - subband->y0)
02306                               * (tileComp->x1 - tileComp->x0)
02307                               + (cb->x0 - subband->x0)];
02308        for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
02309          val = (int)coeff->mag;
02310          if (val != 0) {
02311            shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
02312            if (shift2 > 0) {
02313              val = (val << shift2) + (1 << (shift2 - 1));
02314            } else {
02315              val >>= -shift2;
02316            }
02317            if (qStyle == 0) {
02318              if (tileComp->transform == 0) {
02319               val &= -1 << fracBits;
02320              }
02321            } else {
02322              val = (int)((double)val * mu);
02323            }
02324            if (coeff->flags & jpxCoeffSign) {
02325              val = -val;
02326            }
02327          }
02328          *dataPtr++ = val;
02329        }
02330       }
02331       ++cb;
02332     }
02333   }
02334 
02335   //----- IDWT for each level
02336 
02337   for (r = 1; r <= tileComp->nDecompLevels; ++r) {
02338     resLevel = &tileComp->resLevels[r];
02339 
02340     // (n)LL is already in the upper-left corner of the
02341     // tile-component data array -- interleave with (n)HL/LH/HH
02342     // and inverse transform to get (n-1)LL, which will be stored
02343     // in the upper-left corner of the tile-component data array
02344     if (r == tileComp->nDecompLevels) {
02345       nx0 = tileComp->x0;
02346       ny0 = tileComp->y0;
02347       nx1 = tileComp->x1;
02348       ny1 = tileComp->y1;
02349     } else {
02350       nx0 = tileComp->resLevels[r+1].x0;
02351       ny0 = tileComp->resLevels[r+1].y0;
02352       nx1 = tileComp->resLevels[r+1].x1;
02353       ny1 = tileComp->resLevels[r+1].y1;
02354     }
02355     inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1);
02356   }
02357 }
02358 
02359 // Do one level of the inverse transform:
02360 // - take (n)LL from the tile-component data array
02361 // - take (n)HL/LH/HH from <resLevel>
02362 // - leave the resulting (n-1)LL in the tile-component data array
02363 void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
02364                                   Guint r, JPXResLevel *resLevel,
02365                                   Guint nx0, Guint ny0,
02366                                   Guint nx1, Guint ny1) {
02367   JPXPrecinct *precinct;
02368   JPXSubband *subband;
02369   JPXCodeBlock *cb;
02370   JPXCoeff *coeff0, *coeff;
02371   Guint qStyle, guard, eps, shift, shift2, t;
02372   double mu;
02373   int val;
02374   int *dataPtr;
02375   Guint xo, yo;
02376   Guint x, y, sb, cbX, cbY;
02377   int xx, yy;
02378 
02379   //----- interleave
02380 
02381   // spread out LL
02382   for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) {
02383     for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) {
02384       tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0)
02385                    + (2 * xx - nx0)] =
02386          tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0)
02387                       + (xx - resLevel->x0)];
02388     }
02389   }
02390 
02391   // i-quant parameters
02392   qStyle = tileComp->quantStyle & 0x1f;
02393   guard = (tileComp->quantStyle >> 5) & 7;
02394 
02395   // interleave HL/LH/HH
02396   precinct = &resLevel->precincts[0];
02397   for (sb = 0; sb < 3; ++sb) {
02398 
02399     // i-quant parameters
02400     if (qStyle == 0) {
02401       eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f;
02402       shift = guard + eps - 1;
02403       mu = 0; // make gcc happy
02404     } else {
02405       shift = guard + tileComp->prec;
02406       if (sb == 2) {
02407        ++shift;
02408       }
02409       t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)];
02410       mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
02411     }
02412     if (tileComp->transform == 0) {
02413       shift += fracBits;
02414     }
02415 
02416     // copy the subband coefficients into the data array, doing the
02417     // fixed point adjustment and dequantization along the way
02418     xo = (sb & 1) ? 0 : 1;
02419     yo = (sb > 0) ? 1 : 0;
02420     subband = &precinct->subbands[sb];
02421     cb = subband->cbs;
02422     for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
02423       for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
02424        for (y = cb->y0, coeff0 = cb->coeffs;
02425             y < cb->y1;
02426             ++y, coeff0 += tileComp->cbW) {
02427          dataPtr = &tileComp->data[(2 * y + yo - ny0)
02428                                 * (tileComp->x1 - tileComp->x0)
02429                                 + (2 * cb->x0 + xo - nx0)];
02430          for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
02431            val = (int)coeff->mag;
02432            if (val != 0) {
02433              shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
02434              if (shift2 > 0) {
02435               val = (val << shift2) + (1 << (shift2 - 1));
02436              } else {
02437               val >>= -shift2;
02438              }
02439              if (qStyle == 0) {
02440               if (tileComp->transform == 0) {
02441                 val &= -1 << fracBits;
02442               }
02443              } else {
02444               val = (int)((double)val * mu);
02445              }
02446              if (coeff->flags & jpxCoeffSign) {
02447               val = -val;
02448              }
02449            }
02450            *dataPtr = val;
02451            dataPtr += 2;
02452          }
02453        }
02454        ++cb;
02455       }
02456     }
02457   }
02458 
02459   //----- horizontal (row) transforms
02460   dataPtr = tileComp->data;
02461   for (y = 0; y < ny1 - ny0; ++y) {
02462     inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1);
02463     dataPtr += tileComp->x1 - tileComp->x0;
02464   }
02465 
02466   //----- vertical (column) transforms
02467   dataPtr = tileComp->data;
02468   for (x = 0; x < nx1 - nx0; ++x) {
02469     inverseTransform1D(tileComp, dataPtr,
02470                      tileComp->x1 - tileComp->x0, ny0, ny1);
02471     ++dataPtr;
02472   }
02473 }
02474 
02475 void JPXStream::inverseTransform1D(JPXTileComp *tileComp,
02476                                int *data, Guint stride,
02477                                Guint i0, Guint i1) {
02478   int *buf;
02479   Guint offset, end, i;
02480 
02481   //----- special case for length = 1
02482   if (i1 - i0 == 1) {
02483     if (i0 & 1) {
02484       *data >>= 1;
02485     }
02486 
02487   } else {
02488 
02489     // choose an offset: this makes even buf[] indexes correspond to
02490     // odd values of i, and vice versa
02491     offset = 3 + (i0 & 1);
02492     end = offset + i1 - i0;
02493 
02494     //----- gather
02495     buf = tileComp->buf;
02496     for (i = 0; i < i1 - i0; ++i) {
02497       buf[offset + i] = data[i * stride];
02498     }
02499 
02500     //----- extend right
02501     buf[end] = buf[end - 2];
02502     if (i1 - i0 == 2) {
02503       buf[end+1] = buf[offset + 1];
02504       buf[end+2] = buf[offset];
02505       buf[end+3] = buf[offset + 1];
02506     } else {
02507       buf[end+1] = buf[end - 3];
02508       if (i1 - i0 == 3) {
02509        buf[end+2] = buf[offset + 1];
02510        buf[end+3] = buf[offset + 2];
02511       } else {
02512        buf[end+2] = buf[end - 4];
02513        if (i1 - i0 == 4) {
02514          buf[end+3] = buf[offset + 1];
02515        } else {
02516          buf[end+3] = buf[end - 5];
02517        }
02518       }
02519     }
02520 
02521     //----- extend left
02522     buf[offset - 1] = buf[offset + 1];
02523     buf[offset - 2] = buf[offset + 2];
02524     buf[offset - 3] = buf[offset + 3];
02525     if (offset == 4) {
02526       buf[0] = buf[offset + 4];
02527     }
02528 
02529     //----- 9-7 irreversible filter
02530 
02531     if (tileComp->transform == 0) {
02532       // step 1 (even)
02533       for (i = 1; i <= end + 2; i += 2) {
02534        buf[i] = (int)(idwtKappa * buf[i]);
02535       }
02536       // step 2 (odd)
02537       for (i = 0; i <= end + 3; i += 2) {
02538        buf[i] = (int)(idwtIKappa * buf[i]);
02539       }
02540       // step 3 (even)
02541       for (i = 1; i <= end + 2; i += 2) {
02542        buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1]));
02543       }
02544       // step 4 (odd)
02545       for (i = 2; i <= end + 1; i += 2) {
02546        buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1]));
02547       }
02548       // step 5 (even)
02549       for (i = 3; i <= end; i += 2) {
02550        buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1]));
02551       }
02552       // step 6 (odd)
02553       for (i = 4; i <= end - 1; i += 2) {
02554        buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1]));
02555       }
02556 
02557     //----- 5-3 reversible filter
02558 
02559     } else {
02560       // step 1 (even)
02561       for (i = 3; i <= end; i += 2) {
02562        buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2;
02563       }
02564       // step 2 (odd)
02565       for (i = 4; i < end; i += 2) {
02566        buf[i] += (buf[i-1] + buf[i+1]) >> 1;
02567       }
02568     }
02569 
02570     //----- scatter
02571     for (i = 0; i < i1 - i0; ++i) {
02572       data[i * stride] = buf[offset + i];
02573     }
02574   }
02575 }
02576 
02577 // Inverse multi-component transform and DC level shift.  This also
02578 // converts fixed point samples back to integers.
02579 GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
02580   JPXTileComp *tileComp;
02581   int coeff, d0, d1, d2, minVal, maxVal, zeroVal;
02582   int *dataPtr;
02583   Guint j, comp, x, y;
02584 
02585   //----- inverse multi-component transform
02586 
02587   if (tile->multiComp == 1) {
02588     if (img.nComps < 3 ||
02589        tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
02590        tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
02591        tile->tileComps[1].hSep != tile->tileComps[2].hSep ||
02592        tile->tileComps[1].vSep != tile->tileComps[2].vSep) {
02593       return gFalse;
02594     }
02595 
02596     // inverse irreversible multiple component transform
02597     if (tile->tileComps[0].transform == 0) {
02598       j = 0;
02599       for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
02600        for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
02601          d0 = tile->tileComps[0].data[j];
02602          d1 = tile->tileComps[1].data[j];
02603          d2 = tile->tileComps[2].data[j];
02604          tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5);
02605          tile->tileComps[1].data[j] =
02606              (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5);
02607          tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5);
02608          ++j;
02609        }
02610       }
02611 
02612     // inverse reversible multiple component transform
02613     } else {
02614       j = 0;
02615       for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
02616        for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
02617          d0 = tile->tileComps[0].data[j];
02618          d1 = tile->tileComps[1].data[j];
02619          d2 = tile->tileComps[2].data[j];
02620          tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2);
02621          tile->tileComps[1].data[j] = d2 - d1;
02622          tile->tileComps[2].data[j] = d0 - d1;
02623          ++j;
02624        }
02625       }
02626     }
02627   }
02628 
02629   //----- DC level shift
02630   for (comp = 0; comp < img.nComps; ++comp) {
02631     tileComp = &tile->tileComps[comp];
02632 
02633     // signed: clip
02634     if (tileComp->sgned) {
02635       minVal = -(1 << (tileComp->prec - 1));
02636       maxVal = (1 << (tileComp->prec - 1)) - 1;
02637       dataPtr = tileComp->data;
02638       for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
02639        for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
02640          coeff = *dataPtr;
02641          if (tileComp->transform == 0) {
02642            coeff >>= fracBits;
02643          }
02644          if (coeff < minVal) {
02645            coeff = minVal;
02646          } else if (coeff > maxVal) {
02647            coeff = maxVal;
02648          }
02649          *dataPtr++ = coeff;
02650        }
02651       }
02652 
02653     // unsigned: inverse DC level shift and clip
02654     } else {
02655       maxVal = (1 << tileComp->prec) - 1;
02656       zeroVal = 1 << (tileComp->prec - 1);
02657       dataPtr = tileComp->data;
02658       for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
02659        for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
02660          coeff = *dataPtr;
02661          if (tileComp->transform == 0) {
02662            coeff >>= fracBits;
02663          }
02664          coeff += zeroVal;
02665          if (coeff < 0) {
02666            coeff = 0;
02667          } else if (coeff > maxVal) {
02668            coeff = maxVal;
02669          }
02670          *dataPtr++ = coeff;
02671        }
02672       }
02673     }
02674   }
02675 
02676   return gTrue;
02677 }
02678 
02679 GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) {
02680   Guint len, lenH;
02681 
02682   if (!readULong(&len) ||
02683       !readULong(boxType)) {
02684     return gFalse;
02685   }
02686   if (len == 1) {
02687     if (!readULong(&lenH) || !readULong(&len)) {
02688       return gFalse;
02689     }
02690     if (lenH) {
02691       error(getPos(), "JPX stream contains a box larger than 2^32 bytes");
02692       return gFalse;
02693     }
02694     *boxLen = len;
02695     *dataLen = len - 16;
02696   } else if (len == 0) {
02697     *boxLen = 0;
02698     *dataLen = 0;
02699   } else {
02700     *boxLen = len;
02701     *dataLen = len - 8;
02702   }
02703   return gTrue;
02704 }
02705 
02706 int JPXStream::readMarkerHdr(int *segType, Guint *segLen) {
02707   int c;
02708 
02709   do {
02710     do {
02711       if ((c = str->getChar()) == EOF) {
02712        return gFalse;
02713       }
02714     } while (c != 0xff);
02715     do {
02716       if ((c = str->getChar()) == EOF) {
02717        return gFalse;
02718       }
02719     } while (c == 0xff);
02720   } while (c == 0x00);
02721   *segType = c;
02722   if ((c >= 0x30 && c <= 0x3f) ||
02723       c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) {
02724     *segLen = 0;
02725     return gTrue;
02726   }
02727   return readUWord(segLen);
02728 }
02729 
02730 GBool JPXStream::readUByte(Guint *x) {
02731   int c0;
02732 
02733   if ((c0 = str->getChar()) == EOF) {
02734     return gFalse;
02735   }
02736   *x = (Guint)c0;
02737   return gTrue;
02738 }
02739 
02740 GBool JPXStream::readByte(int *x) {
02741  int c0;
02742 
02743   if ((c0 = str->getChar()) == EOF) {
02744     return gFalse;
02745   }
02746   *x = c0;
02747   if (c0 & 0x80) {
02748     *x |= -1 - 0xff;
02749   }
02750   return gTrue;
02751 }
02752 
02753 GBool JPXStream::readUWord(Guint *x) {
02754   int c0, c1;
02755 
02756   if ((c0 = str->getChar()) == EOF ||
02757       (c1 = str->getChar()) == EOF) {
02758     return gFalse;
02759   }
02760   *x = (Guint)((c0 << 8) | c1);
02761   return gTrue;
02762 }
02763 
02764 GBool JPXStream::readULong(Guint *x) {
02765   int c0, c1, c2, c3;
02766 
02767   if ((c0 = str->getChar()) == EOF ||
02768       (c1 = str->getChar()) == EOF ||
02769       (c2 = str->getChar()) == EOF ||
02770       (c3 = str->getChar()) == EOF) {
02771     return gFalse;
02772   }
02773   *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
02774   return gTrue;
02775 }
02776 
02777 GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) {
02778   int y, c, i;
02779 
02780   y = 0;
02781   for (i = 0; i < nBytes; ++i) {
02782     if ((c = str->getChar()) == EOF) {
02783       return gFalse;
02784     }
02785     y = (y << 8) + c;
02786   }
02787   if (signd) {
02788     if (y & (1 << (8 * nBytes - 1))) {
02789       y |= -1 << (8 * nBytes);
02790     }
02791   }
02792   *x = y;
02793   return gTrue;
02794 }
02795 
02796 GBool JPXStream::readBits(int nBits, Guint *x) {
02797   int c;
02798 
02799   while (bitBufLen < nBits) {
02800     if ((c = str->getChar()) == EOF) {
02801       return gFalse;
02802     }
02803     ++byteCount;
02804     if (bitBufSkip) {
02805       bitBuf = (bitBuf << 7) | (c & 0x7f);
02806       bitBufLen += 7;
02807     } else {
02808       bitBuf = (bitBuf << 8) | (c & 0xff);
02809       bitBufLen += 8;
02810     }
02811     bitBufSkip = c == 0xff;
02812   }
02813   *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1);
02814   bitBufLen -= nBits;
02815   return gTrue;
02816 }
02817 
02818 void JPXStream::clearBitBuf() {
02819   bitBufLen = 0;
02820   bitBufSkip = gFalse;
02821   byteCount = 0;
02822 }