upgraded to xpdf-3.01pl1
[swftools.git] / pdf2swf / xpdf / JPXStream.cc
index defa7d2..336b7ba 100644 (file)
@@ -243,6 +243,9 @@ JPXStream::~JPXStream() {
                        for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
                          cb = &subband->cbs[k];
                          gfree(cb->coeffs);
+                         if (cb->arithDecoder) {
+                           delete cb->arithDecoder;
+                         }
                          if (cb->stats) {
                            delete cb->stats;
                          }
@@ -374,6 +377,122 @@ GBool JPXStream::isBinary(GBool last) {
   return str->isBinary(gTrue);
 }
 
+void JPXStream::getImageParams(int *bitsPerComponent,
+                              StreamColorSpaceMode *csMode) {
+  Guint boxType, boxLen, dataLen, csEnum;
+  Guint bpc1, dummy, i;
+  int csMeth, csPrec, csPrec1, dummy2;
+  StreamColorSpaceMode csMode1;
+  GBool haveBPC, haveCSMode;
+
+  csPrec = 0; // make gcc happy
+  haveBPC = haveCSMode = gFalse;
+  str->reset();
+  if (str->lookChar() == 0xff) {
+    getImageParams2(bitsPerComponent, csMode);
+  } else {
+    while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+      if (boxType == 0x6a703268) { // JP2 header
+       // skip the superbox
+      } else if (boxType == 0x69686472) { // image header
+       if (readULong(&dummy) &&
+           readULong(&dummy) &&
+           readUWord(&dummy) &&
+           readUByte(&bpc1) &&
+           readUByte(&dummy) &&
+           readUByte(&dummy) &&
+           readUByte(&dummy)) {
+         *bitsPerComponent = bpc1 + 1;
+         haveBPC = gTrue;
+       }
+      } else if (boxType == 0x636F6C72) { // color specification
+       if (readByte(&csMeth) &&
+           readByte(&csPrec1) &&
+           readByte(&dummy2)) {
+         if (csMeth == 1) {
+           if (readULong(&csEnum)) {
+             csMode1 = streamCSNone;
+             if (csEnum == jpxCSBiLevel ||
+                 csEnum == jpxCSGrayscale) {
+               csMode1 = streamCSDeviceGray;
+             } else if (csEnum == jpxCSCMYK) {
+               csMode1 = streamCSDeviceCMYK;
+             } else if (csEnum == jpxCSsRGB ||
+                        csEnum == jpxCSCISesRGB ||
+                        csEnum == jpxCSROMMRGB) {
+               csMode1 = streamCSDeviceRGB;
+             }
+             if (csMode1 != streamCSNone &&
+                 (!haveCSMode || csPrec1 > csPrec)) {
+               *csMode = csMode1;
+               csPrec = csPrec1;
+               haveCSMode = gTrue;
+             }
+             for (i = 0; i < dataLen - 7; ++i) {
+               str->getChar();
+             }
+           }
+         } else {
+           for (i = 0; i < dataLen - 3; ++i) {
+             str->getChar();
+           }
+         }
+       }
+      } else if (boxType == 0x6A703263) { // codestream
+       if (!(haveBPC && haveCSMode)) {
+         getImageParams2(bitsPerComponent, csMode);
+       }
+       break;
+      } else {
+       for (i = 0; i < dataLen; ++i) {
+         str->getChar();
+       }
+      }
+    }
+  }
+  str->close();
+}
+
+// Get image parameters from the codestream.
+void JPXStream::getImageParams2(int *bitsPerComponent,
+                               StreamColorSpaceMode *csMode) {
+  int segType;
+  Guint segLen, nComps1, bpc1, dummy, i;
+
+  while (readMarkerHdr(&segType, &segLen)) {
+    if (segType == 0x51) { // SIZ - image and tile size
+      if (readUWord(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readULong(&dummy) &&
+         readUWord(&nComps1) &&
+         readUByte(&bpc1)) {
+       *bitsPerComponent = (bpc1 & 0x7f) + 1;
+       // if there's no color space info, take a guess
+       if (nComps1 == 1) {
+         *csMode = streamCSDeviceGray;
+       } else if (nComps1 == 3) {
+         *csMode = streamCSDeviceRGB;
+       } else if (nComps1 == 4) {
+         *csMode = streamCSDeviceCMYK;
+       }
+      }
+      break;
+    } else {
+      if (segLen > 2) {
+       for (i = 0; i < segLen - 2; ++i) {
+         str->getChar();
+       }
+      }
+    }
+  }
+}
+
 GBool JPXStream::readBoxes() {
   Guint boxType, boxLen, dataLen;
   Guint bpc1, compression, unknownColorspace, ipr;
@@ -388,7 +507,7 @@ GBool JPXStream::readBoxes() {
     error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
     readCodestream(0);
     nComps = img.nComps;
-    bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
+    bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
     for (i = 0; i < nComps; ++i) {
       bpc[i] = img.tiles[0].tileComps[i].prec;
     }
@@ -421,7 +540,7 @@ GBool JPXStream::readBoxes() {
        error(getPos(), "Unknown compression type in JPX stream");
        return gFalse;
       }
-      bpc = (Guint *)gmalloc(nComps * sizeof(Guint));
+      bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
       for (i = 0; i < nComps; ++i) {
        bpc[i] = bpc1;
       }
@@ -454,9 +573,9 @@ GBool JPXStream::readBoxes() {
        error(getPos(), "Unexpected EOF in JPX stream");
        return gFalse;
       }
-      palette.bpc = (Guint *)gmalloc(palette.nComps * sizeof(Guint));
+      palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
       palette.c =
-          (int *)gmalloc(palette.nEntries * palette.nComps * sizeof(int));
+          (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
       for (i = 0; i < palette.nComps; ++i) {
        if (!readUByte(&palette.bpc[i])) {
          error(getPos(), "Unexpected EOF in JPX stream");
@@ -478,9 +597,9 @@ GBool JPXStream::readBoxes() {
       break;
     case 0x636d6170:           // component mapping
       compMap.nChannels = dataLen / 4;
-      compMap.comp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
-      compMap.type = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
-      compMap.pComp = (Guint *)gmalloc(compMap.nChannels * sizeof(Guint));
+      compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+      compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+      compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
       for (i = 0; i < compMap.nChannels; ++i) {
        if (!readUWord(&compMap.comp[i]) ||
            !readUByte(&compMap.type[i]) ||
@@ -497,11 +616,11 @@ GBool JPXStream::readBoxes() {
        return gFalse;
       }
       channelDefn.idx =
-         (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+         (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
       channelDefn.type =
-         (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+         (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
       channelDefn.assoc =
-         (Guint *)gmalloc(channelDefn.nChannels * sizeof(Guint));
+         (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
       for (i = 0; i < channelDefn.nChannels; ++i) {
        if (!readUWord(&channelDefn.idx[i]) ||
            !readUWord(&channelDefn.type[i]) ||
@@ -515,11 +634,9 @@ GBool JPXStream::readBoxes() {
     case 0x6A703263:           // contiguous codestream
       if (!bpc) {
        error(getPos(), "JPX stream is missing the image header box");
-       return gFalse;
       }
       if (!haveCS) {
        error(getPos(), "JPX stream has no supported color spec");
-       return gFalse;
       }
       if (!readCodestream(dataLen)) {
        return gFalse;
@@ -582,7 +699,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) {
       ok = gTrue;
       break;
     case jpxCSCIELab:
-      if (dataLen == 3 + 7*4) {
+      if (dataLen == 7 + 7*4) {
        if (!readULong(&newCS.enumerated.cieLab.rl) ||
            !readULong(&newCS.enumerated.cieLab.ol) ||
            !readULong(&newCS.enumerated.cieLab.ra) ||
@@ -592,7 +709,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) {
            !readULong(&newCS.enumerated.cieLab.il)) {
          goto err;
        }
-      } else if (dataLen == 3) {
+      } else if (dataLen == 7) {
        //~ this assumes the 8-bit case
        newCS.enumerated.cieLab.rl = 100;
        newCS.enumerated.cieLab.ol = 0;
@@ -666,7 +783,7 @@ GBool JPXStream::readCodestream(Guint len) {
   int segType;
   GBool haveSIZ, haveCOD, haveQCD, haveSOT;
   Guint precinctSize, style;
-  Guint segLen, capabilities, comp, i, j, r;
+  Guint segLen, capabilities, nTiles, comp, i, j, r;
 
   //----- main header
   haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
@@ -701,11 +818,16 @@ GBool JPXStream::readCodestream(Guint len) {
                    / img.xTileSize;
       img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
                    / img.yTileSize;
-      img.tiles = (JPXTile *)gmalloc(img.nXTiles * img.nYTiles *
-                                    sizeof(JPXTile));
+      nTiles = img.nXTiles * img.nYTiles;
+      // check for overflow before allocating memory
+      if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) {
+       error(getPos(), "Bad tile count in JPX SIZ marker segment");
+       return gFalse;
+      }
+      img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile));
       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
-       img.tiles[i].tileComps = (JPXTileComp *)gmalloc(img.nComps *
-                                                       sizeof(JPXTileComp));
+       img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
+                                                        sizeof(JPXTileComp));
        for (comp = 0; comp < img.nComps; ++comp) {
          img.tiles[i].tileComps[comp].quantSteps = NULL;
          img.tiles[i].tileComps[comp].data = NULL;
@@ -767,8 +889,8 @@ GBool JPXStream::readCodestream(Guint len) {
                img.tiles[0].tileComps[0].transform;
          }
          img.tiles[i].tileComps[comp].resLevels =
-             (JPXResLevel *)gmalloc(
-                    (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
+             (JPXResLevel *)gmallocn(
+                    (img.tiles[i].tileComps[comp].nDecompLevels + 1),
                     sizeof(JPXResLevel));
          for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
            img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
@@ -841,10 +963,10 @@ GBool JPXStream::readCodestream(Guint len) {
              img.tiles[0].tileComps[comp].transform;
        }
        img.tiles[i].tileComps[comp].resLevels =
-           (JPXResLevel *)grealloc(
+           (JPXResLevel *)greallocn(
                     img.tiles[i].tileComps[comp].resLevels,
-                    (img.tiles[i].tileComps[comp].nDecompLevels + 1) *
-                      sizeof(JPXResLevel));
+                    (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+                    sizeof(JPXResLevel));
        for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
          img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
        }
@@ -881,9 +1003,9 @@ GBool JPXStream::readCodestream(Guint len) {
       if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
        img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
        img.tiles[0].tileComps[0].quantSteps =
-           (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
-                             img.tiles[0].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+                              img.tiles[0].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
          if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
            error(getPos(), "Error in JPX QCD marker segment");
@@ -893,9 +1015,9 @@ GBool JPXStream::readCodestream(Guint len) {
       } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
        img.tiles[0].tileComps[0].nQuantSteps = 1;
        img.tiles[0].tileComps[0].quantSteps =
-           (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
-                             img.tiles[0].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+                              img.tiles[0].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
          error(getPos(), "Error in JPX QCD marker segment");
          return gFalse;
@@ -903,9 +1025,9 @@ GBool JPXStream::readCodestream(Guint len) {
       } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
        img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
        img.tiles[0].tileComps[0].quantSteps =
-           (Guint *)grealloc(img.tiles[0].tileComps[0].quantSteps,
-                             img.tiles[0].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+                              img.tiles[0].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
          if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
            error(getPos(), "Error in JPX QCD marker segment");
@@ -924,9 +1046,9 @@ GBool JPXStream::readCodestream(Guint len) {
            img.tiles[i].tileComps[comp].nQuantSteps =
                img.tiles[0].tileComps[0].nQuantSteps;
            img.tiles[i].tileComps[comp].quantSteps = 
-               (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
-                                 img.tiles[0].tileComps[0].nQuantSteps *
-                                   sizeof(Guint));
+               (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+                                  img.tiles[0].tileComps[0].nQuantSteps,
+                                  sizeof(Guint));
            for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
              img.tiles[i].tileComps[comp].quantSteps[j] =
                  img.tiles[0].tileComps[0].quantSteps[j];
@@ -952,9 +1074,9 @@ GBool JPXStream::readCodestream(Guint len) {
        img.tiles[0].tileComps[comp].nQuantSteps =
            segLen - (img.nComps > 256 ? 5 : 4);
        img.tiles[0].tileComps[comp].quantSteps =
-           (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
-                             img.tiles[0].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+                              img.tiles[0].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
          if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
            error(getPos(), "Error in JPX QCC marker segment");
@@ -964,9 +1086,9 @@ GBool JPXStream::readCodestream(Guint len) {
       } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
        img.tiles[0].tileComps[comp].nQuantSteps = 1;
        img.tiles[0].tileComps[comp].quantSteps =
-           (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
-                             img.tiles[0].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+                              img.tiles[0].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
          error(getPos(), "Error in JPX QCC marker segment");
          return gFalse;
@@ -975,9 +1097,9 @@ GBool JPXStream::readCodestream(Guint len) {
        img.tiles[0].tileComps[comp].nQuantSteps =
            (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
        img.tiles[0].tileComps[comp].quantSteps =
-           (Guint *)grealloc(img.tiles[0].tileComps[comp].quantSteps,
-                             img.tiles[0].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+                              img.tiles[0].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
          if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
            error(getPos(), "Error in JPX QCD marker segment");
@@ -994,9 +1116,9 @@ GBool JPXStream::readCodestream(Guint len) {
        img.tiles[i].tileComps[comp].nQuantSteps =
            img.tiles[0].tileComps[comp].nQuantSteps;
        img.tiles[i].tileComps[comp].quantSteps = 
-           (Guint *)grealloc(img.tiles[i].tileComps[comp].quantSteps,
-                             img.tiles[0].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+                              img.tiles[0].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
          img.tiles[i].tileComps[comp].quantSteps[j] =
              img.tiles[0].tileComps[comp].quantSteps[j];
@@ -1034,7 +1156,7 @@ GBool JPXStream::readCodestream(Guint len) {
       }
 #else
       nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
-      progs = (JPXProgOrder *)gmalloc(nProgs * sizeof(JPXProgOrder));
+      progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
       for (i = 0; i < nProgs; ++i) {
        if (!readUByte(&progs[i].startRes) ||
            !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
@@ -1231,10 +1353,10 @@ GBool JPXStream::readTilePart() {
              img.tiles[tileIdx].tileComps[0].transform;
        }
        img.tiles[tileIdx].tileComps[comp].resLevels =
-           (JPXResLevel *)grealloc(
+           (JPXResLevel *)greallocn(
                     img.tiles[tileIdx].tileComps[comp].resLevels,
-                    (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
-                      sizeof(JPXResLevel));
+                    (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+                    sizeof(JPXResLevel));
        for (r = 0;
             r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
             ++r) {
@@ -1285,10 +1407,10 @@ GBool JPXStream::readTilePart() {
       img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
       img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
       img.tiles[tileIdx].tileComps[comp].resLevels =
-         (JPXResLevel *)grealloc(
+         (JPXResLevel *)greallocn(
                     img.tiles[tileIdx].tileComps[comp].resLevels,
-                    (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1) *
-                      sizeof(JPXResLevel));
+                    (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+                    sizeof(JPXResLevel));
       for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
        img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
       }
@@ -1317,9 +1439,9 @@ GBool JPXStream::readTilePart() {
        img.tiles[tileIdx].tileComps[0].nQuantSteps =
            segLen - 3;
        img.tiles[tileIdx].tileComps[0].quantSteps =
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
-                             img.tiles[tileIdx].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+                              img.tiles[tileIdx].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
          if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
            error(getPos(), "Error in JPX QCD marker segment");
@@ -1329,9 +1451,9 @@ GBool JPXStream::readTilePart() {
       } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
        img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
        img.tiles[tileIdx].tileComps[0].quantSteps =
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
-                             img.tiles[tileIdx].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+                              img.tiles[tileIdx].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
          error(getPos(), "Error in JPX QCD marker segment");
          return gFalse;
@@ -1339,9 +1461,9 @@ GBool JPXStream::readTilePart() {
       } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
        img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
        img.tiles[tileIdx].tileComps[0].quantSteps =
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[0].quantSteps,
-                             img.tiles[tileIdx].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+                              img.tiles[tileIdx].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
          if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
            error(getPos(), "Error in JPX QCD marker segment");
@@ -1358,9 +1480,9 @@ GBool JPXStream::readTilePart() {
        img.tiles[tileIdx].tileComps[comp].nQuantSteps =
            img.tiles[tileIdx].tileComps[0].nQuantSteps;
        img.tiles[tileIdx].tileComps[comp].quantSteps = 
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-                             img.tiles[tileIdx].tileComps[0].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+                              img.tiles[tileIdx].tileComps[0].nQuantSteps,
+                              sizeof(Guint));
        for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
          img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
              img.tiles[tileIdx].tileComps[0].quantSteps[j];
@@ -1379,9 +1501,9 @@ GBool JPXStream::readTilePart() {
        img.tiles[tileIdx].tileComps[comp].nQuantSteps =
            segLen - (img.nComps > 256 ? 5 : 4);
        img.tiles[tileIdx].tileComps[comp].quantSteps =
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-                             img.tiles[tileIdx].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+                              img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
          if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
            error(getPos(), "Error in JPX QCC marker segment");
@@ -1392,9 +1514,9 @@ GBool JPXStream::readTilePart() {
                 == 0x01) {
        img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
        img.tiles[tileIdx].tileComps[comp].quantSteps =
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-                             img.tiles[tileIdx].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+                              img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
          error(getPos(), "Error in JPX QCC marker segment");
          return gFalse;
@@ -1404,9 +1526,9 @@ GBool JPXStream::readTilePart() {
        img.tiles[tileIdx].tileComps[comp].nQuantSteps =
            (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
        img.tiles[tileIdx].tileComps[comp].quantSteps =
-           (Guint *)grealloc(img.tiles[tileIdx].tileComps[comp].quantSteps,
-                             img.tiles[tileIdx].tileComps[comp].nQuantSteps *
-                               sizeof(Guint));
+           (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+                              img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+                              sizeof(Guint));
        for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
          if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
            error(getPos(), "Error in JPX QCD marker segment");
@@ -1449,7 +1571,7 @@ GBool JPXStream::readTilePart() {
       }
 #else
       nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
-      tileProgs = (JPXProgOrder *)gmalloc(nTileProgs * sizeof(JPXProgOrder));
+      tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
       for (i = 0; i < nTileProgs; ++i) {
        if (!readUByte(&tileProgs[i].startRes) ||
            !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
@@ -1541,15 +1663,15 @@ GBool JPXStream::readTilePart() {
       tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
       tileComp->cbW = 1 << tileComp->codeBlockW;
       tileComp->cbH = 1 << tileComp->codeBlockH;
-      tileComp->data = (int *)gmalloc((tileComp->x1 - tileComp->x0) *
-                                     (tileComp->y1 - tileComp->y0) *
-                                     sizeof(int));
+      tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
+                                      (tileComp->y1 - tileComp->y0),
+                                      sizeof(int));
       if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
        n = tileComp->x1 - tileComp->x0;
       } else {
        n = tileComp->y1 - tileComp->y0;
       }
-      tileComp->buf = (int *)gmalloc((n + 8) * sizeof(int));
+      tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
       for (r = 0; r <= tileComp->nDecompLevels; ++r) {
        resLevel = &tileComp->resLevels[r];
        k = r == 0 ? tileComp->nDecompLevels
@@ -1577,7 +1699,7 @@ GBool JPXStream::readTilePart() {
          resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
          resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
        }
-       resLevel->precincts = (JPXPrecinct *)gmalloc(1 * sizeof(JPXPrecinct));
+       resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
        for (pre = 0; pre < 1; ++pre) {
          precinct = &resLevel->precincts[pre];
          precinct->x0 = resLevel->x0;
@@ -1586,7 +1708,7 @@ GBool JPXStream::readTilePart() {
          precinct->y1 = resLevel->y1;
          nSBs = r == 0 ? 1 : 3;
          precinct->subbands =
-             (JPXSubband *)gmalloc(nSBs * sizeof(JPXSubband));
+             (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
          for (sb = 0; sb < nSBs; ++sb) {
            subband = &precinct->subbands[sb];
            subband->x0 = resLevel->bx0[sb];
@@ -1613,18 +1735,18 @@ GBool JPXStream::readTilePart() {
              n += nx * ny;
            }
            subband->inclusion =
-               (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
+               (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
            subband->zeroBitPlane =
-               (JPXTagTreeNode *)gmalloc(n * sizeof(JPXTagTreeNode));
+               (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
            for (k = 0; k < n; ++k) {
              subband->inclusion[k].finished = gFalse;
              subband->inclusion[k].val = 0;
              subband->zeroBitPlane[k].finished = gFalse;
              subband->zeroBitPlane[k].val = 0;
            }
-           subband->cbs = (JPXCodeBlock *)gmalloc(subband->nXCBs *
-                                                  subband->nYCBs *
-                                                  sizeof(JPXCodeBlock));
+           subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
+                                                     subband->nYCBs,
+                                                   sizeof(JPXCodeBlock));
            sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
            sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
            cb = subband->cbs;
@@ -1651,9 +1773,9 @@ GBool JPXStream::readTilePart() {
                cb->nextPass = jpxPassCleanup;
                cb->nZeroBitPlanes = 0;
                cb->coeffs =
-                   (JPXCoeff *)gmalloc((1 << (tileComp->codeBlockW
-                                              + tileComp->codeBlockH))
-                                       * sizeof(JPXCoeff));
+                   (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW
+                                               + tileComp->codeBlockH)),
+                                        sizeof(JPXCoeff));
                for (cbi = 0;
                     cbi < (Guint)(1 << (tileComp->codeBlockW
                                         + tileComp->codeBlockH));
@@ -1662,10 +1784,8 @@ GBool JPXStream::readTilePart() {
                  cb->coeffs[cbi].len = 0;
                  cb->coeffs[cbi].mag = 0;
                }
-               cb->stats = new JArithmeticDecoderStats(jpxNContexts);
-               cb->stats->setEntry(jpxContextSigProp, 4, 0);
-               cb->stats->setEntry(jpxContextRunLength, 3, 0);
-               cb->stats->setEntry(jpxContextUniform, 46, 0);
+               cb->arithDecoder = NULL;
+               cb->stats = NULL;
                ++cb;
              }
            }
@@ -1963,14 +2083,21 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                                   Guint res, Guint sb,
                                   JPXCodeBlock *cb) {
   JPXCoeff *coeff0, *coeff1, *coeff;
-  JArithmeticDecoder *arithDecoder;
   Guint horiz, vert, diag, all, cx, xorBit;
   int horizSign, vertSign;
   Guint i, x, y0, y1, y2;
 
-  arithDecoder = new JArithmeticDecoder();
-  arithDecoder->setStream(str, cb->dataLen);
-  arithDecoder->start();
+  if (cb->arithDecoder) {
+    cb->arithDecoder->restart(cb->dataLen);
+  } else {
+    cb->arithDecoder = new JArithmeticDecoder();
+    cb->arithDecoder->setStream(str, cb->dataLen);
+    cb->arithDecoder->start();
+    cb->stats = new JArithmeticDecoderStats(jpxNContexts);
+    cb->stats->setEntry(jpxContextSigProp, 4, 0);
+    cb->stats->setEntry(jpxContextRunLength, 3, 0);
+    cb->stats->setEntry(jpxContextUniform, 46, 0);
+  }
 
   for (i = 0; i < cb->nCodingPasses; ++i) {
     switch (cb->nextPass) {
@@ -1995,7 +2122,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                  horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
                }
                if (y0+y1 > cb->y0) {
-                 diag += (coeff[-tileComp->cbW - 1].flags
+                 diag += (coeff[-(int)tileComp->cbW - 1].flags
                           >> jpxCoeffSignificantB) & 1;
                }
                if (y0+y1 < cb->y1 - 1) {
@@ -2009,7 +2136,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                  horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
                }
                if (y0+y1 > cb->y0) {
-                 diag += (coeff[-tileComp->cbW + 1].flags
+                 diag += (coeff[-(int)tileComp->cbW + 1].flags
                           >> jpxCoeffSignificantB) & 1;
                }
                if (y0+y1 < cb->y1 - 1) {
@@ -2018,9 +2145,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                }
              }
              if (y0+y1 > cb->y0) {
-               if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
+               if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
                  ++vert;
-                 vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
+                 vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
                              ? -1 : 1;
                }
              }
@@ -2033,12 +2160,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
              }
              cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
              if (cx != 0) {
-               if (arithDecoder->decodeBit(cx, cb->stats)) {
+               if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
                  coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
                  coeff->mag = (coeff->mag << 1) | 1;
                  cx = signContext[horizSign][vertSign][0];
                  xorBit = signContext[horizSign][vertSign][1];
-                 if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+                 if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
                    coeff->flags |= jpxCoeffSign;
                  }
                }
@@ -2070,7 +2197,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                if (x > cb->x0) {
                  all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
                  if (y0+y1 > cb->y0) {
-                   all += (coeff[-tileComp->cbW - 1].flags
+                   all += (coeff[-(int)tileComp->cbW - 1].flags
                            >> jpxCoeffSignificantB) & 1;
                  }
                  if (y0+y1 < cb->y1 - 1) {
@@ -2081,7 +2208,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                if (x < cb->x1 - 1) {
                  all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
                  if (y0+y1 > cb->y0) {
-                   all += (coeff[-tileComp->cbW + 1].flags
+                   all += (coeff[-(int)tileComp->cbW + 1].flags
                            >> jpxCoeffSignificantB) & 1;
                  }
                  if (y0+y1 < cb->y1 - 1) {
@@ -2090,7 +2217,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                  }
                }
                if (y0+y1 > cb->y0) {
-                 all += (coeff[-tileComp->cbW].flags
+                 all += (coeff[-(int)tileComp->cbW].flags
                          >> jpxCoeffSignificantB) & 1;
                }
                if (y0+y1 < cb->y1 - 1) {
@@ -2102,7 +2229,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                cx = 16;
              }
              coeff->mag = (coeff->mag << 1) |
-                          arithDecoder->decodeBit(cx, cb->stats);
+                          cb->arithDecoder->decodeBit(cx, cb->stats);
              ++coeff->len;
              coeff->flags |= jpxCoeffTouched;
              coeff->flags &= ~jpxCoeffFirstMagRef;
@@ -2128,12 +2255,14 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
              !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
              !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
              (x == cb->x0 || y0 == cb->y0 ||
-              !(coeff1[-tileComp->cbW - 1].flags
+              !(coeff1[-(int)tileComp->cbW - 1].flags
                 & jpxCoeffSignificant)) &&
              (y0 == cb->y0 ||
-              !(coeff1[-tileComp->cbW].flags & jpxCoeffSignificant)) &&
+              !(coeff1[-(int)tileComp->cbW].flags
+                & jpxCoeffSignificant)) &&
              (x == cb->x1 - 1 || y0 == cb->y0 ||
-              !(coeff1[-tileComp->cbW + 1].flags & jpxCoeffSignificant)) &&
+              !(coeff1[-(int)tileComp->cbW + 1].flags
+                & jpxCoeffSignificant)) &&
              (x == cb->x0 ||
               (!(coeff1[-1].flags & jpxCoeffSignificant) &&
                !(coeff1[tileComp->cbW - 1].flags
@@ -2157,10 +2286,10 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
              (x == cb->x1 - 1 || y0+4 == cb->y1 ||
               !(coeff1[4 * tileComp->cbW + 1].flags
                 & jpxCoeffSignificant))) {
-           if (arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
-             y1 = arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+           if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
+             y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
              y1 = (y1 << 1) |
-                  arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+                  cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
              for (y2 = 0, coeff = coeff1;
                   y2 < y1;
                   ++y2, coeff += tileComp->cbW) {
@@ -2171,7 +2300,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
              ++coeff->len;
              cx = signContext[2][2][0];
              xorBit = signContext[2][2][1];
-             if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+             if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
                coeff->flags |= jpxCoeffSign;
              }
              ++y1;
@@ -2196,7 +2325,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                  horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
                }
                if (y0+y1 > cb->y0) {
-                 diag += (coeff[-tileComp->cbW - 1].flags
+                 diag += (coeff[-(int)tileComp->cbW - 1].flags
                           >> jpxCoeffSignificantB) & 1;
                }
                if (y0+y1 < cb->y1 - 1) {
@@ -2210,7 +2339,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                  horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
                }
                if (y0+y1 > cb->y0) {
-                 diag += (coeff[-tileComp->cbW + 1].flags
+                 diag += (coeff[-(int)tileComp->cbW + 1].flags
                           >> jpxCoeffSignificantB) & 1;
                }
                if (y0+y1 < cb->y1 - 1) {
@@ -2219,9 +2348,9 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                }
              }
              if (y0+y1 > cb->y0) {
-               if (coeff[-tileComp->cbW].flags & jpxCoeffSignificant) {
+               if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
                  ++vert;
-                 vertSign += (coeff[-tileComp->cbW].flags & jpxCoeffSign)
+                 vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
                              ? -1 : 1;
                }
              }
@@ -2233,12 +2362,12 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
                }
              }
              cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
-             if (arithDecoder->decodeBit(cx, cb->stats)) {
+             if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
                coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
                coeff->mag = (coeff->mag << 1) | 1;
                cx = signContext[horizSign][vertSign][0];
                xorBit = signContext[horizSign][vertSign][1];
-               if (arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+               if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
                  coeff->flags |= jpxCoeffSign;
                }
              }
@@ -2254,7 +2383,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
     }
   }
 
-  delete arithDecoder;
+  cb->arithDecoder->cleanup();
   return gTrue;
 }
 
@@ -2266,7 +2395,8 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) {
   JPXSubband *subband;
   JPXCodeBlock *cb;
   JPXCoeff *coeff0, *coeff;
-  Guint qStyle, guard, eps, shift, shift2;
+  Guint qStyle, guard, eps, shift;
+  int shift2;
   double mu;
   int val;
   int *dataPtr;
@@ -2368,7 +2498,8 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
   JPXSubband *subband;
   JPXCodeBlock *cb;
   JPXCoeff *coeff0, *coeff;
-  Guint qStyle, guard, eps, shift, shift2, t;
+  Guint qStyle, guard, eps, shift, t;
+  int shift2;
   double mu;
   int val;
   int *dataPtr;
@@ -2578,7 +2709,7 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp,
 // converts fixed point samples back to integers.
 GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
   JPXTileComp *tileComp;
-  int coeff, d0, d1, d2, minVal, maxVal, zeroVal;
+  int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
   int *dataPtr;
   Guint j, comp, x, y;
 
@@ -2617,9 +2748,9 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
          d0 = tile->tileComps[0].data[j];
          d1 = tile->tileComps[1].data[j];
          d2 = tile->tileComps[2].data[j];
-         tile->tileComps[0].data[j] = d0 - ((d2 + d1) >> 2);
-         tile->tileComps[1].data[j] = d2 - d1;
-         tile->tileComps[2].data[j] = d0 - d1;
+         tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
+         tile->tileComps[0].data[j] = d2 + t;
+         tile->tileComps[2].data[j] = d1 + t;
          ++j;
        }
       }