X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=pdf%2Fxpdf%2FStream.cc;h=adcf788b53e164f7a1a07d1140f70fffbe8640f5;hb=2164227e7574c89d1a03b808ec525622d42966c2;hp=d7040cee18073721ce94d80439d35df1c828c183;hpb=d9f9a6449f377b4c933b75d57541b19c6d088994;p=evince.git diff --git a/pdf/xpdf/Stream.cc b/pdf/xpdf/Stream.cc index d7040cee..adcf788b 100644 --- a/pdf/xpdf/Stream.cc +++ b/pdf/xpdf/Stream.cc @@ -25,6 +25,15 @@ #include "Stream.h" #include "Stream-CCITT.h" +#ifdef _MSC_VER +#define popen _popen +#define pclose _pclose +#endif + +#ifdef __DJGPP__ +static GBool setDJSYSFLAGS = gFalse; +#endif + #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); @@ -36,42 +45,20 @@ extern "C" int unlink(char *filename); #endif #endif -//------------------------------------------------------------------------ - -#define headerSearchSize 1024 // read this many bytes at beginning of - // file to look for '%PDF' - //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ Stream::Stream() { ref = 1; - predictor = 1; - rawLine = NULL; - pixLine = NULL; } Stream::~Stream() { - gfree(rawLine); - gfree(pixLine); -} - -void Stream::resetImage(int width1, int nComps1, int nBits1) { - reset(); - if (predictor > 1 && - (width1 != width || nComps != nComps || nBits1 != nBits)) - error(-1, "Mismatched image parameters in predictor"); - width = width1; - nComps = nComps1; - nBits = nBits1; - nVals = width * nComps; - pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = (nVals * nBits + 7) >> 3; - rawLine = (Guchar *)grealloc(rawLine, rowBytes + pixBytes); - memset(rawLine, 0, rowBytes); - pixLine = (Guchar *)grealloc(pixLine, ((nVals + 7) & ~7) * sizeof(Guchar)); - pixIdx = nVals; +} + +int Stream::getRawChar() { + error(-1, "Internal: called getRawChar() on non-predictor stream"); + return EOF; } char *Stream::getLine(char *buf, int size) { @@ -95,158 +82,6 @@ char *Stream::getLine(char *buf, int size) { return buf; } -GBool Stream::getImagePixel(Guchar *pix) { - int curPred; - int left, up, upLeft, p, pa, pb, pc; - Guchar upLeftBuf[4]; - Gulong buf, bitMask; - int c; - int bits; - int i, j; - - // read an image line - if (pixIdx >= nVals) { - - // get PNG optimum predictor number - if (predictor == 15) { - if ((curPred = getChar()) == EOF) - return EOF; - curPred += 10; - } else { - curPred = predictor; - } - - // read the raw line, apply byte predictor - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; - for (i = 0; i < rowBytes; ++i) { - upLeftBuf[3] = upLeftBuf[2]; - upLeftBuf[2] = upLeftBuf[1]; - upLeftBuf[1] = upLeftBuf[0]; - upLeftBuf[0] = rawLine[pixBytes+i]; - if ((c = getChar()) == EOF) - return EOF; - switch (curPred) { - case 11: // PNG sub - rawLine[pixBytes+i] = rawLine[i] + (Guchar)c; - break; - case 12: // PNG up - rawLine[pixBytes+i] = rawLine[pixBytes+i] + (Guchar)c; - break; - case 13: // PNG average - rawLine[pixBytes+i] = ((rawLine[i] + rawLine[pixBytes+i]) >> 1) + - (Guchar)c; - break; - case 14: // PNG Paeth - left = rawLine[i]; - up = rawLine[pixBytes+i]; - upLeft = upLeftBuf[pixBytes]; - p = left + up - upLeft; - if ((pa = p - left) < 0) - pa = -pa; - if ((pb = p - up) < 0) - pb = -pb; - if ((pc = p - upLeft) < 0) - pc = -pc; - if (pa <= pb && pa <= pc) - rawLine[pixBytes+i] = pa + (Guchar)c; - else if (pb <= pc) - rawLine[pixBytes+i] = pb + (Guchar)c; - else - rawLine[pixBytes+i] = pc + (Guchar)c; - break; - case 10: // PNG none - default: // no predictor or TIFF predictor - rawLine[pixBytes+i] = (Guchar)c; - break; - } - } - - // convert into pixels, apply component predictor - if (predictor == 2) { - if (nBits == 1) { - for (i = 0, j = pixBytes; i < nVals; i += 8, ++j) { - c = rawLine[j]; - pixLine[i+0] = (Guchar)((pixLine[i+0] + (c >> 7)) & 1); - pixLine[i+1] = (Guchar)((pixLine[i+1] + (c >> 6)) & 1); - pixLine[i+2] = (Guchar)((pixLine[i+2] + (c >> 5)) & 1); - pixLine[i+3] = (Guchar)((pixLine[i+3] + (c >> 4)) & 1); - pixLine[i+4] = (Guchar)((pixLine[i+4] + (c >> 3)) & 1); - pixLine[i+5] = (Guchar)((pixLine[i+5] + (c >> 2)) & 1); - pixLine[i+6] = (Guchar)((pixLine[i+6] + (c >> 1)) & 1); - pixLine[i+7] = (Guchar)((pixLine[i+7] + c) & 1); - } - } else if (nBits == 8) { - for (i = 0, j = pixBytes; i < nVals; ++i, ++j) - pixLine[i] = pixLine[i] + rawLine[j]; - } else { - bitMask = (1 << nBits) - 1; - buf = 0; - bits = 0; - j = pixBytes; - for (i = 0; i < nVals; ++i) { - if (bits < nBits) { - buf = (buf << 8) | (rawLine[j++] & 0xff); - bits += 8; - } - pixLine[i] = (Guchar)((pixLine[i] + - (buf >> (bits - nBits))) & bitMask); - bits -= nBits; - } - } - } else { - if (nBits == 1) { - for (i = 0, j = pixBytes; i < nVals; i += 8, ++j) { - c = rawLine[j]; - pixLine[i+0] = (Guchar)((c >> 7) & 1); - pixLine[i+1] = (Guchar)((c >> 6) & 1); - pixLine[i+2] = (Guchar)((c >> 5) & 1); - pixLine[i+3] = (Guchar)((c >> 4) & 1); - pixLine[i+4] = (Guchar)((c >> 3) & 1); - pixLine[i+5] = (Guchar)((c >> 2) & 1); - pixLine[i+6] = (Guchar)((c >> 1) & 1); - pixLine[i+7] = (Guchar)(c & 1); - } - } else if (nBits == 8) { - for (i = 0, j = pixBytes; i < nVals; ++i, ++j) - pixLine[i] = rawLine[j]; - } else { - bitMask = (1 << nBits) - 1; - buf = 0; - bits = 0; - j = pixBytes; - for (i = 0; i < nVals; ++i) { - if (bits < nBits) { - buf = (buf << 8) | (rawLine[j++] & 0xff); - bits += 8; - } - pixLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); - bits -= nBits; - } - } - } - - // read from start of line - pixIdx = 0; - } - - for (i = 0; i < nComps; ++i) - pix[i] = pixLine[pixIdx++]; - return gTrue; -} - -void Stream::skipImageLine() { - int n, i; - - n = (nVals * nBits + 7) / 8; - for (i = 0; i < n; ++i) - getChar(); - pixIdx = nVals; -} - -void Stream::setPos(int pos) { - error(-1, "Internal: called setPos() on non-FileStream"); -} - GString *Stream::getPSFilter(char *indent) { return new GString(); } @@ -301,8 +136,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { int bits; int early; int encoding; - GBool byteAlign; - GBool black; + GBool endOfLine, byteAlign, endOfBlock, black; int columns, rows; Object obj; @@ -343,33 +177,51 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { str = new RunLengthStream(str); } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) { encoding = 0; + endOfLine = gFalse; byteAlign = gFalse; columns = 1728; rows = 0; + endOfBlock = gTrue; black = gFalse; if (params->isDict()) { params->dictLookup("K", &obj); - if (obj.isInt()) + if (obj.isInt()) { encoding = obj.getInt(); + } + obj.free(); + params->dictLookup("EndOfLine", &obj); + if (obj.isBool()) { + endOfLine = obj.getBool(); + } obj.free(); params->dictLookup("EncodedByteAlign", &obj); - if (obj.isBool()) + if (obj.isBool()) { byteAlign = obj.getBool(); + } obj.free(); params->dictLookup("Columns", &obj); - if (obj.isInt()) + if (obj.isInt()) { columns = obj.getInt(); + } obj.free(); params->dictLookup("Rows", &obj); - if (obj.isInt()) + if (obj.isInt()) { rows = obj.getInt(); + } + obj.free(); + params->dictLookup("EndOfBlock", &obj); + if (obj.isBool()) { + endOfBlock = obj.getBool(); + } obj.free(); params->dictLookup("BlackIs1", &obj); - if (obj.isBool()) + if (obj.isBool()) { black = obj.getBool(); + } obj.free(); } - str = new CCITTFaxStream(str, encoding, byteAlign, columns, rows, black); + str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, + columns, rows, endOfBlock, black); } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { str = new DCTStream(str); } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { @@ -403,24 +255,298 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { return str; } +//------------------------------------------------------------------------ +// BaseStream +//------------------------------------------------------------------------ + +BaseStream::BaseStream(Object *dict) { + this->dict = *dict; +} + +BaseStream::~BaseStream() { + dict.free(); +} + +//------------------------------------------------------------------------ +// FilterStream +//------------------------------------------------------------------------ + +FilterStream::FilterStream(Stream *str) { + this->str = str; +} + +FilterStream::~FilterStream() { +} + +void FilterStream::setPos(int pos) { + error(-1, "Internal: called setPos() on FilterStream"); +} + +//------------------------------------------------------------------------ +// ImageStream +//------------------------------------------------------------------------ + +ImageStream::ImageStream(Stream *str, int width, int nComps, int nBits) { + int imgLineSize; + + this->str = str; + this->width = width; + this->nComps = nComps; + this->nBits = nBits; + + nVals = width * nComps; + if (nBits == 1) { + imgLineSize = (nVals + 7) & ~7; + } else { + imgLineSize = nVals; + } + imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar)); + imgIdx = nVals; +} + +ImageStream::~ImageStream() { + gfree(imgLine); +} + +void ImageStream::reset() { + str->reset(); +} + +GBool ImageStream::getPixel(Guchar *pix) { + Gulong buf, bitMask; + int bits; + int c; + int i; + + if (imgIdx >= nVals) { + + // read one line of image pixels + if (nBits == 1) { + for (i = 0; i < nVals; i += 8) { + c = str->getChar(); + imgLine[i+0] = (Guchar)((c >> 7) & 1); + imgLine[i+1] = (Guchar)((c >> 6) & 1); + imgLine[i+2] = (Guchar)((c >> 5) & 1); + imgLine[i+3] = (Guchar)((c >> 4) & 1); + imgLine[i+4] = (Guchar)((c >> 3) & 1); + imgLine[i+5] = (Guchar)((c >> 2) & 1); + imgLine[i+6] = (Guchar)((c >> 1) & 1); + imgLine[i+7] = (Guchar)(c & 1); + } + } else if (nBits == 8) { + for (i = 0; i < nVals; ++i) { + imgLine[i] = str->getChar(); + } + } else { + bitMask = (1 << nBits) - 1; + buf = 0; + bits = 0; + for (i = 0; i < nVals; ++i) { + if (bits < nBits) { + buf = (buf << 8) | (str->getChar() & 0xff); + bits += 8; + } + imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); + bits -= nBits; + } + } + + // reset to start of line + imgIdx = 0; + } + + for (i = 0; i < nComps; ++i) + pix[i] = imgLine[imgIdx++]; + return gTrue; +} + +void ImageStream::skipLine() { + int n, i; + + n = (nVals * nBits + 7) >> 3; + for (i = 0; i < n; ++i) { + str->getChar(); + } +} + +//------------------------------------------------------------------------ +// 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; + + nVals = width * nComps; + pixBytes = (nComps * nBits + 7) >> 3; + rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; + predLine = (Guchar *)gmalloc(rowBytes); + memset(predLine, 0, rowBytes); + predIdx = rowBytes; +} + +StreamPredictor::~StreamPredictor() { + gfree(predLine); +} + +int StreamPredictor::lookChar() { + if (predIdx >= rowBytes) { + if (!getNextLine()) { + return EOF; + } + } + return predLine[predIdx]; +} + +int StreamPredictor::getChar() { + if (predIdx >= rowBytes) { + if (!getNextLine()) { + return EOF; + } + } + return predLine[predIdx++]; +} + +GBool StreamPredictor::getNextLine() { + int curPred; + Guchar upLeftBuf[4]; + int left, up, upLeft, p, pa, pb, pc; + int c; + Gulong inBuf, outBuf, bitMask; + int inBits, outBits; + int i, j, k; + + // get PNG optimum predictor number + if (predictor == 15) { + if ((curPred = str->getRawChar()) == EOF) { + return gFalse; + } + curPred += 10; + } else { + curPred = predictor; + } + + // read the raw line, apply PNG (byte) predictor + upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; + for (i = pixBytes; i < rowBytes; ++i) { + upLeftBuf[3] = upLeftBuf[2]; + upLeftBuf[2] = upLeftBuf[1]; + upLeftBuf[1] = upLeftBuf[0]; + upLeftBuf[0] = predLine[i]; + if ((c = str->getRawChar()) == EOF) { + break; + } + switch (curPred) { + case 11: // PNG sub + predLine[i] = predLine[i - pixBytes] + (Guchar)c; + break; + case 12: // PNG up + predLine[i] = predLine[i] + (Guchar)c; + break; + case 13: // PNG average + predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + + (Guchar)c; + break; + case 14: // PNG Paeth + left = predLine[i - pixBytes]; + up = predLine[i]; + upLeft = upLeftBuf[pixBytes]; + p = left + up - upLeft; + if ((pa = p - left) < 0) + pa = -pa; + if ((pb = p - up) < 0) + pb = -pb; + if ((pc = p - upLeft) < 0) + pc = -pc; + if (pa <= pb && pa <= pc) + predLine[i] = pa + (Guchar)c; + else if (pb <= pc) + predLine[i] = pb + (Guchar)c; + else + predLine[i] = pc + (Guchar)c; + break; + case 10: // PNG none + default: // no predictor or TIFF predictor + predLine[i] = (Guchar)c; + break; + } + } + + // apply TIFF (component) predictor + //~ this is completely untested + if (predictor == 2) { + if (nBits == 1) { + inBuf = predLine[pixBytes - 1]; + for (i = pixBytes; i < rowBytes; i += 8) { + // 1-bit add is just xor + inBuf = (inBuf << 8) | predLine[i]; + predLine[i] ^= inBuf >> nComps; + } + } else if (nBits == 8) { + for (i = pixBytes; i < rowBytes; ++i) { + predLine[i] += predLine[i - nComps]; + } + } else { + upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; + bitMask = (1 << nBits) - 1; + inBuf = outBuf = 0; + inBits = outBits = 0; + j = k = pixBytes; + for (i = 0; i < nVals; ++i) { + if (inBits < nBits) { + inBuf = (inBuf << 8) | (predLine[j++] & 0xff); + inBits += 8; + } + upLeftBuf[3] = upLeftBuf[2]; + upLeftBuf[2] = upLeftBuf[1]; + upLeftBuf[1] = upLeftBuf[0]; + upLeftBuf[0] = (upLeftBuf[nComps] + + (inBuf >> (inBits - nBits))) & bitMask; + outBuf = (outBuf << nBits) | upLeftBuf[0]; + inBits -= nBits; + outBits += nBits; + if (outBits > 8) { + predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); + } + } + if (outBits > 0) { + predLine[k++] = (Guchar)(outBuf << (8 - outBits)); + } + } + } + + // reset to start of line + predIdx = pixBytes; + + return gTrue; +} + //------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ -FileStream::FileStream(FILE *f1, int start1, int length1, Object *dict1) { - f = f1; - start = start1; - length = length1; +FileStream::FileStream(FILE *f, int start, int length, Object *dict): + BaseStream(dict) { + this->f = f; + this->start = start; + this->length = length; bufPtr = bufEnd = buf; bufPos = start; savePos = -1; - dict = *dict1; } FileStream::~FileStream() { - if (savePos >= 0) + if (savePos >= 0) { fseek(f, savePos, SEEK_SET); - dict.free(); + } +} + +Stream *FileStream::makeSubStream(int start, int length, Object *dict) { + return new FileStream(f, start, length, dict); } void FileStream::reset() { @@ -465,53 +591,48 @@ void FileStream::setPos(int pos1) { bufPtr = bufEnd = buf; } -GBool FileStream::checkHeader() { - char hdrBuf[headerSearchSize+1]; - char *p; - double version; - int i; - - 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; - } - if (i >= headerSearchSize - 5) { - error(-1, "May not be a PDF file (continuing anyway)"); - return gFalse; - } - start += i; - p = strtok(&hdrBuf[i+5], " \t\n\r"); - version = atof(p); - if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || version > pdfVersionNum) { - error(getPos(), "PDF version %s -- xpdf supports version %s" - " (continuing anyway)", p, pdfVersion); - return gFalse; - } - return gTrue; +void FileStream::moveStart(int delta) { + this->start += delta; + bufPtr = bufEnd = buf; + bufPos = start; } //------------------------------------------------------------------------ -// SubStream +// EmbedStream //------------------------------------------------------------------------ -SubStream::SubStream(Stream *str1, Object *dict1) { - str = str1; - dict = *dict1; +EmbedStream::EmbedStream(Stream *str, Object *dict): + BaseStream(dict) { + this->str = str; } -SubStream::~SubStream() { - dict.free(); +EmbedStream::~EmbedStream() { +} + +Stream *EmbedStream::makeSubStream(int start, int length, Object *dict) { + error(-1, "Internal: called makeSubStream() on EmbedStream"); + return NULL; +} + +void EmbedStream::setPos(int pos) { + error(-1, "Internal: called setPos() on EmbedStream"); +} + +int EmbedStream::getStart() { + error(-1, "Internal: called getStart() on EmbedStream"); + return 0; +} + +void EmbedStream::moveStart(int start) { + error(-1, "Internal: called moveStart() on EmbedStream"); } //------------------------------------------------------------------------ // ASCIIHexStream //------------------------------------------------------------------------ -ASCIIHexStream::ASCIIHexStream(Stream *str1) { - str = str1; +ASCIIHexStream::ASCIIHexStream(Stream *str): + FilterStream(str) { buf = EOF; eof = gFalse; } @@ -595,8 +716,8 @@ GBool ASCIIHexStream::isBinary(GBool last) { // ASCII85Stream //------------------------------------------------------------------------ -ASCII85Stream::ASCII85Stream(Stream *str1) { - str = str1; +ASCII85Stream::ASCII85Stream(Stream *str): + FilterStream(str) { index = n = 0; eof = gFalse; } @@ -671,14 +792,13 @@ GBool ASCII85Stream::isBinary(GBool last) { // LZWStream //------------------------------------------------------------------------ -LZWStream::LZWStream(Stream *str1, int predictor1, int columns1, int colors1, - int bits1, int early1) { - str = str1; - predictor = predictor1; - if (predictor1 > 1) { - width = columns1; - nComps = colors1; - nBits = bits1; +LZWStream::LZWStream(Stream *str, int predictor1, int columns1, int colors1, + int bits1, int early1): + FilterStream(str) { + if (predictor1 != 1) { + pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1); + } else { + pred = NULL; } early = early1; zPipe = NULL; @@ -695,17 +815,30 @@ LZWStream::~LZWStream() { zPipe = NULL; unlink(zName); } + if (pred) { + delete pred; + } delete str; } int LZWStream::getChar() { + if (pred) { + return pred->getChar(); + } return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int LZWStream::lookChar() { + if (pred) { + return pred->lookChar(); + } return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } +int LZWStream::getRawChar() { + return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); +} + void LZWStream::reset() { FILE *f; @@ -720,10 +853,19 @@ void LZWStream::reset() { zPipe = NULL; unlink(zName); } +#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); @@ -914,6 +1056,9 @@ GBool LZWStream::fillBuf() { GString *LZWStream::getPSFilter(char *indent) { GString *s; + if (pred) { + return NULL; + } s = str->getPSFilter(indent); s->append(indent)->append("/LZWDecode filter\n"); return s; @@ -927,8 +1072,8 @@ GBool LZWStream::isBinary(GBool last) { // RunLengthStream //------------------------------------------------------------------------ -RunLengthStream::RunLengthStream(Stream *str1) { - str = str1; +RunLengthStream::RunLengthStream(Stream *str): + FilterStream(str) { bufPtr = bufEnd = buf; eof = gFalse; } @@ -985,18 +1130,22 @@ GBool RunLengthStream::fillBuf() { // CCITTFaxStream //------------------------------------------------------------------------ -CCITTFaxStream::CCITTFaxStream(Stream *str1, int encoding1, GBool byteAlign1, - int columns1, int rows1, GBool black1) { - str = str1; - encoding = encoding1; - byteAlign = byteAlign1; - columns = columns1; - rows = rows1; - black = black1; +CCITTFaxStream::CCITTFaxStream(Stream *str, int encoding, GBool endOfLine, + GBool byteAlign, int columns, int rows, + GBool endOfBlock, GBool black): + FilterStream(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)); codingLine = (short *)gmalloc((columns + 2) * sizeof(short)); eof = gFalse; + row = 0; nextLine2D = encoding < 0; inputBits = 0; codingLine[0] = 0; @@ -1013,39 +1162,55 @@ CCITTFaxStream::~CCITTFaxStream() { } void CCITTFaxStream::reset() { + int n; + str->reset(); eof = gFalse; + row = 0; nextLine2D = encoding < 0; inputBits = 0; - if ((look13Bits() >> 1) == 0x001) - eatBits(12); codingLine[0] = 0; codingLine[1] = refLine[2] = columns; 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); + } + } + if (encoding > 0) { + nextLine2D = !lookBits(1); + eatBits(1); + } } int CCITTFaxStream::lookChar() { short code1, code2, code3; int a0New; +#if 0 //~ + GBool err; +#endif int ret; - int bits, i; + int bits, i, n; // if at eof just return EOF - if (eof && codingLine[a0] >= columns) + if (eof && codingLine[a0] >= columns) { return EOF; + } // read the next row +#if 0 //~ + err = gFalse; +#endif if (codingLine[a0] >= columns) { - // check for end of file - i = look13Bits(); - if (i == EOF || (i >> 1) == 0x001) { - eof = gTrue; - codingLine[a0 = 0] = columns; - return EOF; - } - // 2-D encoding if (nextLine2D) { for (i = 0; codingLine[i] < columns; ++i) @@ -1143,7 +1308,13 @@ 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); @@ -1170,21 +1341,104 @@ int CCITTFaxStream::lookChar() { } } - if (codingLine[a0] != columns) + if (codingLine[a0] != columns) { error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); +#if 0 //~ + err = gTrue; +#endif + } - // check for end-of-line marker - code1 = look13Bits(); - if ((code1 >> 1) == 0x001) { - eatBits(12); + // byte-align the row + if (byteAlign) { + inputBits &= ~7; + } + + // check for end-of-line marker, end-of-block marker, and + // 2D encoding tag + if (endOfBlock) { + code1 = lookBits(12); + if (code1 == EOF) { + eof = gTrue; + } else if (code1 == 0x001) { + eatBits(12); + if (encoding > 0) { + nextLine2D = !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); + } + } + } + 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 //~ + // 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) { + do { + if (code1 == EOF) { + eof = gTrue; + return EOF; + } + eatBits(1); + code1 = look13Bits(); + } 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]; + if (outputBits == 0) { + a0 = 1; + outputBits = codingLine[2] - codingLine[1]; + } + + ++row; } // get a byte @@ -1192,8 +1446,9 @@ int CCITTFaxStream::lookChar() { ret = ((a0 & 1) == 0) ? 0xff : 0x00; if ((outputBits -= 8) == 0) { ++a0; - if (codingLine[a0] < columns) + if (codingLine[a0] < columns) { outputBits = codingLine[a0 + 1] - codingLine[a0]; + } } } else { bits = 8; @@ -1202,18 +1457,21 @@ int CCITTFaxStream::lookChar() { if (outputBits > bits) { i = bits; bits = 0; - if ((a0 & 1) == 0) + if ((a0 & 1) == 0) { ret |= 0xff >> (8 - i); + } outputBits -= i; } else { i = outputBits; bits -= outputBits; - if ((a0 & 1) == 0) + if ((a0 & 1) == 0) { ret |= (0xff >> (8 - i)) << bits; + } outputBits = 0; ++a0; - if (codingLine[a0] < columns) + if (codingLine[a0] < columns) { outputBits = codingLine[a0 + 1] - codingLine[a0]; + } } } while (bits > 0 && codingLine[a0] < columns); } @@ -1222,50 +1480,74 @@ int CCITTFaxStream::lookChar() { } short CCITTFaxStream::getTwoDimCode() { - short code, code0; + short code; CCITTCode *p; + int n; - code0 = look13Bits(); - code = code0 >> 6; - if (code == 0x0002) { - eatBits(7); - return twoDimVertL3; - } - if (code == 0x0003) { - eatBits(7); - return twoDimVertR3; - } - code >>= 1; - if (code == 0x0002) { - eatBits(6); - return twoDimVertL2; - } - if (code == 0x0003) { - eatBits(6); - return twoDimVertR2; - } - code >>= 2; - p = &twoDimTab1[code]; - if (p->bits > 0) { - eatBits(p->bits); - return p->n; + code = 0; // make gcc happy + if (endOfBlock) { + code = lookBits(7); + p = &twoDimTab1[code]; + if (p->bits > 0) { + eatBits(p->bits); + return p->n; + } + } else { + for (n = 1; n <= 7; ++n) { + code = lookBits(n); + if (n < 7) { + code <<= 7 - n; + } + p = &twoDimTab1[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } } - error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code0); + error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code); return EOF; } short CCITTFaxStream::getWhiteCode() { short code; CCITTCode *p; + int n; - code = look13Bits(); - if ((code >> 6) == 0) - p = &whiteTab1[code >> 1]; - else - p = &whiteTab2[code >> 4]; - if (p->bits > 0) { - eatBits(p->bits); - return p->n; + code = 0; // make gcc happy + if (endOfBlock) { + code = lookBits(12); + if ((code >> 5) == 0) + p = &whiteTab1[code]; + else + p = &whiteTab2[code >> 3]; + if (p->bits > 0) { + eatBits(p->bits); + return p->n; + } + } else { + for (n = 1; n <= 9; ++n) { + code = lookBits(n); + if (n < 9) { + code <<= 9 - n; + } + p = &whiteTab2[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + for (n = 11; n <= 12; ++n) { + code = lookBits(n); + if (n < 12) { + code <<= 12 - n; + } + p = &whiteTab1[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } } error(getPos(), "Bad white code (%04x) in CCITTFax stream", code); return EOF; @@ -1274,26 +1556,66 @@ short CCITTFaxStream::getWhiteCode() { short CCITTFaxStream::getBlackCode() { short code; CCITTCode *p; + int n; - code = look13Bits(); - if ((code >> 7) == 0) - p = &blackTab1[code]; - else if ((code >> 9) == 0) - p = &blackTab2[(code >> 1) - 64]; - else - p = &blackTab3[code >> 7]; - if (p->bits > 0) { - eatBits(p->bits); - return p->n; + code = 0; // make gcc happy + if (endOfBlock) { + code = lookBits(13); + if ((code >> 7) == 0) + p = &blackTab1[code]; + else if ((code >> 9) == 0) + p = &blackTab2[(code >> 1) - 64]; + else + p = &blackTab3[code >> 7]; + if (p->bits > 0) { + eatBits(p->bits); + return p->n; + } + } else { + for (n = 2; n <= 6; ++n) { + code = lookBits(n); + if (n < 6) { + code <<= 6 - n; + } + p = &blackTab3[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + for (n = 7; n <= 12; ++n) { + code = lookBits(n); + if (n < 12) { + code <<= 12 - n; + } + if (code >= 64) { + p = &blackTab2[code - 64]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } + } + for (n = 10; n <= 13; ++n) { + code = lookBits(n); + if (n < 13) { + code <<= 13 - n; + } + p = &blackTab1[code]; + if (p->bits == n) { + eatBits(n); + return p->n; + } + } } error(getPos(), "Bad black code (%04x) in CCITTFax stream", code); return EOF; } -short CCITTFaxStream::look13Bits() { +short CCITTFaxStream::lookBits(int n) { int c; - while (inputBits < 13) { + while (inputBits < n) { if ((c = str->getChar()) == EOF) { if (inputBits == 0) return EOF; @@ -1302,7 +1624,7 @@ short CCITTFaxStream::look13Bits() { inputBuf = (inputBuf << 8) + c; inputBits += 8; } - return (inputBuf >> (inputBits - 13)) & 0x1fff; + return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); } GString *CCITTFaxStream::getPSFilter(char *indent) { @@ -1315,16 +1637,24 @@ GString *CCITTFaxStream::getPSFilter(char *indent) { sprintf(s1, "/K %d ", encoding); s->append(s1); } - if (byteAlign) + if (endOfLine) { + s->append("/EndOfLine true "); + } + if (byteAlign) { s->append("/EncodedByteAlign true "); + } sprintf(s1, "/Columns %d ", columns); s->append(s1); if (rows != 0) { sprintf(s1, "/Rows %d ", rows); s->append(s1); } - if (black) + if (!endOfBlock) { + s->append("/EndOfBlock false "); + } + if (black) { s->append("/BlackIs1 true "); + } s->append(">> /CCITTFaxDecode filter\n"); return s; } @@ -1391,10 +1721,10 @@ static int dctZigZag[64] = { 63 }; -DCTStream::DCTStream(Stream *str1) { +DCTStream::DCTStream(Stream *str): + FilterStream(str) { int i, j; - str = str1; width = height = 0; mcuWidth = mcuHeight = 0; numComps = 0; @@ -1567,7 +1897,7 @@ GBool DCTStream::readMCURow() { pCr = rowBuf[2][y2][x1+x2] - 128; pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; rowBuf[0][y2][x1+x2] = 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] = dctClip[dctClipOffset + pG]; pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB]; @@ -1995,6 +2325,7 @@ GBool DCTStream::readHeader() { numDCHuffTables = 0; numACHuffTables = 0; colorXform = 0; + gotAdobeMarker = gFalse; restartInterval = 0; // read headers @@ -2072,6 +2403,13 @@ GBool DCTStream::readHeader() { for (j = 0; j < mcuHeight; ++j) rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); + // figure out color transform + if (!gotAdobeMarker && numComps == 3) { + if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { + colorXform = 1; + } + } + // initialize counters comp = 0; x = 0; @@ -2237,6 +2575,7 @@ GBool DCTStream::readAdobeMarker() { if (strncmp(buf, "Adobe", 5)) goto err; colorXform = buf[11]; + gotAdobeMarker = gTrue; return gTrue; err: @@ -2364,18 +2703,20 @@ FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { {13, 24577} }; -FlateStream::FlateStream(Stream *str1, int predictor1, int columns1, - int colors1, int bits1) { - str = str1; - predictor = predictor1; - if (predictor1 > 1) { - width = columns1; - nComps = colors1; - nBits = bits1; +FlateStream::FlateStream(Stream *str, int predictor1, int columns1, + int colors1, int bits1): + FilterStream(str) { + if (predictor1 != 1) { + pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1); + } else { + pred = NULL; } } FlateStream::~FlateStream() { + if (pred) { + delete pred; + } delete str; } @@ -2417,6 +2758,9 @@ void FlateStream::reset() { int FlateStream::getChar() { int c; + if (pred) { + return pred->getChar(); + } while (remain == 0) { if (endOfBlock && eof) return EOF; @@ -2431,6 +2775,9 @@ int FlateStream::getChar() { int FlateStream::lookChar() { int c; + if (pred) { + return pred->lookChar(); + } while (remain == 0) { if (endOfBlock && eof) return EOF; @@ -2440,6 +2787,20 @@ int FlateStream::lookChar() { return c; } +int FlateStream::getRawChar() { + int c; + + while (remain == 0) { + if (endOfBlock && eof) + return EOF; + readSome(); + } + c = buf[index]; + index = (index + 1) & flateMask; + --remain; + return c; +} + GString *FlateStream::getPSFilter(char *indent) { return NULL; } @@ -2772,8 +3133,8 @@ int FlateStream::getCodeWord(int bits) { // EOFStream //------------------------------------------------------------------------ -EOFStream::EOFStream(Stream *str1) { - str = str1; +EOFStream::EOFStream(Stream *str): + FilterStream(str) { } EOFStream::~EOFStream() { @@ -2784,8 +3145,8 @@ EOFStream::~EOFStream() { // FixedLengthEncoder //------------------------------------------------------------------------ -FixedLengthEncoder::FixedLengthEncoder(Stream *str1, int length1) { - str = str1; +FixedLengthEncoder::FixedLengthEncoder(Stream *str, int length1): + FilterStream(str) { length = length1; count = 0; } @@ -2817,8 +3178,8 @@ int FixedLengthEncoder::lookChar() { // ASCII85Encoder //------------------------------------------------------------------------ -ASCII85Encoder::ASCII85Encoder(Stream *str1) { - str = str1; +ASCII85Encoder::ASCII85Encoder(Stream *str): + FilterStream(str) { bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; @@ -2886,8 +3247,8 @@ GBool ASCII85Encoder::fillBuf() { // RunLengthEncoder //------------------------------------------------------------------------ -RunLengthEncoder::RunLengthEncoder(Stream *str1) { - str = str1; +RunLengthEncoder::RunLengthEncoder(Stream *str): + FilterStream(str) { bufPtr = bufEnd = nextEnd = buf; eof = gFalse; }