]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/Stream.cc
Synched with Xpdf 0.92
[evince.git] / pdf / xpdf / Stream.cc
index adcf788b53e164f7a1a07d1140f70fffbe8640f5..0afcc94abc526347dcf0bda342c7483d8f92883e 100644 (file)
 #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,6 +44,10 @@ extern "C" int unlink(char *filename);
 #endif
 #endif
 
+#ifdef MACOS
+#include "StuffItEngineLib.h"
+#endif
+
 //------------------------------------------------------------------------
 // Stream (base class)
 //------------------------------------------------------------------------
@@ -56,6 +59,9 @@ Stream::Stream() {
 Stream::~Stream() {
 }
 
+void Stream::close() {
+}
+
 int Stream::getRawChar() {
   error(-1, "Internal: called getRawChar() on non-predictor stream");
   return EOF;
@@ -261,11 +267,24 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
 
 BaseStream::BaseStream(Object *dict) {
   this->dict = *dict;
+#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 objNum, int objGen) {
+  decrypt = new Decrypt(fileKey, objNum, objGen);
 }
+#endif
 
 //------------------------------------------------------------------------
 // FilterStream
@@ -278,6 +297,10 @@ FilterStream::FilterStream(Stream *str) {
 FilterStream::~FilterStream() {
 }
 
+void FilterStream::close() {
+  str->close();
+}
+
 void FilterStream::setPos(int pos) {
   error(-1, "Internal: called setPos() on FilterStream");
 }
@@ -540,9 +563,7 @@ FileStream::FileStream(FILE *f, int start, int length, Object *dict):
 }
 
 FileStream::~FileStream() {
-  if (savePos >= 0) {
-    fseek(f, savePos, SEEK_SET);
-  }
+  close();
 }
 
 Stream *FileStream::makeSubStream(int start, int length, Object *dict) {
@@ -554,23 +575,47 @@ void FileStream::reset() {
   fseek(f, start, SEEK_SET);
   bufPtr = bufEnd = buf;
   bufPos = start;
+#ifndef NO_DECRYPTION
+  if (decrypt)
+    decrypt->reset();
+#endif
+}
+
+void FileStream::close() {
+  if (savePos >= 0) {
+    fseek(f, savePos, SEEK_SET);
+    savePos = -1;
+  }
 }
 
 GBool FileStream::fillBuf() {
   int n;
+#ifndef NO_DECRYPTION
+  char *p;
+#endif
 
   bufPos += bufEnd - buf;
   bufPtr = bufEnd = buf;
-  if (length >= 0 && bufPos >= start + length)
+  if (length >= 0 && bufPos >= start + length) {
     return gFalse;
-  if (length >= 0 && bufPos + 256 > start + length)
+  }
+  if (length >= 0 && bufPos + fileStreamBufSize > start + length) {
     n = start + length - bufPos;
-  else
-    n = 256;
+  } 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;
 }
 
@@ -813,7 +858,8 @@ LZWStream::~LZWStream() {
     fclose(zPipe);
 #endif
     zPipe = NULL;
-    unlink(zName);
+    unlink(zName->getCString());
+    delete zName;
   }
   if (pred) {
     delete pred;
@@ -841,9 +887,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);
@@ -851,51 +897,82 @@ 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
+#else // HAVE_POPEN
 #ifdef VMS
-  if (!system(zCmd)) {
+  if (!system(zCmd->getCString())) {
 #else
-  if (system(zCmd)) {
+  if (system(zCmd->getCString())) {
 #endif
-    error(getPos(), "Couldn't execute '%s'", zCmd);
-    unlink(zName);
+    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) {
@@ -910,6 +987,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);
@@ -1046,7 +1125,8 @@ GBool LZWStream::fillBuf() {
     fclose(zPipe);
 #endif
     zPipe = NULL;
-    unlink(zName);
+    unlink(zName->getCString());
+    delete zName;
   }
   bufPtr = buf;
   bufEnd = buf + n;
@@ -1141,7 +1221,7 @@ CCITTFaxStream::CCITTFaxStream(Stream *str, int encoding, GBool endOfLine,
   this->rows = rows;
   this->endOfBlock = endOfBlock;
   this->black = black;
-  refLine = (short *)gmalloc((columns + 2) * sizeof(short));
+  refLine = (short *)gmalloc((columns + 3) * sizeof(short));
   codingLine = (short *)gmalloc((columns + 2) * sizeof(short));
 
   eof = gFalse;
@@ -1197,8 +1277,9 @@ int CCITTFaxStream::lookChar() {
 #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) {
@@ -1353,58 +1434,53 @@ 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);
-       }
       }
     }
 
@@ -1517,10 +1593,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;
@@ -1550,7 +1627,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() {
@@ -1561,12 +1641,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;
@@ -1609,7 +1690,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) {
@@ -1617,9 +1701,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;
@@ -2723,6 +2812,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
@@ -2745,13 +2842,6 @@ void FlateStream::reset() {
     return;
   }
 
-  // initialize
-  index = 0;
-  remain = 0;
-  codeBuf = 0;
-  codeSize = 0;
-  compressedBlock = gFalse;
-  endOfBlock = gTrue;
   eof = gFalse;
 }
 
@@ -2949,11 +3039,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;
@@ -3161,6 +3252,9 @@ void FixedLengthEncoder::reset() {
   count = 0;
 }
 
+void FixedLengthEncoder::close() {
+}
+
 int FixedLengthEncoder::getChar() {
   if (length >= 0 && count >= length)
     return EOF;
@@ -3197,6 +3291,9 @@ void ASCII85Encoder::reset() {
   eof = gFalse;
 }
 
+void ASCII85Encoder::close() {
+}
+
 GBool ASCII85Encoder::fillBuf() {
   Gulong t;
   char buf1[5];
@@ -3264,6 +3361,9 @@ void RunLengthEncoder::reset() {
   eof = gFalse;
 }
 
+void RunLengthEncoder::close() {
+}
+
 //
 // When fillBuf finishes, buf[] looks like this:
 //   +-----+--------------+-----------------+--
@@ -3303,6 +3403,7 @@ GBool RunLengthEncoder::fillBuf() {
   }
 
   // check for repeat
+  c = 0; // make gcc happy
   if (c1 == c2) {
     n = 2;
     while (n < 128 && (c = str->getChar()) == c1)