]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/JBIG2Stream.cc
Do real thumbnailing of PDF files. It's slow, but I'll speed it up next!
[evince.git] / pdf / xpdf / JBIG2Stream.cc
index 716fee1cabff4aa80fc0697c523320762793fa13..c1bf4f78d0433bd9133e35d6a317de6824be1f0f 100644 (file)
@@ -2,7 +2,7 @@
 //
 // JBIG2Stream.cc
 //
 //
 // JBIG2Stream.cc
 //
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
 //
 //========================================================================
 
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include "GList.h"
 #include "Error.h"
 #include <stdlib.h>
 #include "GList.h"
 #include "Error.h"
+#include "JArithmeticDecoder.h"
 #include "JBIG2Stream.h"
 
 //~ share these tables
 #include "JBIG2Stream.h"
 
 //~ share these tables
 static int contextSize[4] = { 16, 13, 10, 10 };
 static int refContextSize[2] = { 13, 10 };
 
 static int contextSize[4] = { 16, 13, 10, 10 };
 static int refContextSize[2] = { 13, 10 };
 
-//------------------------------------------------------------------------
-// JBIG2ArithmeticDecoderStats
-//------------------------------------------------------------------------
-
-class JBIG2ArithmeticDecoderStats {
-public:
-
-  JBIG2ArithmeticDecoderStats(int contextSizeA);
-  ~JBIG2ArithmeticDecoderStats();
-  JBIG2ArithmeticDecoderStats *copy();
-  void reset();
-  int getContextSize() { return contextSize; }
-  void copyFrom(JBIG2ArithmeticDecoderStats *stats);
-
-private:
-
-  Guchar *cxTab;               // cxTab[cx] = (i[cx] << 1) + mps[cx]
-  int contextSize;
-
-  friend class JBIG2ArithmeticDecoder;
-};
-
-JBIG2ArithmeticDecoderStats::JBIG2ArithmeticDecoderStats(int contextSizeA) {
-  contextSize = contextSizeA;
-  cxTab = (Guchar *)gmalloc((1 << contextSize) * sizeof(Guchar));
-  reset();
-}
-
-JBIG2ArithmeticDecoderStats::~JBIG2ArithmeticDecoderStats() {
-  gfree(cxTab);
-}
-
-JBIG2ArithmeticDecoderStats *JBIG2ArithmeticDecoderStats::copy() {
-  JBIG2ArithmeticDecoderStats *stats;
-
-  stats = new JBIG2ArithmeticDecoderStats(contextSize);
-  memcpy(stats->cxTab, cxTab, 1 << contextSize);
-  return stats;
-}
-
-void JBIG2ArithmeticDecoderStats::reset() {
-  memset(cxTab, 0, 1 << contextSize);
-}
-
-void JBIG2ArithmeticDecoderStats::copyFrom(
-                                     JBIG2ArithmeticDecoderStats *stats) {
-  memcpy(cxTab, stats->cxTab, 1 << contextSize);
-}
-
-//------------------------------------------------------------------------
-// JBIG2ArithmeticDecoder
-//------------------------------------------------------------------------
-
-class JBIG2ArithmeticDecoder {
-public:
-
-  JBIG2ArithmeticDecoder();
-  ~JBIG2ArithmeticDecoder();
-  void setStream(Stream *strA) { str = strA; }
-  void start();
-  int decodeBit(Guint context, JBIG2ArithmeticDecoderStats *stats);
-  int decodeByte(Guint context, JBIG2ArithmeticDecoderStats *stats);
-
-  // Returns false for OOB, otherwise sets *<x> and returns true.
-  GBool decodeInt(int *x, JBIG2ArithmeticDecoderStats *stats);
-
-  Guint decodeIAID(Guint codeLen,
-                  JBIG2ArithmeticDecoderStats *stats);
-
-private:
-
-  int decodeIntBit(JBIG2ArithmeticDecoderStats *stats);
-  void byteIn();
-
-  static Guint qeTab[47];
-  static int nmpsTab[47];
-  static int nlpsTab[47];
-  static int switchTab[47];
-
-  Guint buf0, buf1;
-  Guint c, a;
-  int ct;
-
-  Guint prev;                  // for the integer decoder
-
-  Stream *str;
-};
-
-Guint JBIG2ArithmeticDecoder::qeTab[47] = {
-  0x56010000, 0x34010000, 0x18010000, 0x0AC10000,
-  0x05210000, 0x02210000, 0x56010000, 0x54010000,
-  0x48010000, 0x38010000, 0x30010000, 0x24010000,
-  0x1C010000, 0x16010000, 0x56010000, 0x54010000,
-  0x51010000, 0x48010000, 0x38010000, 0x34010000,
-  0x30010000, 0x28010000, 0x24010000, 0x22010000,
-  0x1C010000, 0x18010000, 0x16010000, 0x14010000,
-  0x12010000, 0x11010000, 0x0AC10000, 0x09C10000,
-  0x08A10000, 0x05210000, 0x04410000, 0x02A10000,
-  0x02210000, 0x01410000, 0x01110000, 0x00850000,
-  0x00490000, 0x00250000, 0x00150000, 0x00090000,
-  0x00050000, 0x00010000, 0x56010000
-};
-
-int JBIG2ArithmeticDecoder::nmpsTab[47] = {
-   1,  2,  3,  4,  5, 38,  7,  8,  9, 10, 11, 12, 13, 29, 15, 16,
-  17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
-  33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46
-};
-
-int JBIG2ArithmeticDecoder::nlpsTab[47] = {
-   1,  6,  9, 12, 29, 33,  6, 14, 14, 14, 17, 18, 20, 21, 14, 14,
-  15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
-  30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46
-};
-
-int JBIG2ArithmeticDecoder::switchTab[47] = {
-  1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-JBIG2ArithmeticDecoder::JBIG2ArithmeticDecoder() {
-  str = NULL;
-}
-
-JBIG2ArithmeticDecoder::~JBIG2ArithmeticDecoder() {
-}
-
-void JBIG2ArithmeticDecoder::start() {
-  buf0 = (Guint)str->getChar() & 0xff;
-  buf1 = (Guint)str->getChar() & 0xff;
-
-  // INITDEC
-  c = (buf0 ^ 0xff) << 16;
-  byteIn();
-  c <<= 7;
-  ct -= 7;
-  a = 0x80000000;
-}
-
-int JBIG2ArithmeticDecoder::decodeBit(Guint context,
-                                     JBIG2ArithmeticDecoderStats *stats) {
-  int bit;
-  Guint qe;
-  int iCX, mpsCX;
-
-  iCX = stats->cxTab[context] >> 1;
-  mpsCX = stats->cxTab[context] & 1;
-  qe = qeTab[iCX];
-  a -= qe;
-  if (c < a) {
-    if (a & 0x80000000) {
-      bit = mpsCX;
-    } else {
-      // MPS_EXCHANGE
-      if (a < qe) {
-       bit = 1 - mpsCX;
-       if (switchTab[iCX]) {
-         stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX);
-       } else {
-         stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX;
-       }
-      } else {
-       bit = mpsCX;
-       stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX;
-      }
-      // RENORMD
-      do {
-       if (ct == 0) {
-         byteIn();
-       }
-       a <<= 1;
-       c <<= 1;
-       --ct;
-      } while (!(a & 0x80000000));
-    }
-  } else {
-    c -= a;
-    // LPS_EXCHANGE
-    if (a < qe) {
-      bit = mpsCX;
-      stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX;
-    } else {
-      bit = 1 - mpsCX;
-      if (switchTab[iCX]) {
-       stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX);
-      } else {
-       stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX;
-      }
-    }
-    a = qe;
-    // RENORMD
-    do {
-      if (ct == 0) {
-       byteIn();
-      }
-      a <<= 1;
-      c <<= 1;
-      --ct;
-    } while (!(a & 0x80000000));
-  }
-  return bit;
-}
-
-int JBIG2ArithmeticDecoder::decodeByte(Guint context,
-                                      JBIG2ArithmeticDecoderStats *stats) {
-  int byte;
-  int i;
-
-  byte = 0;
-  for (i = 0; i < 8; ++i) {
-    byte = (byte << 1) | decodeBit(context, stats);
-  }
-  return byte;
-}
-
-GBool JBIG2ArithmeticDecoder::decodeInt(int *x,
-                                       JBIG2ArithmeticDecoderStats *stats) {
-  int s;
-  Guint v;
-  int i;
-
-  prev = 1;
-  s = decodeIntBit(stats);
-  if (decodeIntBit(stats)) {
-    if (decodeIntBit(stats)) {
-      if (decodeIntBit(stats)) {
-       if (decodeIntBit(stats)) {
-         if (decodeIntBit(stats)) {
-           v = 0;
-           for (i = 0; i < 32; ++i) {
-             v = (v << 1) | decodeIntBit(stats);
-           }
-           v += 4436;
-         } else {
-           v = 0;
-           for (i = 0; i < 12; ++i) {
-             v = (v << 1) | decodeIntBit(stats);
-           }
-           v += 340;
-         }
-       } else {
-         v = 0;
-         for (i = 0; i < 8; ++i) {
-           v = (v << 1) | decodeIntBit(stats);
-         }
-         v += 84;
-       }
-      } else {
-       v = 0;
-       for (i = 0; i < 6; ++i) {
-         v = (v << 1) | decodeIntBit(stats);
-       }
-       v += 20;
-      }
-    } else {
-      v = decodeIntBit(stats);
-      v = (v << 1) | decodeIntBit(stats);
-      v = (v << 1) | decodeIntBit(stats);
-      v = (v << 1) | decodeIntBit(stats);
-      v += 4;
-    }
-  } else {
-    v = decodeIntBit(stats);
-    v = (v << 1) | decodeIntBit(stats);
-  }
-
-  if (s) {
-    if (v == 0) {
-      return gFalse;
-    }
-    *x = -(int)v;
-  } else {
-    *x = (int)v;
-  }
-  return gTrue;
-}
-
-int JBIG2ArithmeticDecoder::decodeIntBit(JBIG2ArithmeticDecoderStats *stats) {
-  int bit;
-
-  bit = decodeBit(prev, stats);
-  if (prev < 0x100) {
-    prev = (prev << 1) | bit;
-  } else {
-    prev = (((prev << 1) | bit) & 0x1ff) | 0x100;
-  }
-  return bit;
-}
-
-Guint JBIG2ArithmeticDecoder::decodeIAID(Guint codeLen,
-                                        JBIG2ArithmeticDecoderStats *stats) {
-  Guint i;
-  int bit;
-
-  prev = 1;
-  for (i = 0; i < codeLen; ++i) {
-    bit = decodeBit(prev, stats);
-    prev = (prev << 1) | bit;
-  }
-  return prev - (1 << codeLen);
-}
-
-void JBIG2ArithmeticDecoder::byteIn() {
-  if (buf0 == 0xff) {
-    if (buf1 > 0x8f) {
-      ct = 8;
-    } else {
-      buf0 = buf1;
-      buf1 = (Guint)str->getChar() & 0xff;
-      c = c + 0xfe00 - (buf0 << 9);
-      ct = 7;
-    }
-  } else {
-    buf0 = buf1;
-    buf1 = (Guint)str->getChar() & 0xff;
-    c = c + 0xff00 - (buf0 << 8);
-    ct = 8;
-  }
-}
-
 //------------------------------------------------------------------------
 // JBIG2HuffmanTable
 //------------------------------------------------------------------------
 //------------------------------------------------------------------------
 // JBIG2HuffmanTable
 //------------------------------------------------------------------------
@@ -655,25 +335,22 @@ GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) {
   len = 0;
   prefix = 0;
   while (table[i].rangeLen != jbig2HuffmanEOT) {
   len = 0;
   prefix = 0;
   while (table[i].rangeLen != jbig2HuffmanEOT) {
-    //~ if buildTable removes the entries with prefixLen=0, this is unneeded
-    if (table[i].prefixLen > 0) {
-      while (len < table[i].prefixLen) {
-       prefix = (prefix << 1) | readBit();
-       ++len;
+    while (len < table[i].prefixLen) {
+      prefix = (prefix << 1) | readBit();
+      ++len;
+    }
+    if (prefix == table[i].prefix) {
+      if (table[i].rangeLen == jbig2HuffmanOOB) {
+       return gFalse;
       }
       }
-      if (prefix == table[i].prefix) {
-       if (table[i].rangeLen == jbig2HuffmanOOB) {
-         return gFalse;
-       }
-       if (table[i].rangeLen == jbig2HuffmanLOW) {
-         *x = table[i].val - readBits(32);
-       } else if (table[i].rangeLen > 0) {
-         *x = table[i].val + readBits(table[i].rangeLen);
-       } else {
-         *x = table[i].val;
-       }
-       return gTrue;
+      if (table[i].rangeLen == jbig2HuffmanLOW) {
+       *x = table[i].val - readBits(32);
+      } else if (table[i].rangeLen > 0) {
+       *x = table[i].val + readBits(table[i].rangeLen);
+      } else {
+       *x = table[i].val;
       }
       }
+      return gTrue;
     }
     ++i;
   }
     }
     ++i;
   }
@@ -713,22 +390,41 @@ Guint JBIG2HuffmanDecoder::readBit() {
   return (buf >> bufLen) & 1;
 }
 
   return (buf >> bufLen) & 1;
 }
 
-static int cmpHuffmanTabEntries(const void *p1, const void *p2) {
-  return ((JBIG2HuffmanTable *)p1)->prefixLen
-         - ((JBIG2HuffmanTable *)p2)->prefixLen;
-}
-
-//~ should remove entries with prefixLen = 0
 void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) {
 void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) {
-  Guint i, prefix;
-
-  qsort(table, len, sizeof(JBIG2HuffmanTable), &cmpHuffmanTabEntries);
-  for (i = 0; i < len && table[i].prefixLen == 0; ++i) {
-    table[i].prefix = 0;
+  Guint i, j, k, prefix;
+  JBIG2HuffmanTable tab;
+
+  // stable selection sort:
+  // - entries with prefixLen > 0, in ascending prefixLen order
+  // - entry with prefixLen = 0, rangeLen = EOT
+  // - all other entries with prefixLen = 0
+  // (on entry, table[len] has prefixLen = 0, rangeLen = EOT)
+  for (i = 0; i < len; ++i) {
+    for (j = i; j < len && table[j].prefixLen == 0; ++j) ;
+    if (j == len) {
+      break;
+    }
+    for (k = j + 1; k < len; ++k) {
+      if (table[k].prefixLen > 0 &&
+         table[k].prefixLen < table[j].prefixLen) {
+       j = k;
+      }
+    }
+    if (j != i) {
+      tab = table[j];
+      for (k = j; k > i; --k) {
+       table[k] = table[k - 1];
+      }
+      table[i] = tab;
+    }
   }
   }
+  table[i] = table[len];
+
+  // assign prefixes
+  i = 0;
   prefix = 0;
   table[i++].prefix = prefix++;
   prefix = 0;
   table[i++].prefix = prefix++;
-  for (; i < len; ++i) {
+  for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) {
     prefix <<= table[i].prefixLen - table[i-1].prefixLen;
     table[i].prefix = prefix++;
   }
     prefix <<= table[i].prefixLen - table[i-1].prefixLen;
     table[i].prefix = prefix++;
   }
@@ -810,7 +506,7 @@ int JBIG2MMRDecoder::getWhiteCode() {
     ++nBytesRead;
   }
   while (1) {
     ++nBytesRead;
   }
   while (1) {
-    if (bufLen > 7 && ((buf >> (bufLen - 7)) & 0x7f) == 0) {
+    if (bufLen >= 7 && ((buf >> (bufLen - 7)) & 0x7f) == 0) {
       if (bufLen <= 12) {
        code = buf << (12 - bufLen);
       } else {
       if (bufLen <= 12) {
        code = buf << (12 - bufLen);
       } else {
@@ -825,7 +521,7 @@ int JBIG2MMRDecoder::getWhiteCode() {
       }
       p = &whiteTab2[code & 0x1ff];
     }
       }
       p = &whiteTab2[code & 0x1ff];
     }
-    if (p->bits > 0 && p->bits < (int)bufLen) {
+    if (p->bits > 0 && p->bits <= (int)bufLen) {
       bufLen -= p->bits;
       return p->n;
     }
       bufLen -= p->bits;
       return p->n;
     }
@@ -853,14 +549,14 @@ int JBIG2MMRDecoder::getBlackCode() {
     ++nBytesRead;
   }
   while (1) {
     ++nBytesRead;
   }
   while (1) {
-    if (bufLen > 6 && ((buf >> (bufLen - 6)) & 0x3f) == 0) {
+    if (bufLen >= 6 && ((buf >> (bufLen - 6)) & 0x3f) == 0) {
       if (bufLen <= 13) {
        code = buf << (13 - bufLen);
       } else {
        code = buf >> (bufLen - 13);
       }
       p = &blackTab1[code & 0x7f];
       if (bufLen <= 13) {
        code = buf << (13 - bufLen);
       } else {
        code = buf >> (bufLen - 13);
       }
       p = &blackTab1[code & 0x7f];
-    } else if (bufLen > 4 && ((buf >> (bufLen - 4)) & 0x0f) == 0) {
+    } else if (bufLen >= 4 && ((buf >> (bufLen - 4)) & 0x0f) == 0) {
       if (bufLen <= 12) {
        code = buf << (12 - bufLen);
       } else {
       if (bufLen <= 12) {
        code = buf << (12 - bufLen);
       } else {
@@ -875,7 +571,7 @@ int JBIG2MMRDecoder::getBlackCode() {
       }
       p = &blackTab3[code & 0x3f];
     }
       }
       p = &blackTab3[code & 0x3f];
     }
-    if (p->bits > 0 && p->bits < (int)bufLen) {
+    if (p->bits > 0 && p->bits <= (int)bufLen) {
       bufLen -= p->bits;
       return p->n;
     }
       bufLen -= p->bits;
       return p->n;
     }
@@ -938,6 +634,12 @@ private:
 // JBIG2Bitmap
 //------------------------------------------------------------------------
 
 // JBIG2Bitmap
 //------------------------------------------------------------------------
 
+struct JBIG2BitmapPtr {
+  Guchar *p;
+  int shift;
+  int x;
+};
+
 class JBIG2Bitmap: public JBIG2Segment {
 public:
 
 class JBIG2Bitmap: public JBIG2Segment {
 public:
 
@@ -958,6 +660,8 @@ public:
     { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); }
   void clearPixel(int x, int y)
     { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); }
     { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); }
   void clearPixel(int x, int y)
     { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); }
+  void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr);
+  int nextPixel(JBIG2BitmapPtr *ptr);
   void duplicateRow(int yDest, int ySrc);
   void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp);
   Guchar *getDataPtr() { return data; }
   void duplicateRow(int yDest, int ySrc);
   void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp);
   Guchar *getDataPtr() { return data; }
@@ -1032,6 +736,42 @@ void JBIG2Bitmap::clearToOne() {
   memset(data, 0xff, h * line);
 }
 
   memset(data, 0xff, h * line);
 }
 
+inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) {
+  if (y < 0 || y >= h || x >= w) {
+    ptr->p = NULL;
+  } else if (x < 0) {
+    ptr->p = &data[y * line];
+    ptr->shift = 7;
+    ptr->x = x;
+  } else {
+    ptr->p = &data[y * line + (x >> 3)];
+    ptr->shift = 7 - (x & 7);
+    ptr->x = x;
+  }
+}
+
+inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) {
+  int pix;
+
+  if (!ptr->p) {
+    pix = 0;
+  } else if (ptr->x < 0) {
+    ++ptr->x;
+    pix = 0;
+  } else {
+    pix = (*ptr->p >> ptr->shift) & 1;
+    if (++ptr->x == w) {
+      ptr->p = NULL;
+    } else if (ptr->shift == 0) {
+      ++ptr->p;
+      ptr->shift = 7;
+    } else {
+      --ptr->shift;
+    }
+  }
+  return pix;
+}
+
 void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) {
   memcpy(data + yDest * line, data + ySrc * line, line);
 }
 void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) {
   memcpy(data + yDest * line, data + ySrc * line, line);
 }
@@ -1232,21 +972,21 @@ public:
   Guint getSize() { return size; }
   void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; }
   JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; }
   Guint getSize() { return size; }
   void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; }
   JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; }
-  void setGenericRegionStats(JBIG2ArithmeticDecoderStats *stats)
+  void setGenericRegionStats(JArithmeticDecoderStats *stats)
     { genericRegionStats = stats; }
     { genericRegionStats = stats; }
-  void setRefinementRegionStats(JBIG2ArithmeticDecoderStats *stats)
+  void setRefinementRegionStats(JArithmeticDecoderStats *stats)
     { refinementRegionStats = stats; }
     { refinementRegionStats = stats; }
-  JBIG2ArithmeticDecoderStats *getGenericRegionStats()
+  JArithmeticDecoderStats *getGenericRegionStats()
     { return genericRegionStats; }
     { return genericRegionStats; }
-  JBIG2ArithmeticDecoderStats *getRefinementRegionStats()
+  JArithmeticDecoderStats *getRefinementRegionStats()
     { return refinementRegionStats; }
 
 private:
 
   Guint size;
   JBIG2Bitmap **bitmaps;
     { return refinementRegionStats; }
 
 private:
 
   Guint size;
   JBIG2Bitmap **bitmaps;
-  JBIG2ArithmeticDecoderStats *genericRegionStats;
-  JBIG2ArithmeticDecoderStats *refinementRegionStats;
+  JArithmeticDecoderStats *genericRegionStats;
+  JArithmeticDecoderStats *refinementRegionStats;
 };
 
 JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA):
 };
 
 JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA):
@@ -1345,27 +1085,27 @@ JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream):
 {
   pageBitmap = NULL;
 
 {
   pageBitmap = NULL;
 
-  arithDecoder = new JBIG2ArithmeticDecoder();
-  genericRegionStats = new JBIG2ArithmeticDecoderStats(1);
-  refinementRegionStats = new JBIG2ArithmeticDecoderStats(1);
-  iadhStats = new JBIG2ArithmeticDecoderStats(9);
-  iadwStats = new JBIG2ArithmeticDecoderStats(9);
-  iaexStats = new JBIG2ArithmeticDecoderStats(9);
-  iaaiStats = new JBIG2ArithmeticDecoderStats(9);
-  iadtStats = new JBIG2ArithmeticDecoderStats(9);
-  iaitStats = new JBIG2ArithmeticDecoderStats(9);
-  iafsStats = new JBIG2ArithmeticDecoderStats(9);
-  iadsStats = new JBIG2ArithmeticDecoderStats(9);
-  iardxStats = new JBIG2ArithmeticDecoderStats(9);
-  iardyStats = new JBIG2ArithmeticDecoderStats(9);
-  iardwStats = new JBIG2ArithmeticDecoderStats(9);
-  iardhStats = new JBIG2ArithmeticDecoderStats(9);
-  iariStats = new JBIG2ArithmeticDecoderStats(9);
-  iaidStats = new JBIG2ArithmeticDecoderStats(1);
+  arithDecoder = new JArithmeticDecoder();
+  genericRegionStats = new JArithmeticDecoderStats(1 << 1);
+  refinementRegionStats = new JArithmeticDecoderStats(1 << 1);
+  iadhStats = new JArithmeticDecoderStats(1 << 9);
+  iadwStats = new JArithmeticDecoderStats(1 << 9);
+  iaexStats = new JArithmeticDecoderStats(1 << 9);
+  iaaiStats = new JArithmeticDecoderStats(1 << 9);
+  iadtStats = new JArithmeticDecoderStats(1 << 9);
+  iaitStats = new JArithmeticDecoderStats(1 << 9);
+  iafsStats = new JArithmeticDecoderStats(1 << 9);
+  iadsStats = new JArithmeticDecoderStats(1 << 9);
+  iardxStats = new JArithmeticDecoderStats(1 << 9);
+  iardyStats = new JArithmeticDecoderStats(1 << 9);
+  iardwStats = new JArithmeticDecoderStats(1 << 9);
+  iardhStats = new JArithmeticDecoderStats(1 << 9);
+  iariStats = new JArithmeticDecoderStats(1 << 9);
+  iaidStats = new JArithmeticDecoderStats(1 << 1);
   huffDecoder = new JBIG2HuffmanDecoder();
   mmrDecoder = new JBIG2MMRDecoder();
 
   huffDecoder = new JBIG2HuffmanDecoder();
   mmrDecoder = new JBIG2MMRDecoder();
 
-  segments = new GList();
+  segments = globalSegments = new GList();
   if (globalsStream->isStream()) {
     curStr = globalsStream->getStream();
     curStr->reset();
   if (globalsStream->isStream()) {
     curStr = globalsStream->getStream();
     curStr->reset();
@@ -1374,7 +1114,6 @@ JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream):
     mmrDecoder->setStream(curStr);
     readSegments();
   }
     mmrDecoder->setStream(curStr);
     readSegments();
   }
-  globalSegments = segments;
 
   segments = NULL;
   curStr = NULL;
 
   segments = NULL;
   curStr = NULL;
@@ -1452,7 +1191,7 @@ int JBIG2Stream::lookChar() {
   return EOF;
 }
 
   return EOF;
 }
 
-GString *JBIG2Stream::getPSFilter(char *indent) {
+GString *JBIG2Stream::getPSFilter(int psLevel, char *indent) {
   return NULL;
 }
 
   return NULL;
 }
 
@@ -1768,20 +1507,23 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
   } else {
     if (contextUsed && inputSymbolDict) {
       resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats());
   } else {
     if (contextUsed && inputSymbolDict) {
       resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats());
-      if (refAgg) {
-       resetRefinementStats(sdrTemplate,
-                            inputSymbolDict->getRefinementRegionStats());
-      }
     } else {
       resetGenericStats(sdTemplate, NULL);
     } else {
       resetGenericStats(sdTemplate, NULL);
-      if (refAgg) {
-       resetRefinementStats(sdrTemplate, NULL);
-      }
     }
     resetIntStats(symCodeLen);
     arithDecoder->start();
   }
 
     }
     resetIntStats(symCodeLen);
     arithDecoder->start();
   }
 
+  // set up the arithmetic decoder for refinement/aggregation
+  if (refAgg) {
+    if (contextUsed && inputSymbolDict) {
+      resetRefinementStats(sdrTemplate,
+                          inputSymbolDict->getRefinementRegionStats());
+    } else {
+      resetRefinementStats(sdrTemplate, NULL);
+    }
+  }
+
   // allocate symbol widths storage
   symWidths = NULL;
   if (huff && !refAgg) {
   // allocate symbol widths storage
   symWidths = NULL;
   if (huff && !refAgg) {
@@ -1834,7 +1576,13 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
            break;
          }
        }
            break;
          }
        }
+#if 0 //~ This special case was added about a year before the final draft
+      //~ of the JBIG2 spec was released.  I have encountered some old
+      //~ JBIG2 images that predate it.
+       if (0) {
+#else
        if (refAggNum == 1) {
        if (refAggNum == 1) {
+#endif
          if (huff) {
            symID = huffDecoder->readBits(symCodeLen);
            huffDecoder->decodeInt(&refDX, huffTableO);
          if (huff) {
            symID = huffDecoder->readBits(symCodeLen);
            huffDecoder->decodeInt(&refDX, huffTableO);
@@ -1878,15 +1626,13 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     // read the collective bitmap
     if (huff && !refAgg) {
       huffDecoder->decodeInt(&bmSize, huffBMSizeTable);
     // read the collective bitmap
     if (huff && !refAgg) {
       huffDecoder->decodeInt(&bmSize, huffBMSizeTable);
-      if (huff) {
-       huffDecoder->reset();
-      }
+      huffDecoder->reset();
       if (bmSize == 0) {
        collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight);
        bmSize = symHeight * ((totalWidth + 7) >> 3);
        p = collBitmap->getDataPtr();
        for (k = 0; k < (Guint)bmSize; ++k) {
       if (bmSize == 0) {
        collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight);
        bmSize = symHeight * ((totalWidth + 7) >> 3);
        p = collBitmap->getDataPtr();
        for (k = 0; k < (Guint)bmSize; ++k) {
-         *p++ = str->getChar();
+         *p++ = curStr->getChar();
        }
       } else {
        collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight,
        }
       } else {
        collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight,
@@ -1924,7 +1670,7 @@ void JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length,
     }
     ex = !ex;
   }
     }
     ex = !ex;
   }
-  
+
   for (i = 0; i < numNewSyms; ++i) {
     delete bitmaps[numInputSyms + i];
   }
   for (i = 0; i < numNewSyms; ++i) {
     delete bitmaps[numInputSyms + i];
   }
@@ -1965,7 +1711,8 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
   JBIG2Bitmap **syms;
   Guint w, h, x, y, segInfoFlags, extCombOp;
   Guint flags, huff, refine, logStrips, refCorner, transposed;
   JBIG2Bitmap **syms;
   Guint w, h, x, y, segInfoFlags, extCombOp;
   Guint flags, huff, refine, logStrips, refCorner, transposed;
-  Guint combOp, defPixel, sOffset, templ;
+  Guint combOp, defPixel, templ;
+  int sOffset;
   Guint huffFlags, huffFS, huffDS, huffDT;
   Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize;
   Guint numInstances, numSyms, symCodeLen;
   Guint huffFlags, huffFS, huffDS, huffDT;
   Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize;
   Guint numInstances, numSyms, symCodeLen;
@@ -1993,6 +1740,9 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
   combOp = (flags >> 7) & 3;
   defPixel = (flags >> 9) & 1;
   sOffset = (flags >> 10) & 0x1f;
   combOp = (flags >> 7) & 3;
   defPixel = (flags >> 9) & 1;
   sOffset = (flags >> 10) & 0x1f;
+  if (sOffset & 0x10) {
+    sOffset |= -1 - 0x0f;
+  }
   templ = (flags >> 15) & 1;
   huffFS = huffDS = huffDT = 0; // make gcc happy
   huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy
   templ = (flags >> 15) & 1;
   huffFS = huffDS = huffDT = 0; // make gcc happy
   huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy
@@ -2135,6 +1885,7 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
     runLengthTab[34].val = 0x20b;
     runLengthTab[34].prefixLen = huffDecoder->readBits(4);
     runLengthTab[34].rangeLen = 7;
     runLengthTab[34].val = 0x20b;
     runLengthTab[34].prefixLen = huffDecoder->readBits(4);
     runLengthTab[34].rangeLen = 7;
+    runLengthTab[35].prefixLen = 0;
     runLengthTab[35].rangeLen = jbig2HuffmanEOT;
     huffDecoder->buildTable(runLengthTab, 35);
     symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) *
     runLengthTab[35].rangeLen = jbig2HuffmanEOT;
     huffDecoder->buildTable(runLengthTab, 35);
     symCodeTab = (JBIG2HuffmanTable *)gmalloc((numSyms + 1) *
@@ -2158,8 +1909,8 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
       } else {
        symCodeTab[i++].prefixLen = j;
       }
       } else {
        symCodeTab[i++].prefixLen = j;
       }
-
     }
     }
+    symCodeTab[numSyms].prefixLen = 0;
     symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT;
     huffDecoder->buildTable(symCodeTab, numSyms);
     huffDecoder->reset();
     symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT;
     huffDecoder->buildTable(symCodeTab, numSyms);
     huffDecoder->reset();
@@ -2168,11 +1919,11 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
   } else {
     symCodeTab = NULL;
     resetIntStats(symCodeLen);
   } else {
     symCodeTab = NULL;
     resetIntStats(symCodeLen);
-    if (refine) {
-      resetRefinementStats(templ, NULL);
-    }
     arithDecoder->start();
   }
     arithDecoder->start();
   }
+  if (refine) {
+    resetRefinementStats(templ, NULL);
+  }
 
   bitmap = readTextRegion(huff, refine, w, h, numInstances,
                          logStrips, numSyms, symCodeTab, symCodeLen, syms,
 
   bitmap = readTextRegion(huff, refine, w, h, numInstances,
                          logStrips, numSyms, symCodeTab, symCodeLen, syms,
@@ -2219,7 +1970,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
                                         JBIG2Bitmap **syms,
                                         Guint defPixel, Guint combOp,
                                         Guint transposed, Guint refCorner,
                                         JBIG2Bitmap **syms,
                                         Guint defPixel, Guint combOp,
                                         Guint transposed, Guint refCorner,
-                                        Guint sOffset,
+                                        int sOffset,
                                         JBIG2HuffmanTable *huffFSTable,
                                         JBIG2HuffmanTable *huffDSTable,
                                         JBIG2HuffmanTable *huffDTTable,
                                         JBIG2HuffmanTable *huffFSTable,
                                         JBIG2HuffmanTable *huffDSTable,
                                         JBIG2HuffmanTable *huffDTTable,
@@ -2253,7 +2004,7 @@ JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
   } else {
     arithDecoder->decodeInt(&t, iadtStats);
   }
   } else {
     arithDecoder->decodeInt(&t, iadtStats);
   }
-  t *= -strips;
+  t *= -(int)strips;
 
   inst = 0;
   sFirst = 0;
 
   inst = 0;
   sFirst = 0;
@@ -2426,10 +2177,10 @@ void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) {
   }
 
   // read the bitmap
   }
 
   // read the bitmap
-  atx[0] = -patternW; aty[0] =  0;
-  atx[1] = -3;        aty[1] = -1;
-  atx[2] =  2;        aty[2] = -2;
-  atx[3] = -2;        aty[3] = -2;
+  atx[0] = -(int)patternW; aty[0] =  0;
+  atx[1] = -3;             aty[1] = -1;
+  atx[2] =  2;             aty[2] = -2;
+  atx[3] = -2;             aty[3] = -2;
   bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH,
                             templ, gFalse, gFalse, NULL,
                             atx, aty, length - 7);
   bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH,
                             templ, gFalse, gFalse, NULL,
                             atx, aty, length - 7);
@@ -2686,6 +2437,8 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
   JBIG2Bitmap *bitmap;
   GBool ltp;
   Guint ltpCX, cx, cx0, cx1, cx2;
   JBIG2Bitmap *bitmap;
   GBool ltp;
   Guint ltpCX, cx, cx0, cx1, cx2;
+  JBIG2BitmapPtr cxPtr0, cxPtr1;
+  JBIG2BitmapPtr atPtr0, atPtr1, atPtr2, atPtr3;
   int *refLine, *codingLine;
   int code1, code2, code3;
   int x, y, a0, pix, i, refI, codingI;
   int *refLine, *codingLine;
   int code1, code2, code3;
   int x, y, a0, pix, i, refI, codingI;
@@ -2743,10 +2496,12 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
              code2 += code3 = mmrDecoder->getBlackCode();
            } while (code3 >= 64);
          }
              code2 += code3 = mmrDecoder->getBlackCode();
            } while (code3 >= 64);
          }
-         a0 = codingLine[codingI++] = a0 + code1;
-         a0 = codingLine[codingI++] = a0 + code2;
-         while (refLine[refI] <= a0 && refLine[refI] < w) {
-           refI += 2;
+         if (code1 > 0 || code2 > 0) {
+           a0 = codingLine[codingI++] = a0 + code1;
+           a0 = codingLine[codingI++] = a0 + code2;
+           while (refLine[refI] <= a0 && refLine[refI] < w) {
+             refI += 2;
+           }
          }
          break;
        case twoDimVert0:
          }
          break;
        case twoDimVert0:
@@ -2880,99 +2635,151 @@ JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
        }
       }
 
        }
       }
 
-      // set up the context
       switch (templ) {
       case 0:
       switch (templ) {
       case 0:
-       cx0 = (bitmap->getPixel(0, y-2) << 1) |
-             bitmap->getPixel(1, y-2);
-       cx1 = (bitmap->getPixel(0, y-1) << 2) |
-             (bitmap->getPixel(1, y-1) << 1) |
-             bitmap->getPixel(2, y-1);
+
+       // set up the context
+       bitmap->getPixelPtr(0, y-2, &cxPtr0);
+       cx0 = bitmap->nextPixel(&cxPtr0);
+       cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+       bitmap->getPixelPtr(0, y-1, &cxPtr1);
+       cx1 = bitmap->nextPixel(&cxPtr1);
+       cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+       cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
        cx2 = 0;
        cx2 = 0;
+       bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+       bitmap->getPixelPtr(atx[1], y + aty[1], &atPtr1);
+       bitmap->getPixelPtr(atx[2], y + aty[2], &atPtr2);
+       bitmap->getPixelPtr(atx[3], y + aty[3], &atPtr3);
+
+       // decode the row
+       for (x = 0; x < w; ++x) {
+
+         // build the context
+         cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) |
+              (bitmap->nextPixel(&atPtr0) << 3) |
+              (bitmap->nextPixel(&atPtr1) << 2) |
+              (bitmap->nextPixel(&atPtr2) << 1) |
+              bitmap->nextPixel(&atPtr3);
+
+         // check for a skipped pixel
+         if (useSkip && skip->getPixel(x, y)) {
+           pix = 0;
+
+         // decode the pixel
+         } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+           bitmap->setPixel(x, y);
+         }
+
+         // update the context
+         cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07;
+         cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f;
+         cx2 = ((cx2 << 1) | pix) & 0x0f;
+       }
        break;
        break;
+
       case 1:
       case 1:
-       cx0 = (bitmap->getPixel(0, y-2) << 2) |
-             (bitmap->getPixel(1, y-2) << 1) |
-             bitmap->getPixel(2, y-2);
-       cx1 = (bitmap->getPixel(0, y-1) << 2) |
-             (bitmap->getPixel(1, y-1) << 1) |
-             bitmap->getPixel(2, y-1);
+
+       // set up the context
+       bitmap->getPixelPtr(0, y-2, &cxPtr0);
+       cx0 = bitmap->nextPixel(&cxPtr0);
+       cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+       cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+       bitmap->getPixelPtr(0, y-1, &cxPtr1);
+       cx1 = bitmap->nextPixel(&cxPtr1);
+       cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+       cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
        cx2 = 0;
        cx2 = 0;
+       bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+
+       // decode the row
+       for (x = 0; x < w; ++x) {
+
+         // build the context
+         cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) |
+              bitmap->nextPixel(&atPtr0);
+
+         // check for a skipped pixel
+         if (useSkip && skip->getPixel(x, y)) {
+           pix = 0;
+
+         // decode the pixel
+         } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+           bitmap->setPixel(x, y);
+         }
+
+         // update the context
+         cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x0f;
+         cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f;
+         cx2 = ((cx2 << 1) | pix) & 0x07;
+       }
        break;
        break;
+
       case 2:
       case 2:
-       cx0 = (bitmap->getPixel(0, y-2) << 1) |
-             bitmap->getPixel(1, y-2);
-       cx1 = (bitmap->getPixel(0, y-1) << 1) |
-             bitmap->getPixel(1, y-1);
-       cx2 = 0;
-       break;
-      case 3:
-       cx1 = (bitmap->getPixel(0, y-1) << 1) |
-             bitmap->getPixel(1, y-1);
+
+       // set up the context
+       bitmap->getPixelPtr(0, y-2, &cxPtr0);
+       cx0 = bitmap->nextPixel(&cxPtr0);
+       cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+       bitmap->getPixelPtr(0, y-1, &cxPtr1);
+       cx1 = bitmap->nextPixel(&cxPtr1);
+       cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
        cx2 = 0;
        cx2 = 0;
+       bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+
+       // decode the row
+       for (x = 0; x < w; ++x) {
+
+         // build the context
+         cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) |
+              bitmap->nextPixel(&atPtr0);
+
+         // check for a skipped pixel
+         if (useSkip && skip->getPixel(x, y)) {
+           pix = 0;
+
+         // decode the pixel
+         } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+           bitmap->setPixel(x, y);
+         }
+
+         // update the context
+         cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07;
+         cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x0f;
+         cx2 = ((cx2 << 1) | pix) & 0x03;
+       }
        break;
        break;
-      }
 
 
-      // decode the row
-      for (x = 0; x < w; ++x) {
+      case 3:
 
 
-       // check for a skipped pixel
-       if (useSkip && skip->getPixel(x, y)) {
-         pix = 0;
+       // set up the context
+       bitmap->getPixelPtr(0, y-1, &cxPtr1);
+       cx1 = bitmap->nextPixel(&cxPtr1);
+       cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+       cx2 = 0;
+       bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
 
 
-       } else {
+       // decode the row
+       for (x = 0; x < w; ++x) {
 
          // build the context
 
          // build the context
-         switch (templ) {
-         case 0:
-           cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) |
-                (bitmap->getPixel(x + atx[0], y + aty[0]) << 3) |
-                (bitmap->getPixel(x + atx[1], y + aty[1]) << 2) |
-                (bitmap->getPixel(x + atx[2], y + aty[2]) << 1) |
-                bitmap->getPixel(x + atx[3], y + aty[3]);
-           break;
-         case 1:
-           cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) |
-                bitmap->getPixel(x + atx[0], y + aty[0]);
-           break;
-         case 2:
-           cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) |
-                bitmap->getPixel(x + atx[0], y + aty[0]);
-           break;
-         case 3:
-           cx = (cx1 << 5) | (cx2 << 1) |
-                bitmap->getPixel(x + atx[0], y + aty[0]);
-           break;
-         }
+         cx = (cx1 << 5) | (cx2 << 1) |
+              bitmap->nextPixel(&atPtr0);
+
+         // check for a skipped pixel
+         if (useSkip && skip->getPixel(x, y)) {
+           pix = 0;
 
          // decode the pixel
 
          // decode the pixel
-         if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+         } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
            bitmap->setPixel(x, y);
          }
            bitmap->setPixel(x, y);
          }
-       }
 
 
-       // update the context
-       switch (templ) {
-         case 0:
-           cx0 = ((cx0 << 1) | bitmap->getPixel(x+2, y-2)) & 0x07;
-           cx1 = ((cx1 << 1) | bitmap->getPixel(x+3, y-1)) & 0x1f;
-           cx2 = ((cx2 << 1) | pix) & 0x0f;
-           break;
-         case 1:
-           cx0 = ((cx0 << 1) | bitmap->getPixel(x+3, y-2)) & 0x0f;
-           cx1 = ((cx1 << 1) | bitmap->getPixel(x+3, y-1)) & 0x1f;
-           cx2 = ((cx2 << 1) | pix) & 0x07;
-           break;
-         case 2:
-           cx0 = ((cx0 << 1) | bitmap->getPixel(x+2, y-2)) & 0x07;
-           cx1 = ((cx1 << 1) | bitmap->getPixel(x+2, y-1)) & 0x0f;
-           cx2 = ((cx2 << 1) | pix) & 0x03;
-           break;
-         case 3:
-           cx1 = ((cx1 << 1) | bitmap->getPixel(x+2, y-1)) & 0x1f;
-           cx2 = ((cx2 << 1) | pix) & 0x0f;
-           break;
+         // update the context
+         cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f;
+         cx2 = ((cx2 << 1) | pix) & 0x0f;
        }
        }
+       break;
       }
     }
   }
       }
     }
   }
@@ -3076,6 +2883,8 @@ JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
   JBIG2Bitmap *bitmap;
   GBool ltp;
   Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2;
   JBIG2Bitmap *bitmap;
   GBool ltp;
   Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2;
+  JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6;
+  JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2;
   int x, y, pix;
 
   bitmap = new JBIG2Bitmap(0, w, h);
   int x, y, pix;
 
   bitmap = new JBIG2Bitmap(0, w, h);
@@ -3091,87 +2900,144 @@ JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
   ltp = 0;
   for (y = 0; y < h; ++y) {
 
   ltp = 0;
   for (y = 0; y < h; ++y) {
 
-    // set up the context
     if (templ) {
     if (templ) {
-      cx0 = bitmap->getPixel(0, y-1);
-      cx2 = 0; // unused
-      cx3 = (refBitmap->getPixel(-1-refDX, y-refDY) << 1) |
-           refBitmap->getPixel(-refDX, y-refDY);
-      cx4 = refBitmap->getPixel(-refDX, y+1-refDY);
-    } else {
-      cx0 = bitmap->getPixel(0, y-1);
-      cx2 = refBitmap->getPixel(-refDX, y-1-refDY);
-      cx3 = (refBitmap->getPixel(-1-refDX, y-refDY) << 1) |
-           refBitmap->getPixel(-refDX, y-refDY);
-      cx4 = (refBitmap->getPixel(-1-refDX, y+1-refDY) << 1) |
-           refBitmap->getPixel(-refDX, y+1-refDY);
-    }
-
-    // set up the typical prediction context
-    tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
-    if (tpgrOn) {
-      tpgrCX0 = (refBitmap->getPixel(-1-refDX, y-1-refDY) << 2) |
-               (refBitmap->getPixel(-refDX, y-1-refDY) << 1) |
-               refBitmap->getPixel(1-refDX, y-1-refDY);
-      tpgrCX1 = (refBitmap->getPixel(-1-refDX, y-refDY) << 2) |
-               (refBitmap->getPixel(-refDX, y-refDY) << 1) |
-               refBitmap->getPixel(1-refDX, y-refDY);
-      tpgrCX2 = (refBitmap->getPixel(-1-refDX, y+1-refDY) << 2) |
-               (refBitmap->getPixel(-refDX, y+1-refDY) << 1) |
-               refBitmap->getPixel(1-refDX, y+1-refDY);
-    }
-
-    for (x = 0; x < w; ++x) {
-
-      // update the context
-      if (templ) {
-       cx0 = ((cx0 << 1) | bitmap->getPixel(x+1, y-1)) & 7;
-       cx3 = ((cx3 << 1) | refBitmap->getPixel(x+1-refDX, y-refDY)) & 7;
-       cx4 = ((cx4 << 1) | refBitmap->getPixel(x+1-refDX, y+1-refDY)) & 3;
-      } else {
-       cx0 = ((cx0 << 1) | bitmap->getPixel(x+1, y-1)) & 3;
-       cx2 = ((cx2 << 1) | refBitmap->getPixel(x+1-refDX, y-1-refDY)) & 3;
-       cx3 = ((cx3 << 1) | refBitmap->getPixel(x+1-refDX, y-refDY)) & 7;
-       cx4 = ((cx4 << 1) | refBitmap->getPixel(x+1-refDX, y+1-refDY)) & 7;
-      }
 
 
+      // set up the context
+      bitmap->getPixelPtr(0, y-1, &cxPtr0);
+      cx0 = bitmap->nextPixel(&cxPtr0);
+      bitmap->getPixelPtr(-1, y, &cxPtr1);
+      refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2);
+      refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3);
+      cx3 = refBitmap->nextPixel(&cxPtr3);
+      cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3);
+      refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4);
+      cx4 = refBitmap->nextPixel(&cxPtr4);
+
+      // set up the typical prediction context
+      tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
       if (tpgrOn) {
       if (tpgrOn) {
-       // update the typical predictor context
-       tpgrCX0 = ((tpgrCX0 << 1) |
-                  refBitmap->getPixel(x+1-refDX, y-1-refDY)) & 7;
-       tpgrCX1 = ((tpgrCX1 << 1) |
-                  refBitmap->getPixel(x+1-refDX, y-refDY)) & 7;
-       tpgrCX2 = ((tpgrCX2 << 1) |
-                  refBitmap->getPixel(x+1-refDX, y+1-refDY)) & 7;
-
-       // check for a "typical" pixel
-       if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
-         ltp = !ltp;
+       refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0);
+       tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0);
+       tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+       tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+       refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1);
+       tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1);
+       tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+       tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+       refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2);
+       tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
+       tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+       tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+      }
+
+      for (x = 0; x < w; ++x) {
+
+       // update the context
+       cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7;
+       cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7;
+       cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3;
+
+       if (tpgrOn) {
+         // update the typical predictor context
+         tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7;
+         tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7;
+         tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7;
+
+         // check for a "typical" pixel
+         if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
+           ltp = !ltp;
+         }
+         if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
+           bitmap->clearPixel(x, y);
+           continue;
+         } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+           bitmap->setPixel(x, y);
+           continue;
+         }
        }
        }
-       if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
-         bitmap->clearPixel(x, y);
-         continue;
-       } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+
+       // build the context
+       cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) |
+            (refBitmap->nextPixel(&cxPtr2) << 5) |
+            (cx3 << 2) | cx4;
+
+       // decode the pixel
+       if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
          bitmap->setPixel(x, y);
          bitmap->setPixel(x, y);
-         continue;
        }
       }
 
        }
       }
 
-      // build the context
-      if (templ) {
-       cx = (cx0 << 7) | (bitmap->getPixel(x-1, y) << 6) |
-            (refBitmap->getPixel(x-refDX, y-1-refDY) << 5) |
-            (cx3 << 2) | cx4;
-      } else {
-       cx = (cx0 << 11) | (bitmap->getPixel(x-1, y) << 10) |
-            (cx2 << 8) | (cx3 << 5) | (cx4 << 2) |
-            (bitmap->getPixel(x+atx[0], y+aty[0]) << 1) |
-            refBitmap->getPixel(x+atx[1]-refDX, y+aty[1]-refDY);
+    } else {
+
+      // set up the context
+      bitmap->getPixelPtr(0, y-1, &cxPtr0);
+      cx0 = bitmap->nextPixel(&cxPtr0);
+      bitmap->getPixelPtr(-1, y, &cxPtr1);
+      refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2);
+      cx2 = refBitmap->nextPixel(&cxPtr2);
+      refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3);
+      cx3 = refBitmap->nextPixel(&cxPtr3);
+      cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3);
+      refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4);
+      cx4 = refBitmap->nextPixel(&cxPtr4);
+      cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4);
+      bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5);
+      refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6);
+
+      // set up the typical prediction context
+      tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
+      if (tpgrOn) {
+       refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0);
+       tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0);
+       tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+       tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+       refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1);
+       tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1);
+       tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+       tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+       refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2);
+       tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
+       tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+       tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
       }
 
       }
 
-      // decode the pixel
-      if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
-       bitmap->setPixel(x, y);
+      for (x = 0; x < w; ++x) {
+
+       // update the context
+       cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3;
+       cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3;
+       cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7;
+       cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7;
+
+       if (tpgrOn) {
+         // update the typical predictor context
+         tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7;
+         tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7;
+         tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7;
+
+         // check for a "typical" pixel
+         if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
+           ltp = !ltp;
+         }
+         if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
+           bitmap->clearPixel(x, y);
+           continue;
+         } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+           bitmap->setPixel(x, y);
+           continue;
+         }
+       }
+
+       // build the context
+       cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) |
+            (cx2 << 8) | (cx3 << 5) | (cx4 << 2) |
+            (bitmap->nextPixel(&cxPtr5) << 1) |
+            refBitmap->nextPixel(&cxPtr6);
+
+       // decode the pixel
+       if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
+         bitmap->setPixel(x, y);
+       }
       }
     }
   }
       }
     }
   }
@@ -3239,8 +3105,8 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) {
     goto eofError;
   }
   oob = flags & 1;
     goto eofError;
   }
   oob = flags & 1;
-  prefixBits = (flags >> 1) & 7;
-  rangeBits = (flags >> 4) & 7;
+  prefixBits = ((flags >> 1) & 7) + 1;
+  rangeBits = ((flags >> 4) & 7) + 1;
 
   huffDecoder->reset();
   huffTabSize = 8;
 
   huffDecoder->reset();
   huffTabSize = 8;
@@ -3282,7 +3148,6 @@ void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) {
   huffTab[i].val = 0;
   huffTab[i].prefixLen = 0;
   huffTab[i].rangeLen = jbig2HuffmanEOT;
   huffTab[i].val = 0;
   huffTab[i].prefixLen = 0;
   huffTab[i].rangeLen = jbig2HuffmanEOT;
-  ++i;
   huffDecoder->buildTable(huffTab, i);
 
   // create and store the new table segment
   huffDecoder->buildTable(huffTab, i);
 
   // create and store the new table segment
@@ -3336,14 +3201,14 @@ void JBIG2Stream::discardSegment(Guint segNum) {
   for (i = 0; i < segments->getLength(); ++i) {
     seg = (JBIG2Segment *)segments->get(i);
     if (seg->getSegNum() == segNum) {
   for (i = 0; i < segments->getLength(); ++i) {
     seg = (JBIG2Segment *)segments->get(i);
     if (seg->getSegNum() == segNum) {
-      globalSegments->del(i);
+      segments->del(i);
       return;
     }
   }
 }
 
 void JBIG2Stream::resetGenericStats(Guint templ,
       return;
     }
   }
 }
 
 void JBIG2Stream::resetGenericStats(Guint templ,
-                                   JBIG2ArithmeticDecoderStats *prevStats) {
+                                   JArithmeticDecoderStats *prevStats) {
   int size;
 
   size = contextSize[templ];
   int size;
 
   size = contextSize[templ];
@@ -3359,14 +3224,13 @@ void JBIG2Stream::resetGenericStats(Guint templ,
       genericRegionStats->reset();
     } else {
       delete genericRegionStats;
       genericRegionStats->reset();
     } else {
       delete genericRegionStats;
-      genericRegionStats = new JBIG2ArithmeticDecoderStats(size);
+      genericRegionStats = new JArithmeticDecoderStats(1 << size);
     }
   }
 }
 
     }
   }
 }
 
-void JBIG2Stream::resetRefinementStats(
-                     Guint templ,
-                     JBIG2ArithmeticDecoderStats *prevStats) {
+void JBIG2Stream::resetRefinementStats(Guint templ,
+                                      JArithmeticDecoderStats *prevStats) {
   int size;
 
   size = refContextSize[templ];
   int size;
 
   size = refContextSize[templ];
@@ -3382,7 +3246,7 @@ void JBIG2Stream::resetRefinementStats(
       refinementRegionStats->reset();
     } else {
       delete refinementRegionStats;
       refinementRegionStats->reset();
     } else {
       delete refinementRegionStats;
-      refinementRegionStats = new JBIG2ArithmeticDecoderStats(size);
+      refinementRegionStats = new JArithmeticDecoderStats(1 << size);
     }
   }
 }
     }
   }
 }
@@ -3405,7 +3269,7 @@ void JBIG2Stream::resetIntStats(int symCodeLen) {
     iaidStats->reset();
   } else {
     delete iaidStats;
     iaidStats->reset();
   } else {
     delete iaidStats;
-    iaidStats = new JBIG2ArithmeticDecoderStats(symCodeLen + 1);
+    iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1));
   }
 }
 
   }
 }
 
@@ -3467,7 +3331,7 @@ GBool JBIG2Stream::readLong(int *x) {
   }
   *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
   if (c0 & 0x80) {
   }
   *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
   if (c0 & 0x80) {
-    *x |= -1 - 0xffffffff;
+    *x |= -1 - (int)0xffffffff;
   }
   return gTrue;
 }
   }
   return gTrue;
 }