]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/Stream.cc
change (disabled) font embedding code
[evince.git] / pdf / xpdf / Stream.cc
index 6e52d791c5a6d0c8f1c9fe7a2091f943204bbb28..9777940da3b70a4dcea3d15092a4857a189cd8f4 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Stream.cc
 //
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2002 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -10,6 +10,7 @@
 #pragma implementation
 #endif
 
+#include <aconf.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <string.h>
 #include <ctype.h>
 #include "gmem.h"
+#include "gfile.h"
 #include "config.h"
 #include "Error.h"
 #include "Object.h"
+#ifndef NO_DECRYPTION
+#include "Decrypt.h"
+#endif
 #include "Stream.h"
 #include "Stream-CCITT.h"
 
-#ifdef _MSC_VER
-#define popen _popen
-#define pclose _pclose
-#endif
-
 #ifdef __DJGPP__
 static GBool setDJSYSFLAGS = gFalse;
 #endif
@@ -45,10 +45,9 @@ extern "C" int unlink(char *filename);
 #endif
 #endif
 
-//------------------------------------------------------------------------
-
-#define headerSearchSize 1024  // read this many bytes at beginning of
-                               //   file to look for '%PDF'
+#ifdef MACOS
+#include "StuffItEngineLib.h"
+#endif
 
 //------------------------------------------------------------------------
 // Stream (base class)
@@ -61,6 +60,9 @@ Stream::Stream() {
 Stream::~Stream() {
 }
 
+void Stream::close() {
+}
+
 int Stream::getRawChar() {
   error(-1, "Internal: called getRawChar() on non-predictor stream");
   return EOF;
@@ -87,10 +89,6 @@ char *Stream::getLine(char *buf, int size) {
   return buf;
 }
 
-void Stream::setPos(int pos) {
-  error(-1, "Internal: called setPos() on non-FileStream");
-}
-
 GString *Stream::getPSFilter(char *indent) {
   return new GString();
 }
@@ -264,17 +262,62 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
   return str;
 }
 
+//------------------------------------------------------------------------
+// BaseStream
+//------------------------------------------------------------------------
+
+BaseStream::BaseStream(Object *dictA) {
+  dict = *dictA;
+#ifndef NO_DECRYPTION
+  decrypt = NULL;
+#endif
+}
+
+BaseStream::~BaseStream() {
+  dict.free();
+#ifndef NO_DECRYPTION
+  if (decrypt)
+    delete decrypt;
+#endif
+}
+
+#ifndef NO_DECRYPTION
+void BaseStream::doDecryption(Guchar *fileKey, int keyLength,
+                             int objNum, int objGen) {
+  decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
+}
+#endif
+
+//------------------------------------------------------------------------
+// FilterStream
+//------------------------------------------------------------------------
+
+FilterStream::FilterStream(Stream *strA) {
+  str = strA;
+}
+
+FilterStream::~FilterStream() {
+}
+
+void FilterStream::close() {
+  str->close();
+}
+
+void FilterStream::setPos(Guint pos, int dir) {
+  error(-1, "Internal: called setPos() on FilterStream");
+}
+
 //------------------------------------------------------------------------
 // ImageStream
 //------------------------------------------------------------------------
 
-ImageStream::ImageStream(Stream *str, int width, int nComps, int nBits) {
+ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) {
   int imgLineSize;
 
-  this->str = str;
-  this->width = width;
-  this->nComps = nComps;
-  this->nBits = nBits;
+  str = strA;
+  width = widthA;
+  nComps = nCompsA;
+  nBits = nBitsA;
 
   nVals = width * nComps;
   if (nBits == 1) {
@@ -355,13 +398,13 @@ void ImageStream::skipLine() {
 // StreamPredictor
 //------------------------------------------------------------------------
 
-StreamPredictor::StreamPredictor(Stream *str, int predictor,
-                                int width, int nComps, int nBits) {
-  this->str = str;
-  this->predictor = predictor;
-  this->width = width;
-  this->nComps = nComps;
-  this->nBits = nBits;
+StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
+                                int widthA, int nCompsA, int nBitsA) {
+  str = strA;
+  predictor = predictorA;
+  width = widthA;
+  nComps = nCompsA;
+  nBits = nBitsA;
 
   nVals = width * nComps;
   pixBytes = (nComps * nBits + 7) >> 3;
@@ -445,11 +488,11 @@ GBool StreamPredictor::getNextLine() {
       if ((pc = p - upLeft) < 0)
        pc = -pc;
       if (pa <= pb && pa <= pc)
-       predLine[i] = pa + (Guchar)c;
+       predLine[i] = left + (Guchar)c;
       else if (pb <= pc)
-       predLine[i] = pb + (Guchar)c;
+       predLine[i] = up + (Guchar)c;
       else
-       predLine[i] = pc + (Guchar)c;
+       predLine[i] = upLeft + (Guchar)c;
       break;
     case 10:                   // PNG none
     default:                   // no predictor or TIFF predictor
@@ -511,112 +554,249 @@ GBool StreamPredictor::getNextLine() {
 // FileStream
 //------------------------------------------------------------------------
 
-FileStream::FileStream(BaseFile f1, int start1, int length1, Object *dict1) {
-  f = f1;
-  start = start1;
-  length = length1;
+FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA,
+                      Guint lengthA, Object *dictA):
+    BaseStream(dictA) {
+  f = fA;
+  start = startA;
+  limited = limitedA;
+  length = lengthA;
   bufPtr = bufEnd = buf;
   bufPos = start;
-  savePos = -1;
-  dict = *dict1;
+  savePos = 0;
+  saved = gFalse;
 }
 
 FileStream::~FileStream() {
-  if (savePos >= 0)
-    bfseek(f, savePos, SEEK_SET);
-  dict.free();
+  close();
+}
+
+Stream *FileStream::makeSubStream(Guint startA, GBool limitedA,
+                                 Guint lengthA, Object *dictA) {
+  return new FileStream(f, startA, limitedA, lengthA, dictA);
 }
 
 void FileStream::reset() {
-  savePos = (int)bftell(f);
-  bfseek(f, start, SEEK_SET);
+#if HAVE_FSEEK64
+  savePos = (Guint)ftell64(f);
+  fseek64(f, start, SEEK_SET);
+#else
+  savePos = (Guint)ftell(f);
+  fseek(f, start, SEEK_SET);
+#endif
+  saved = gTrue;
   bufPtr = bufEnd = buf;
   bufPos = start;
+#ifndef NO_DECRYPTION
+  if (decrypt)
+    decrypt->reset();
+#endif
+}
+
+void FileStream::close() {
+  if (saved) {
+#if HAVE_FSEEK64
+    fseek64(f, savePos, SEEK_SET);
+#else
+    fseek(f, savePos, SEEK_SET);
+#endif
+    saved = gFalse;
+  }
 }
 
 GBool FileStream::fillBuf() {
   int n;
+#ifndef NO_DECRYPTION
+  char *p;
+#endif
 
   bufPos += bufEnd - buf;
   bufPtr = bufEnd = buf;
-  if (length >= 0 && bufPos >= start + length)
+  if (limited && bufPos >= start + length) {
     return gFalse;
-  if (length >= 0 && bufPos + 256 > start + length)
+  }
+  if (limited && bufPos + fileStreamBufSize > start + length) {
     n = start + length - bufPos;
-  else
-    n = 256;
-  n = bfread(buf, 1, n, f);
+  } else {
+    n = fileStreamBufSize;
+  }
+  n = fread(buf, 1, n, f);
   bufEnd = buf + n;
-  if (bufPtr >= bufEnd)
+  if (bufPtr >= bufEnd) {
     return gFalse;
+  }
+#ifndef NO_DECRYPTION
+  if (decrypt) {
+    for (p = buf; p < bufEnd; ++p) {
+      *p = (char)decrypt->decryptByte((Guchar)*p);
+    }
+  }
+#endif
   return gTrue;
 }
 
-void FileStream::setPos(int pos1) {
-  long size;
+void FileStream::setPos(Guint pos, int dir) {
+  Guint size;
 
-  if (pos1 >= 0) {
-    bfseek(f, pos1, SEEK_SET);
-    bufPos = pos1;
+  if (dir >= 0) {
+#if HAVE_FSEEK64
+    fseek64(f, pos, SEEK_SET);
+#else
+    fseek(f, pos, SEEK_SET);
+#endif
+    bufPos = pos;
   } else {
-    bfseek(f, 0, SEEK_END);
-    size = bftell(f);
-    if (pos1 < -size)
-      pos1 = (int)(-size);
-    bfseek(f, pos1, SEEK_END);
-    bufPos = (int)bftell(f);
+#if HAVE_FSEEK64
+    fseek64(f, 0, SEEK_END);
+    size = (Guint)ftell64(f);
+#else
+    fseek(f, 0, SEEK_END);
+    size = (Guint)ftell(f);
+#endif
+    if (pos > size)
+      pos = (Guint)size;
+#ifdef __CYGWIN32__
+    //~ work around a bug in cygwin's implementation of fseek
+    rewind(f);
+#endif
+#if HAVE_FSEEK64
+    fseek64(f, -(int)pos, SEEK_END);
+    bufPos = (Guint)ftell64(f);
+#else
+    fseek(f, -(int)pos, SEEK_END);
+    bufPos = (Guint)ftell(f);
+#endif
   }
   bufPtr = bufEnd = buf;
 }
 
-GBool FileStream::checkHeader() {
-  char hdrBuf[headerSearchSize+1];
-  char *p;
-  double version;
-  int i;
+void FileStream::moveStart(int delta) {
+  start += delta;
+  bufPtr = bufEnd = buf;
+  bufPos = start;
+}
 
-  for (i = 0; i < headerSearchSize; ++i)
-    hdrBuf[i] = getChar();
-  hdrBuf[headerSearchSize] = '\0';
-  for (i = 0; i < headerSearchSize - 5; ++i) {
-    if (!strncmp(&hdrBuf[i], "%PDF-", 5))
-      break;
+//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA):
+    BaseStream(dictA) {
+  buf = bufA;
+  needFree = gFalse;
+  length = lengthA;
+  bufEnd = buf + length;
+  bufPtr = buf;
+}
+
+MemStream::~MemStream() {
+  if (needFree) {
+    gfree(buf);
   }
-  if (i >= headerSearchSize - 5) {
-    error(-1, "May not be a PDF file (continuing anyway)");
-    return gFalse;
+}
+
+Stream *MemStream::makeSubStream(Guint start, GBool limited,
+                                Guint lengthA, Object *dictA) {
+  Guint newLength;
+
+  if (!limited || start + lengthA > length) {
+    newLength = length - start;
+  } else {
+    newLength = lengthA;
   }
-  start += i;
-  p = strtok(&hdrBuf[i+5], " \t\n\r");
-  version = atof(p);
-  if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
-      version > pdfVersionNum + 0.0001) {
-    error(getPos(), "PDF version %s -- xpdf supports version %s"
-         " (continuing anyway)", p, pdfVersion);
-    return gFalse;
+  return new MemStream(buf + start, newLength, dictA);
+}
+
+void MemStream::reset() {
+  bufPtr = buf;
+#ifndef NO_DECRYPTION
+  if (decrypt) {
+    decrypt->reset();
   }
-  return gTrue;
+#endif
+}
+
+void MemStream::close() {
 }
 
+void MemStream::setPos(Guint pos, int dir) {
+  if (dir >= 0) {
+    if (pos > length) {
+      bufPtr = bufEnd;
+    } else {
+      bufPtr = buf + pos;
+    }
+  } else {
+    if (pos > length) {
+      bufPtr = buf;
+    } else {
+      bufPtr = bufEnd - pos;
+    }
+  }
+}
+
+void MemStream::moveStart(int delta) {
+  buf += delta;
+  bufPtr = buf;
+}
+
+#ifndef NO_DECRYPTION
+void MemStream::doDecryption(Guchar *fileKey, int keyLength,
+                            int objNum, int objGen) {
+  char *newBuf;
+  char *p, *q;
+
+  this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen);
+  if (decrypt) {
+    newBuf = (char *)gmalloc(bufEnd - buf);
+    for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) {
+      *q = (char)decrypt->decryptByte((Guchar)*p);
+    }
+    bufEnd = newBuf + (bufEnd - buf);
+    bufPtr = newBuf + (bufPtr - buf);
+    buf = newBuf;
+    needFree = gTrue;
+  }
+}
+#endif
+
 //------------------------------------------------------------------------
-// SubStream
+// EmbedStream
 //------------------------------------------------------------------------
 
-SubStream::SubStream(Stream *str1, Object *dict1) {
-  str = str1;
-  dict = *dict1;
+EmbedStream::EmbedStream(Stream *strA, Object *dictA):
+    BaseStream(dictA) {
+  str = strA;
 }
 
-SubStream::~SubStream() {
-  dict.free();
+EmbedStream::~EmbedStream() {
+}
+
+Stream *EmbedStream::makeSubStream(Guint start, GBool limited,
+                                  Guint length, Object *dictA) {
+  error(-1, "Internal: called makeSubStream() on EmbedStream");
+  return NULL;
+}
+
+void EmbedStream::setPos(Guint pos, int dir) {
+  error(-1, "Internal: called setPos() on EmbedStream");
+}
+
+Guint EmbedStream::getStart() {
+  error(-1, "Internal: called getStart() on EmbedStream");
+  return 0;
+}
+
+void EmbedStream::moveStart(int delta) {
+  error(-1, "Internal: called moveStart() on EmbedStream");
 }
 
 //------------------------------------------------------------------------
 // ASCIIHexStream
 //------------------------------------------------------------------------
 
-ASCIIHexStream::ASCIIHexStream(Stream *str1) {
-  str = str1;
+ASCIIHexStream::ASCIIHexStream(Stream *strA):
+    FilterStream(strA) {
   buf = EOF;
   eof = gFalse;
 }
@@ -687,7 +867,9 @@ int ASCIIHexStream::lookChar() {
 GString *ASCIIHexStream::getPSFilter(char *indent) {
   GString *s;
 
-  s = str->getPSFilter(indent);
+  if (!(s = str->getPSFilter(indent))) {
+    return NULL;
+  }
   s->append(indent)->append("/ASCIIHexDecode filter\n");
   return s;
 }
@@ -700,8 +882,8 @@ GBool ASCIIHexStream::isBinary(GBool last) {
 // ASCII85Stream
 //------------------------------------------------------------------------
 
-ASCII85Stream::ASCII85Stream(Stream *str1) {
-  str = str1;
+ASCII85Stream::ASCII85Stream(Stream *strA):
+    FilterStream(strA) {
   index = n = 0;
   eof = gFalse;
 }
@@ -763,7 +945,9 @@ int ASCII85Stream::lookChar() {
 GString *ASCII85Stream::getPSFilter(char *indent) {
   GString *s;
 
-  s = str->getPSFilter(indent);
+  if (!(s = str->getPSFilter(indent))) {
+    return NULL;
+  }
   s->append(indent)->append("/ASCII85Decode filter\n");
   return s;
 }
@@ -776,15 +960,15 @@ GBool ASCII85Stream::isBinary(GBool last) {
 // LZWStream
 //------------------------------------------------------------------------
 
-LZWStream::LZWStream(Stream *str1, int predictor1, int columns1, int colors1,
-                    int bits1, int early1) {
-  str = str1;
-  if (predictor1 != 1) {
-    pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1);
+LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors,
+                    int bits, int earlyA):
+    FilterStream(strA) {
+  if (predictor != 1) {
+    pred = new StreamPredictor(this, predictor, columns, colors, bits);
   } else {
     pred = NULL;
   }
-  early = early1;
+  early = earlyA;
   zPipe = NULL;
   bufPtr = bufEnd = buf;
 }
@@ -797,7 +981,8 @@ LZWStream::~LZWStream() {
     fclose(zPipe);
 #endif
     zPipe = NULL;
-    unlink(zName);
+    unlink(zName->getCString());
+    delete zName;
   }
   if (pred) {
     delete pred;
@@ -825,9 +1010,9 @@ int LZWStream::getRawChar() {
 
 void LZWStream::reset() {
   FILE *f;
+  GString *zCmd;
 
-  str->reset();
-  bufPtr = bufEnd = buf;
+  //----- close old LZW stream
   if (zPipe) {
 #ifdef HAVE_POPEN
     pclose(zPipe);
@@ -835,51 +1020,78 @@ void LZWStream::reset() {
     fclose(zPipe);
 #endif
     zPipe = NULL;
-    unlink(zName);
+    unlink(zName->getCString());
+    delete zName;
   }
+
+  //----- tell Delorie runtime to spawn a new instance of COMMAND.COM
+  //      to run gzip
 #if __DJGPP__
   if (!setDJSYSFLAGS) {
     setenv("DJSYSFLAGS", "0x0002", 0);
     setDJSYSFLAGS = gTrue;
   }
 #endif
-  strcpy(zCmd, uncompressCmd);
-  strcat(zCmd, " ");
-  zName = zCmd + strlen(zCmd);
-  tmpnam(zName);
-#ifdef _MSC_VER
-  zName[strlen(zName) - 2] = '\0';
-#endif
-  strcat(zName, ".Z");
-  if (!(f = fopen(zName, "wb"))) {
-    error(getPos(), "Couldn't open temporary file '%s'", zName);
+
+  //----- create the .Z file
+  if (!openTempFile(&zName, &f, "wb", ".Z")) {
+    error(getPos(), "Couldn't create temporary file for LZW stream");
     return;
   }
   dumpFile(f);
   fclose(f);
-#ifdef HAVE_POPEN
-  if (!(zPipe = popen(zCmd, "r"))) {
-    error(getPos(), "Couldn't popen '%s'", zCmd);
-    unlink(zName);
+
+  //----- execute uncompress / gzip
+  zCmd = new GString(uncompressCmd);
+  zCmd->append(' ');
+  zCmd->append(zName);
+#if defined(MACOS)
+  long magicCookie;
+  // first we open the engine up
+  OSErr err = OpenSITEngine(kUseExternalEngine, &magicCookie);
+  // if we found it - let's use it!
+  if (!err && magicCookie) {
+    // make sure we have the correct version of the Engine
+    if (GetSITEngineVersion(magicCookie) >= kFirstSupportedEngine) {
+      FSSpec myFSS;
+      Str255 pName;
+      strcpy((char *)pName, zName->getCString());
+      c2pstr((char *)pName);
+      FSMakeFSSpec(0, 0, pName, &myFSS);
+      short ftype = DetermineFileType(magicCookie, &myFSS);
+      OSErr expandErr = ExpandFSSpec(magicCookie, ftype, &myFSS,
+                                    NULL, NULL, kCreateFolderNever,
+                                    kDeleteOriginal, kTextConvertSmart);
+    }
+  }
+#elif defined(HAVE_POPEN)
+  if (!(zPipe = popen(zCmd->getCString(), POPEN_READ_MODE))) {
+    error(getPos(), "Couldn't popen '%s'", zCmd->getCString());
+    unlink(zName->getCString());
+    delete zName;
     return;
   }
-#else
-#ifdef VMS
-  if (!system(zCmd)) {
-#else
-  if (system(zCmd)) {
-#endif
-    error(getPos(), "Couldn't execute '%s'", zCmd);
-    unlink(zName);
+#else // HAVE_POPEN
+  if (!executeCommand(zCmd->getCString())) {
+    error(getPos(), "Couldn't execute '%s'", zCmd->getCString());
+    unlink(zName->getCString());
+    delete zName;
     return;
   }
-  zName[strlen(zName) - 2] = '\0';
-  if (!(zPipe = fopen(zName, "rb"))) {
-    error(getPos(), "Couldn't open uncompress file '%s'", zName);
-    unlink(zName);
+  zName->del(zName->getLength() - 2, 2);
+  if (!(zPipe = fopen(zName->getCString(), "rb"))) {
+    error(getPos(), "Couldn't open uncompress file '%s'", zName->getCString());
+    unlink(zName->getCString());
+    delete zName;
     return;
   }
-#endif
+#endif // HAVE_POPEN
+
+  //----- clean up
+  delete zCmd;
+
+  //----- initialize buffer
+  bufPtr = bufEnd = buf;
 }
 
 void LZWStream::dumpFile(FILE *f) {
@@ -894,6 +1106,8 @@ void LZWStream::dumpFile(FILE *f) {
   GBool first;                 // indicates first code word after clear
   int i, j;
 
+  str->reset();
+
   // magic number
   fputc(0x1f, f);
   fputc(0x9d, f);
@@ -1030,7 +1244,8 @@ GBool LZWStream::fillBuf() {
     fclose(zPipe);
 #endif
     zPipe = NULL;
-    unlink(zName);
+    unlink(zName->getCString());
+    delete zName;
   }
   bufPtr = buf;
   bufEnd = buf + n;
@@ -1043,7 +1258,9 @@ GString *LZWStream::getPSFilter(char *indent) {
   if (pred) {
     return NULL;
   }
-  s = str->getPSFilter(indent);
+  if (!(s = str->getPSFilter(indent))) {
+    return NULL;
+  }
   s->append(indent)->append("/LZWDecode filter\n");
   return s;
 }
@@ -1056,8 +1273,8 @@ GBool LZWStream::isBinary(GBool last) {
 // RunLengthStream
 //------------------------------------------------------------------------
 
-RunLengthStream::RunLengthStream(Stream *str1) {
-  str = str1;
+RunLengthStream::RunLengthStream(Stream *strA):
+    FilterStream(strA) {
   bufPtr = bufEnd = buf;
   eof = gFalse;
 }
@@ -1075,7 +1292,9 @@ void RunLengthStream::reset() {
 GString *RunLengthStream::getPSFilter(char *indent) {
   GString *s;
 
-  s = str->getPSFilter(indent);
+  if (!(s = str->getPSFilter(indent))) {
+    return NULL;
+  }
   s->append(indent)->append("/RunLengthDecode filter\n");
   return s;
 }
@@ -1114,18 +1333,18 @@ GBool RunLengthStream::fillBuf() {
 // CCITTFaxStream
 //------------------------------------------------------------------------
 
-CCITTFaxStream::CCITTFaxStream(Stream *str, int encoding, GBool endOfLine,
-                              GBool byteAlign, int columns, int rows,
-                              GBool endOfBlock, GBool black) {
-  this->str = str;
-  this->encoding = encoding;
-  this->endOfLine = endOfLine;
-  this->byteAlign = byteAlign;
-  this->columns = columns;
-  this->rows = rows;
-  this->endOfBlock = endOfBlock;
-  this->black = black;
-  refLine = (short *)gmalloc((columns + 2) * sizeof(short));
+CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+                              GBool byteAlignA, int columnsA, int rowsA,
+                              GBool endOfBlockA, GBool blackA):
+    FilterStream(strA) {
+  encoding = encodingA;
+  endOfLine = endOfLineA;
+  byteAlign = byteAlignA;
+  columns = columnsA;
+  rows = rowsA;
+  endOfBlock = endOfBlockA;
+  black = blackA;
+  refLine = (short *)gmalloc((columns + 3) * sizeof(short));
   codingLine = (short *)gmalloc((columns + 2) * sizeof(short));
 
   eof = gFalse;
@@ -1178,11 +1397,12 @@ void CCITTFaxStream::reset() {
 int CCITTFaxStream::lookChar() {
   short code1, code2, code3;
   int a0New;
-#if 0 //~
+#if 0
   GBool err;
 #endif
+  GBool gotEOL;
   int ret;
-  int bits, i, n;
+  int bits, i;
 
   // if at eof just return EOF
   if (eof && codingLine[a0] >= columns) {
@@ -1190,7 +1410,7 @@ int CCITTFaxStream::lookChar() {
   }
 
   // read the next row
-#if 0 //~
+#if 0
   err = gFalse;
 #endif
   if (codingLine[a0] >= columns) {
@@ -1292,7 +1512,7 @@ int CCITTFaxStream::lookChar() {
          return EOF;
        default:
          error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1);
-#if 0 //~
+#if 0
          err = gTrue;
          break;
 #else
@@ -1327,7 +1547,7 @@ int CCITTFaxStream::lookChar() {
 
     if (codingLine[a0] != columns) {
       error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]);
-#if 0 //~
+#if 0
       err = gTrue;
 #endif
     }
@@ -1337,62 +1557,57 @@ int CCITTFaxStream::lookChar() {
       inputBits &= ~7;
     }
 
-    // check for end-of-line marker, end-of-block marker, and
-    // 2D encoding tag
-    if (endOfBlock) {
+    // check for end-of-line marker, skipping over any extra zero bits
+    gotEOL = gFalse;
+    if (!endOfBlock && row == rows - 1) {
+      eof = gTrue;
+    } else {
       code1 = lookBits(12);
-      if (code1 == EOF) {
+      while (code1 == 0) {
+       eatBits(1);
+       code1 = lookBits(12);
+      }
+      if (code1 == 0x001) {
+       eatBits(12);
+       gotEOL = gTrue;
+      } else if (code1 == EOF) {
        eof = gTrue;
-      } else if (code1 == 0x001) {
+      }
+    }
+
+    // get 2D encoding tag
+    if (!eof && encoding > 0) {
+      nextLine2D = !lookBits(1);
+      eatBits(1);
+    }
+
+    // check for end-of-block marker
+    if (endOfBlock && gotEOL) {
+      code1 = lookBits(12);
+      if (code1 == 0x001) {
        eatBits(12);
        if (encoding > 0) {
-         nextLine2D = !lookBits(1);
+         lookBits(1);
          eatBits(1);
        }
-       code1 = lookBits(12);
-       if (code1 == 0x001) {
-         eatBits(12);
-         if (encoding > 0) {
-           lookBits(1);
-           eatBits(1);
-         }
-         if (encoding >= 0) {
-           for (i = 0; i < 4; ++i) {
-             code1 = lookBits(12);
-             if (code1 != 0x001) {
-               error(getPos(), "Bad RTC code in CCITTFax stream");
-             }
-             eatBits(12);
-             if (encoding > 0) {
-               lookBits(1);
-               eatBits(1);
-             }
+       if (encoding >= 0) {
+         for (i = 0; i < 4; ++i) {
+           code1 = lookBits(12);
+           if (code1 != 0x001) {
+             error(getPos(), "Bad RTC code in CCITTFax stream");
+           }
+           eatBits(12);
+           if (encoding > 0) {
+             lookBits(1);
+             eatBits(1);
            }
          }
-         eof = gTrue;
        }
-      } else {
-       if (encoding > 0) {
-         nextLine2D = !lookBits(1);
-         eatBits(1);
-       }
-      }
-    } else {
-      if (row == rows - 1) {
        eof = gTrue;
-      } else {
-       for (n = 0; n < 11 && lookBits(n) == 0; ++n) ;
-       if (n == 11 && lookBits(12) == 0x001) {
-         eatBits(12);
-       }
-       if (encoding > 0) {
-         nextLine2D = !lookBits(1);
-         eatBits(1);
-       }
       }
     }
 
-#if 0 //~
+#if 0
     // This looks for an end-of-line marker after an error, however
     // some (most?) CCITT streams in PDF files don't use end-of-line
     // markers, and the just-plow-on technique works better in those
@@ -1501,10 +1716,11 @@ short CCITTFaxStream::getWhiteCode() {
   code = 0; // make gcc happy
   if (endOfBlock) {
     code = lookBits(12);
-    if ((code >> 5) == 0)
+    if ((code >> 5) == 0) {
       p = &whiteTab1[code];
-    else
+    } else {
       p = &whiteTab2[code >> 3];
+    }
     if (p->bits > 0) {
       eatBits(p->bits);
       return p->n;
@@ -1534,7 +1750,10 @@ short CCITTFaxStream::getWhiteCode() {
     }
   }
   error(getPos(), "Bad white code (%04x) in CCITTFax stream", code);
-  return EOF;
+  // eat a bit and return a positive number so that the caller doesn't
+  // go into an infinite loop
+  eatBits(1);
+  return 1;
 }
 
 short CCITTFaxStream::getBlackCode() {
@@ -1545,12 +1764,13 @@ short CCITTFaxStream::getBlackCode() {
   code = 0; // make gcc happy
   if (endOfBlock) {
     code = lookBits(13);
-    if ((code >> 7) == 0)
+    if ((code >> 7) == 0) {
       p = &blackTab1[code];
-    else if ((code >> 9) == 0)
+    } else if ((code >> 9) == 0) {
       p = &blackTab2[(code >> 1) - 64];
-    else
+    } else {
       p = &blackTab3[code >> 7];
+    }
     if (p->bits > 0) {
       eatBits(p->bits);
       return p->n;
@@ -1593,7 +1813,10 @@ short CCITTFaxStream::getBlackCode() {
     }
   }
   error(getPos(), "Bad black code (%04x) in CCITTFax stream", code);
-  return EOF;
+  // eat a bit and return a positive number so that the caller doesn't
+  // go into an infinite loop
+  eatBits(1);
+  return 1;
 }
 
 short CCITTFaxStream::lookBits(int n) {
@@ -1601,9 +1824,14 @@ short CCITTFaxStream::lookBits(int n) {
 
   while (inputBits < n) {
     if ((c = str->getChar()) == EOF) {
-      if (inputBits == 0)
+      if (inputBits == 0) {
        return EOF;
-      c = 0;
+      }
+      // near the end of the stream, the caller may ask for more bits
+      // than are available, but there may still be a valid code in
+      // however many bits are available -- we need to return correct
+      // data in this case
+      return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n));
     }
     inputBuf = (inputBuf << 8) + c;
     inputBits += 8;
@@ -1615,7 +1843,9 @@ GString *CCITTFaxStream::getPSFilter(char *indent) {
   GString *s;
   char s1[50];
 
-  s = str->getPSFilter(indent);
+  if (!(s = str->getPSFilter(indent))) {
+    return NULL;
+  }
   s->append(indent)->append("<< ");
   if (encoding != 0) {
     sprintf(s1, "/K %d ", encoding);
@@ -1705,10 +1935,10 @@ static int dctZigZag[64] = {
   63
 };
 
-DCTStream::DCTStream(Stream *str1) {
+DCTStream::DCTStream(Stream *strA):
+    FilterStream(strA) {
   int i, j;
 
-  str = str1;
   width = height = 0;
   mcuWidth = mcuHeight = 0;
   numComps = 0;
@@ -1896,7 +2126,7 @@ GBool DCTStream::readMCURow() {
            pCr = rowBuf[2][y2][x1+x2] - 128;
            pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
            rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR];
-           pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32678) >> 16;
+           pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
            rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG];
            pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
            rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB];
@@ -2605,7 +2835,9 @@ int DCTStream::read16() {
 GString *DCTStream::getPSFilter(char *indent) {
   GString *s;
 
-  s = str->getPSFilter(indent);
+  if (!(s = str->getPSFilter(indent))) {
+    return NULL;
+  }
   s->append(indent)->append("<< >> /DCTDecode filter\n");
   return s;
 }
@@ -2687,11 +2919,11 @@ FlateDecode FlateStream::distDecode[flateMaxDistCodes] = {
   {13, 24577}
 };
 
-FlateStream::FlateStream(Stream *str1, int predictor1, int columns1,
-                        int colors1, int bits1) {
-  str = str1;
-  if (predictor1 != 1) {
-    pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1);
+FlateStream::FlateStream(Stream *strA, int predictor, int columns,
+                        int colors, int bits):
+    FilterStream(strA) {
+  if (predictor != 1) {
+    pred = new StreamPredictor(this, predictor, columns, colors, bits);
   } else {
     pred = NULL;
   }
@@ -2707,6 +2939,14 @@ FlateStream::~FlateStream() {
 void FlateStream::reset() {
   int cmf, flg;
 
+  index = 0;
+  remain = 0;
+  codeBuf = 0;
+  codeSize = 0;
+  compressedBlock = gFalse;
+  endOfBlock = gTrue;
+  eof = gTrue;
+
   str->reset();
 
   // read header
@@ -2729,13 +2969,6 @@ void FlateStream::reset() {
     return;
   }
 
-  // initialize
-  index = 0;
-  remain = 0;
-  codeBuf = 0;
-  codeSize = 0;
-  compressedBlock = gFalse;
-  endOfBlock = gTrue;
   eof = gFalse;
 }
 
@@ -2933,11 +3166,12 @@ void FlateStream::loadFixedCodes() {
   compHuffmanCodes(&litCodeTab, flateMaxLitCodes);
 
   // initialize distance code table
-  for (i = 0; i < 5; ++i)
+  for (i = 0; i <= 5; ++i) {
     distCodeTab.start[i] = 0;
-  distCodeTab.start[5] = 0;
-  for (i = 6; i <= flateMaxHuffman+1; ++i)
-    distCodeTab.start[6] = flateMaxDistCodes;
+  }
+  for (i = 6; i <= flateMaxHuffman+1; ++i) {
+    distCodeTab.start[i] = flateMaxDistCodes;
+  }
   for (i = 0; i < flateMaxDistCodes; ++i) {
     distCodeTab.codes[i].len = 5;
     distCodeTab.codes[i].code = i;
@@ -3117,8 +3351,8 @@ int FlateStream::getCodeWord(int bits) {
 // EOFStream
 //------------------------------------------------------------------------
 
-EOFStream::EOFStream(Stream *str1) {
-  str = str1;
+EOFStream::EOFStream(Stream *strA):
+    FilterStream(strA) {
 }
 
 EOFStream::~EOFStream() {
@@ -3129,9 +3363,9 @@ EOFStream::~EOFStream() {
 // FixedLengthEncoder
 //------------------------------------------------------------------------
 
-FixedLengthEncoder::FixedLengthEncoder(Stream *str1, int length1) {
-  str = str1;
-  length = length1;
+FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA):
+    FilterStream(strA) {
+  length = lengthA;
   count = 0;
 }
 
@@ -3145,6 +3379,9 @@ void FixedLengthEncoder::reset() {
   count = 0;
 }
 
+void FixedLengthEncoder::close() {
+}
+
 int FixedLengthEncoder::getChar() {
   if (length >= 0 && count >= length)
     return EOF;
@@ -3158,12 +3395,62 @@ int FixedLengthEncoder::lookChar() {
   return str->getChar();
 }
 
+//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA):
+    FilterStream(strA) {
+  bufPtr = bufEnd = buf;
+  lineLen = 0;
+  eof = gFalse;
+}
+
+ASCIIHexEncoder::~ASCIIHexEncoder() {
+  if (str->isEncoder()) {
+    delete str;
+  }
+}
+
+void ASCIIHexEncoder::reset() {
+  str->reset();
+  bufPtr = bufEnd = buf;
+  lineLen = 0;
+  eof = gFalse;
+}
+
+void ASCIIHexEncoder::close() {
+}
+
+GBool ASCIIHexEncoder::fillBuf() {
+  static char *hex = "0123456789abcdef";
+  int c;
+
+  if (eof) {
+    return gFalse;
+  }
+  bufPtr = bufEnd = buf;
+  if ((c = str->getChar()) == EOF) {
+    *bufEnd++ = '>';
+    eof = gTrue;
+  } else {
+    if (lineLen >= 64) {
+      *bufEnd++ = '\n';
+      lineLen = 0;
+    }
+    *bufEnd++ = hex[(c >> 4) & 0x0f];
+    *bufEnd++ = hex[c & 0x0f];
+    lineLen += 2;
+  }
+  return gTrue;
+}
+
 //------------------------------------------------------------------------
 // ASCII85Encoder
 //------------------------------------------------------------------------
 
-ASCII85Encoder::ASCII85Encoder(Stream *str1) {
-  str = str1;
+ASCII85Encoder::ASCII85Encoder(Stream *strA):
+    FilterStream(strA) {
   bufPtr = bufEnd = buf;
   lineLen = 0;
   eof = gFalse;
@@ -3181,6 +3468,9 @@ void ASCII85Encoder::reset() {
   eof = gFalse;
 }
 
+void ASCII85Encoder::close() {
+}
+
 GBool ASCII85Encoder::fillBuf() {
   Gulong t;
   char buf1[5];
@@ -3231,8 +3521,8 @@ GBool ASCII85Encoder::fillBuf() {
 // RunLengthEncoder
 //------------------------------------------------------------------------
 
-RunLengthEncoder::RunLengthEncoder(Stream *str1) {
-  str = str1;
+RunLengthEncoder::RunLengthEncoder(Stream *strA):
+    FilterStream(strA) {
   bufPtr = bufEnd = nextEnd = buf;
   eof = gFalse;
 }
@@ -3248,6 +3538,9 @@ void RunLengthEncoder::reset() {
   eof = gFalse;
 }
 
+void RunLengthEncoder::close() {
+}
+
 //
 // When fillBuf finishes, buf[] looks like this:
 //   +-----+--------------+-----------------+--
@@ -3287,6 +3580,7 @@ GBool RunLengthEncoder::fillBuf() {
   }
 
   // check for repeat
+  c = 0; // make gcc happy
   if (c1 == c2) {
     n = 2;
     while (n < 128 && (c = str->getChar()) == c1)