X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=pdf%2Fxpdf%2FStream.cc;h=3d19436774229ebc9b34245c2e9d856c43edc232;hb=d97441740d457e1463083d561afdb719ca99e66b;hp=0d19d4d2c362074b4a45e6a5e66b20af341801bb;hpb=64676031423465996e83c4a685290f0c3d97a249;p=evince.git diff --git a/pdf/xpdf/Stream.cc b/pdf/xpdf/Stream.cc index 0d19d4d2..3d194367 100644 --- a/pdf/xpdf/Stream.cc +++ b/pdf/xpdf/Stream.cc @@ -2,7 +2,7 @@ // // Stream.cc // -// Copyright 1996-2002 Glyph & Cog, LLC +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== @@ -22,7 +22,7 @@ #include #include "gmem.h" #include "gfile.h" -#include "config.h" +#include "xpdfconfig.h" #include "Error.h" #include "Object.h" #ifndef NO_DECRYPTION @@ -30,6 +30,7 @@ #endif #include "Stream.h" #include "JBIG2Stream.h" +#include "JPXStream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ @@ -84,7 +85,7 @@ char *Stream::getLine(char *buf, int size) { return buf; } -GString *Stream::getPSFilter(char *indent) { +GString *Stream::getPSFilter(int psLevel, char *indent) { return new GString(); } @@ -256,6 +257,8 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { } str = new JBIG2Stream(str, &globals); globals.free(); + } else if (!strcmp(name, "JPXDecode")) { + str = new JPXStream(str); } else { error(getPos(), "Unknown filter '%s'", name); str = new EOFStream(str); @@ -450,7 +453,7 @@ GBool StreamPredictor::getNextLine() { int i, j, k; // get PNG optimum predictor number - if (predictor == 15) { + if (predictor >= 10) { if ((curPred = str->getRawChar()) == EOF) { return gFalse; } @@ -467,7 +470,7 @@ GBool StreamPredictor::getNextLine() { upLeftBuf[1] = upLeftBuf[0]; upLeftBuf[0] = predLine[i]; if ((c = str->getRawChar()) == EOF) { - break; + return gFalse; } switch (curPred) { case 11: // PNG sub @@ -506,7 +509,6 @@ GBool StreamPredictor::getNextLine() { } // apply TIFF (component) predictor - //~ this is completely untested if (predictor == 2) { if (nBits == 1) { inBuf = predLine[pixBytes - 1]; @@ -697,13 +699,14 @@ void FileStream::moveStart(int delta) { // MemStream //------------------------------------------------------------------------ -MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA): +MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): BaseStream(dictA) { buf = bufA; - needFree = gFalse; + start = startA; length = lengthA; - bufEnd = buf + length; - bufPtr = buf; + bufEnd = buf + start + length; + bufPtr = buf + start; + needFree = gFalse; } MemStream::~MemStream() { @@ -712,20 +715,22 @@ MemStream::~MemStream() { } } -Stream *MemStream::makeSubStream(Guint start, GBool limited, +Stream *MemStream::makeSubStream(Guint startA, GBool limited, Guint lengthA, Object *dictA) { + MemStream *subStr; Guint newLength; - if (!limited || start + lengthA > length) { - newLength = length - start; + if (!limited || startA + lengthA > start + length) { + newLength = start + length - startA; } else { newLength = lengthA; } - return new MemStream(buf + start, newLength, dictA); + subStr = new MemStream(buf, startA, newLength, dictA); + return subStr; } void MemStream::reset() { - bufPtr = buf; + bufPtr = buf + start; #ifndef NO_DECRYPTION if (decrypt) { decrypt->reset(); @@ -737,24 +742,24 @@ void MemStream::close() { } void MemStream::setPos(Guint pos, int dir) { + Guint i; + if (dir >= 0) { - if (pos > length) { - bufPtr = bufEnd; - } else { - bufPtr = buf + pos; - } + i = pos; } else { - if (pos > length) { - bufPtr = buf; - } else { - bufPtr = bufEnd - pos; - } + i = start + length - pos; } + if (i < start) { + i = start; + } else if (i > start + length) { + i = start + length; + } + bufPtr = buf + i; } void MemStream::moveStart(int delta) { - buf += delta; - bufPtr = buf; + start += delta; + bufPtr = buf + start; } #ifndef NO_DECRYPTION @@ -765,12 +770,13 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength, this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); if (decrypt) { - newBuf = (char *)gmalloc(bufEnd - buf); - for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) { + newBuf = (char *)gmalloc(length); + for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { *q = (char)decrypt->decryptByte((Guchar)*p); } - bufEnd = newBuf + (bufEnd - buf); - bufPtr = newBuf + (bufPtr - buf); + bufEnd = newBuf + length; + bufPtr = newBuf + (bufPtr - (buf + start)); + start = 0; buf = newBuf; needFree = gTrue; } @@ -781,20 +787,38 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength, // EmbedStream //------------------------------------------------------------------------ -EmbedStream::EmbedStream(Stream *strA, Object *dictA): +EmbedStream::EmbedStream(Stream *strA, Object *dictA, + GBool limitedA, Guint lengthA): BaseStream(dictA) { str = strA; + limited = limitedA; + length = lengthA; } EmbedStream::~EmbedStream() { } -Stream *EmbedStream::makeSubStream(Guint start, GBool limited, - Guint length, Object *dictA) { +Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA) { error(-1, "Internal: called makeSubStream() on EmbedStream"); return NULL; } +int EmbedStream::getChar() { + if (limited && !length) { + return EOF; + } + --length; + return str->getChar(); +} + +int EmbedStream::lookChar() { + if (limited && !length) { + return EOF; + } + return str->lookChar(); +} + void EmbedStream::setPos(Guint pos, int dir) { error(-1, "Internal: called setPos() on EmbedStream"); } @@ -881,10 +905,13 @@ int ASCIIHexStream::lookChar() { return buf; } -GString *ASCIIHexStream::getPSFilter(char *indent) { +GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/ASCIIHexDecode filter\n"); @@ -959,10 +986,13 @@ int ASCII85Stream::lookChar() { return b[index]; } -GString *ASCII85Stream::getPSFilter(char *indent) { +GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/ASCII85Decode filter\n"); @@ -1138,13 +1168,13 @@ int LZWStream::getCode() { return code; } -GString *LZWStream::getPSFilter(char *indent) { +GString *LZWStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (pred) { + if (psLevel < 2 || pred) { return NULL; } - if (!(s = str->getPSFilter(indent))) { + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/LZWDecode filter\n"); @@ -1175,10 +1205,13 @@ void RunLengthStream::reset() { eof = gFalse; } -GString *RunLengthStream::getPSFilter(char *indent) { +GString *RunLengthStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/RunLengthDecode filter\n"); @@ -1251,7 +1284,7 @@ CCITTFaxStream::~CCITTFaxStream() { } void CCITTFaxStream::reset() { - int n; + short code1; str->reset(); eof = gFalse; @@ -1263,16 +1296,13 @@ void CCITTFaxStream::reset() { a0 = 1; buf = EOF; - // get initial end-of-line marker and 2D encoding tag - if (endOfBlock) { - if (lookBits(12) == 0x001) { - eatBits(12); - } - } else { - for (n = 0; n < 11 && lookBits(n) == 0; ++n) ; - if (n == 11 && lookBits(12) == 0x001) { - eatBits(12); - } + // skip any initial zero bits and end-of-line marker, and get the 2D + // encoding tag + while ((code1 = lookBits(12)) == 0) { + eatBits(1); + } + if (code1 == 0x001) { + eatBits(12); } if (encoding > 0) { nextLine2D = !lookBits(1); @@ -1283,10 +1313,7 @@ void CCITTFaxStream::reset() { int CCITTFaxStream::lookChar() { short code1, code2, code3; int a0New; -#if 0 - GBool err; -#endif - GBool gotEOL; + GBool err, gotEOL; int ret; int bits, i; @@ -1296,9 +1323,7 @@ int CCITTFaxStream::lookChar() { } // read the next row -#if 0 err = gFalse; -#endif if (codingLine[a0] >= columns) { // 2-D encoding @@ -1335,12 +1360,14 @@ int CCITTFaxStream::lookChar() { code2 += code3 = getWhiteCode(); } while (code3 >= 64); } - codingLine[a0 + 1] = a0New + code1; - ++a0; - a0New = codingLine[a0 + 1] = codingLine[a0] + code2; - ++a0; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; + if (code1 > 0 || code2 > 0) { + codingLine[a0 + 1] = a0New + code1; + ++a0; + a0New = codingLine[a0 + 1] = codingLine[a0] + code2; + ++a0; + while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + b1 += 2; + } break; case twoDimVert0: a0New = codingLine[++a0] = refLine[b1]; @@ -1398,13 +1425,8 @@ int CCITTFaxStream::lookChar() { return EOF; default: error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); -#if 0 err = gTrue; break; -#else - eof = gTrue; - return EOF; -#endif } } while (codingLine[a0] < columns); @@ -1433,9 +1455,12 @@ int CCITTFaxStream::lookChar() { if (codingLine[a0] != columns) { error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); -#if 0 + // force the row to be the correct length + while (codingLine[a0] > columns) { + --a0; + } + codingLine[++a0] = columns; err = gTrue; -#endif } // byte-align the row @@ -1491,30 +1516,25 @@ int CCITTFaxStream::lookChar() { } eof = gTrue; } - } -#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 - // cases. - else if (err) { + // look for an end-of-line marker after an error -- we only do + // this if we know the stream contains end-of-line markers because + // the "just plow on" technique tends to work better otherwise + } else if (err && endOfLine) { do { if (code1 == EOF) { eof = gTrue; return EOF; } eatBits(1); - code1 = look13Bits(); + code1 = lookBits(13); } while ((code1 >> 1) != 0x001); eatBits(12); - codingLine[++a0] = columns; if (encoding > 0) { eatBits(1); nextLine2D = !(code1 & 1); } } -#endif a0 = 0; outputBits = codingLine[1] - codingLine[0]; @@ -1725,11 +1745,14 @@ short CCITTFaxStream::lookBits(int n) { return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); } -GString *CCITTFaxStream::getPSFilter(char *indent) { +GString *CCITTFaxStream::getPSFilter(int psLevel, char *indent) { GString *s; char s1[50]; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< "); @@ -1865,6 +1888,7 @@ void DCTStream::reset() { numDCHuffTables = 0; numACHuffTables = 0; colorXform = 0; + gotJFIFMarker = gFalse; gotAdobeMarker = gFalse; restartInterval = 0; @@ -1895,7 +1919,12 @@ void DCTStream::reset() { // figure out color transform if (!gotAdobeMarker && numComps == 3) { - if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { + if (gotJFIFMarker) { + colorXform = 1; + } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && + compInfo[2].id == 66) { // ASCII "RGB" + colorXform = 0; + } else { colorXform = 1; } } @@ -2142,8 +2171,8 @@ GBool DCTStream::readMCURow() { // Read one scan from a progressive or non-interleaved JPEG stream. void DCTStream::readScan() { int data[64]; - int x1, y1, dy1, x2, y2, y3, cc, i; - int h, v, horiz, vert, hSub, vSub; + int x1, y1, dx1, dy1, x2, y2, y3, cc, i; + int h, v, horiz, vert, vSub; int *p1; int c; @@ -2153,13 +2182,15 @@ void DCTStream::readScan() { break; } } + dx1 = mcuWidth / compInfo[cc].hSample; dy1 = mcuHeight / compInfo[cc].vSample; } else { + dx1 = mcuWidth; dy1 = mcuHeight; } - for (y1 = 0; y1 < bufHeight; y1 += dy1) { - for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (y1 = 0; y1 < height; y1 += dy1) { + for (x1 = 0; x1 < width; x1 += dx1) { // deal with restart marker if (restartInterval > 0 && restartCtr == 0) { @@ -2184,10 +2215,9 @@ void DCTStream::readScan() { v = compInfo[cc].vSample; horiz = mcuWidth / h; vert = mcuHeight / v; - hSub = horiz / 8; vSub = vert / 8; for (y2 = 0; y2 < dy1; y2 += vert) { - for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + for (x2 = 0; x2 < dx1; x2 += horiz) { // pull out the current values p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; @@ -2283,8 +2313,10 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, return gFalse; } i += run; - j = dctZigZag[i++]; - data[j] = amp; + if (i < 64) { + j = dctZigZag[i++]; + data[j] = amp; + } } } return gTrue; @@ -2370,7 +2402,7 @@ GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, eobRun = 0; for (k = 0; k < j; ++k) { if ((bit = readBit()) == EOF) { - return 9999; + return gFalse; } eobRun = (eobRun << 1) | bit; } @@ -2807,7 +2839,6 @@ GBool DCTStream::readHeader() { break; case 0xd9: // EOI return gFalse; - break; case 0xda: // SOS if (!readScanInfo()) { return gFalse; @@ -2824,6 +2855,11 @@ GBool DCTStream::readHeader() { return gFalse; } break; + case 0xe0: // APP0 + if (!readJFIFMarker()) { + return gFalse; + } + break; case 0xee: // APP14 if (!readAdobeMarker()) { return gFalse; @@ -2920,14 +2956,21 @@ GBool DCTStream::readScanInfo() { } for (i = 0; i < scanInfo.numComps; ++i) { id = str->getChar(); - for (j = 0; j < numComps; ++j) { - if (id == compInfo[j].id) { - break; + // some (broken) DCT streams reuse ID numbers, but at least they + // keep the components in order, so we check compInfo[i] first to + // work around the problem + if (id == compInfo[i].id) { + j = i; + } else { + for (j = 0; j < numComps; ++j) { + if (id == compInfo[j].id) { + break; + } + } + if (j == numComps) { + error(getPos(), "Bad DCT component ID in scan info block"); + return gFalse; } - } - if (j == numComps) { - error(getPos(), "Bad DCT component ID in scan info block"); - return gFalse; } scanInfo.comp[j] = gTrue; c = str->getChar(); @@ -3020,6 +3063,36 @@ GBool DCTStream::readRestartInterval() { return gTrue; } +GBool DCTStream::readJFIFMarker() { + int length, i; + char buf[5]; + int c; + + length = read16(); + length -= 2; + if (length >= 5) { + for (i = 0; i < 5; ++i) { + if ((c = str->getChar()) == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + buf[i] = c; + } + length -= 5; + if (!memcmp(buf, "JFIF\0", 5)) { + gotJFIFMarker = gTrue; + } + } + while (length > 0) { + if (str->getChar() == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + --length; + } + return gTrue; +} + GBool DCTStream::readAdobeMarker() { int length, i; char buf[12]; @@ -3087,10 +3160,13 @@ int DCTStream::read16() { return (c1 << 8) + c2; } -GString *DCTStream::getPSFilter(char *indent) { +GString *DCTStream::getPSFilter(int psLevel, char *indent) { GString *s; - if (!(s = str->getPSFilter(indent))) { + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< >> /DCTDecode filter\n"); @@ -3277,8 +3353,17 @@ int FlateStream::getRawChar() { return c; } -GString *FlateStream::getPSFilter(char *indent) { - return NULL; +GString *FlateStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 3 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /FlateDecode filter\n"); + return s; } GBool FlateStream::isBinary(GBool last) { @@ -3447,6 +3532,8 @@ GBool FlateStream::readDynamicCodes() { int len, repeat, code; int i; + codeLenCodeTab.codes = NULL; + // read lengths if ((numLitCodes = getCodeWord(5)) == EOF) { goto err; @@ -3489,23 +3576,35 @@ GBool FlateStream::readDynamicCodes() { if ((repeat = getCodeWord(2)) == EOF) { goto err; } - for (repeat += 3; repeat > 0; --repeat) { + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + for (; repeat > 0; --repeat) { codeLengths[i++] = len; } } else if (code == 17) { if ((repeat = getCodeWord(3)) == EOF) { goto err; } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } len = 0; - for (repeat += 3; repeat > 0; --repeat) { + for (; repeat > 0; --repeat) { codeLengths[i++] = 0; } } else if (code == 18) { if ((repeat = getCodeWord(7)) == EOF) { goto err; } + repeat += 11; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } len = 0; - for (repeat += 11; repeat > 0; --repeat) { + for (; repeat > 0; --repeat) { codeLengths[i++] = 0; } } else { @@ -3641,9 +3740,6 @@ void FixedLengthEncoder::reset() { count = 0; } -void FixedLengthEncoder::close() { -} - int FixedLengthEncoder::getChar() { if (length >= 0 && count >= length) return EOF; @@ -3657,6 +3753,10 @@ int FixedLengthEncoder::lookChar() { return str->getChar(); } +GBool FixedLengthEncoder::isBinary(GBool last) { + return str->isBinary(gTrue); +} + //------------------------------------------------------------------------ // ASCIIHexEncoder //------------------------------------------------------------------------ @@ -3681,9 +3781,6 @@ void ASCIIHexEncoder::reset() { eof = gFalse; } -void ASCIIHexEncoder::close() { -} - GBool ASCIIHexEncoder::fillBuf() { static char *hex = "0123456789abcdef"; int c; @@ -3730,9 +3827,6 @@ void ASCII85Encoder::reset() { eof = gFalse; } -void ASCII85Encoder::close() { -} - GBool ASCII85Encoder::fillBuf() { Gulong t; char buf1[5]; @@ -3800,9 +3894,6 @@ void RunLengthEncoder::reset() { eof = gFalse; } -void RunLengthEncoder::close() { -} - // // When fillBuf finishes, buf[] looks like this: // +-----+--------------+-----------------+--