X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2Fxpdf%2FStream.cc;h=7a663d3605687d60e139dd3ed0522ea54d3cab8d;hb=ebe12c095d5a5274feb5f4475b3782aa64a07d0a;hp=0afcc94abc526347dcf0bda342c7483d8f92883e;hpb=fc554a43712b76d16b41ec77dd311b4a78b1ef6b;p=swftools.git diff --git a/pdf2swf/xpdf/Stream.cc b/pdf2swf/xpdf/Stream.cc index 0afcc94..7a663d3 100644 --- a/pdf2swf/xpdf/Stream.cc +++ b/pdf2swf/xpdf/Stream.cc @@ -2,11 +2,13 @@ // // Stream.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif @@ -15,6 +17,8 @@ #include #ifndef WIN32 #include +#else +extern "C" int unlink(char *filename); #endif #include #include @@ -23,10 +27,12 @@ #include "config.h" #include "Error.h" #include "Object.h" -#ifndef NO_DECRYPTION +#include "Lexer.h" #include "Decrypt.h" -#endif +#include "GfxState.h" #include "Stream.h" +#include "JBIG2Stream.h" +#include "JPXStream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ @@ -34,9 +40,6 @@ static GBool setDJSYSFLAGS = gFalse; #endif #ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif #ifdef __GNUC__ #define SEEK_SET 0 #define SEEK_CUR 1 @@ -44,10 +47,6 @@ extern "C" int unlink(char *filename); #endif #endif -#ifdef MACOS -#include "StuffItEngineLib.h" -#endif - //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -88,7 +87,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(); } @@ -144,7 +143,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { int encoding; GBool endOfLine, byteAlign, endOfBlock, black; int columns, rows; - Object obj; + Object globals, obj; if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { str = new ASCIIHexStream(str); @@ -254,6 +253,14 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { obj.free(); } str = new FlateStream(str, pred, columns, colors, bits); + } else if (!strcmp(name, "JBIG2Decode")) { + if (params->isDict()) { + params->dictLookup("JBIG2Globals", &globals); + } + 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); @@ -265,33 +272,28 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { // BaseStream //------------------------------------------------------------------------ -BaseStream::BaseStream(Object *dict) { - this->dict = *dict; -#ifndef NO_DECRYPTION +BaseStream::BaseStream(Object *dictA) { + dict = *dictA; 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); +void BaseStream::doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen) { + decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); } -#endif //------------------------------------------------------------------------ // FilterStream //------------------------------------------------------------------------ -FilterStream::FilterStream(Stream *str) { - this->str = str; +FilterStream::FilterStream(Stream *strA) { + str = strA; } FilterStream::~FilterStream() { @@ -301,7 +303,7 @@ void FilterStream::close() { str->close(); } -void FilterStream::setPos(int pos) { +void FilterStream::setPos(Guint pos, int dir) { error(-1, "Internal: called setPos() on FilterStream"); } @@ -309,13 +311,13 @@ void FilterStream::setPos(int pos) { // 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) { @@ -323,7 +325,7 @@ ImageStream::ImageStream(Stream *str, int width, int nComps, int nBits) { } else { imgLineSize = nVals; } - imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar)); + imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar)); imgIdx = nVals; } @@ -336,51 +338,54 @@ void ImageStream::reset() { } GBool ImageStream::getPixel(Guchar *pix) { + int i; + + if (imgIdx >= nVals) { + getLine(); + imgIdx = 0; + } + for (i = 0; i < nComps; ++i) { + pix[i] = imgLine[imgIdx++]; + } + return gTrue; +} + +Guchar *ImageStream::getLine() { 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; + 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; + return imgLine; } void ImageStream::skipLine() { @@ -396,20 +401,35 @@ 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) { + int totalBits; + + str = strA; + predictor = predictorA; + width = widthA; + nComps = nCompsA; + nBits = nBitsA; + predLine = NULL; + ok = gFalse; nVals = width * nComps; + totalBits = nVals * nBits; + if (totalBits == 0 || + (totalBits / nBits) / nComps != width || + totalBits + 7 < 0) { + return; + } pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; + rowBytes = ((totalBits + 7) >> 3) + pixBytes; + if (rowBytes < 0) { + return; + } predLine = (Guchar *)gmalloc(rowBytes); memset(predLine, 0, rowBytes); predIdx = rowBytes; + + ok = gTrue; } StreamPredictor::~StreamPredictor() { @@ -436,15 +456,15 @@ int StreamPredictor::getChar() { GBool StreamPredictor::getNextLine() { int curPred; - Guchar upLeftBuf[4]; + Guchar upLeftBuf[gfxColorMaxComps * 2 + 1]; int left, up, upLeft, p, pa, pb, pc; int c; Gulong inBuf, outBuf, bitMask; int inBits, outBits; - int i, j, k; + int i, j, k, kk; // get PNG optimum predictor number - if (predictor == 15) { + if (predictor >= 10) { if ((curPred = str->getRawChar()) == EOF) { return gFalse; } @@ -454,14 +474,20 @@ GBool StreamPredictor::getNextLine() { } // read the raw line, apply PNG (byte) predictor - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; + memset(upLeftBuf, 0, pixBytes + 1); for (i = pixBytes; i < rowBytes; ++i) { - upLeftBuf[3] = upLeftBuf[2]; - upLeftBuf[2] = upLeftBuf[1]; - upLeftBuf[1] = upLeftBuf[0]; + for (j = pixBytes; j > 0; --j) { + upLeftBuf[j] = upLeftBuf[j-1]; + } upLeftBuf[0] = predLine[i]; if ((c = str->getRawChar()) == EOF) { - break; + if (i > pixBytes) { + // this ought to return false, but some (broken) PDF files + // contain truncated image data, and Adobe apparently reads the + // last partial line + break; + } + return gFalse; } switch (curPred) { case 11: // PNG sub @@ -486,11 +512,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 @@ -500,7 +526,6 @@ GBool StreamPredictor::getNextLine() { } // apply TIFF (component) predictor - //~ this is completely untested if (predictor == 2) { if (nBits == 1) { inBuf = predLine[pixBytes - 1]; @@ -514,30 +539,31 @@ GBool StreamPredictor::getNextLine() { predLine[i] += predLine[i - nComps]; } } else { - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; + memset(upLeftBuf, 0, nComps + 1); 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)); + for (i = 0; i < width; ++i) { + for (kk = 0; kk < nComps; ++kk) { + if (inBits < nBits) { + inBuf = (inBuf << 8) | (predLine[j++] & 0xff); + inBits += 8; + } + upLeftBuf[kk] = (upLeftBuf[kk] + + (inBuf >> (inBits - nBits))) & bitMask; + inBits -= nBits; + outBuf = (outBuf << nBits) | upLeftBuf[kk]; + outBits += nBits; + if (outBits >= 8) { + predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); + outBits -= 8; + } } } if (outBits > 0) { - predLine[k++] = (Guchar)(outBuf << (8 - outBits)); + predLine[k++] = (Guchar)((outBuf << (8 - outBits)) + + (inBuf & ((1 << (8 - outBits)) - 1))); } } } @@ -552,54 +578,69 @@ GBool StreamPredictor::getNextLine() { // FileStream //------------------------------------------------------------------------ -FileStream::FileStream(FILE *f, int start, int length, Object *dict): - BaseStream(dict) { - this->f = f; - this->start = start; - this->length = length; +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; + savePos = 0; + saved = gFalse; } FileStream::~FileStream() { close(); } -Stream *FileStream::makeSubStream(int start, int length, Object *dict) { - return new FileStream(f, start, length, dict); +Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, + Guint lengthA, Object *dictA) { + return new FileStream(f, startA, limitedA, lengthA, dictA); } void FileStream::reset() { - savePos = (int)ftell(f); +#if HAVE_FSEEKO + savePos = (Guint)ftello(f); + fseeko(f, start, SEEK_SET); +#elif 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 (savePos >= 0) { + if (saved) { +#if HAVE_FSEEKO + fseeko(f, savePos, SEEK_SET); +#elif HAVE_FSEEK64 + fseek64(f, savePos, SEEK_SET); +#else fseek(f, savePos, SEEK_SET); - savePos = -1; +#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 + fileStreamBufSize > start + length) { + if (limited && bufPos + fileStreamBufSize > start + length) { n = start + length - bufPos; } else { n = fileStreamBufSize; @@ -609,66 +650,194 @@ GBool FileStream::fillBuf() { 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) { - fseek(f, pos1, SEEK_SET); - bufPos = pos1; + if (dir >= 0) { +#if HAVE_FSEEKO + fseeko(f, pos, SEEK_SET); +#elif HAVE_FSEEK64 + fseek64(f, pos, SEEK_SET); +#else + fseek(f, pos, SEEK_SET); +#endif + bufPos = pos; } else { +#if HAVE_FSEEKO + fseeko(f, 0, SEEK_END); + size = (Guint)ftello(f); +#elif HAVE_FSEEK64 + fseek64(f, 0, SEEK_END); + size = (Guint)ftell64(f); +#else fseek(f, 0, SEEK_END); - size = ftell(f); - if (pos1 < -size) - pos1 = (int)(-size); - fseek(f, pos1, SEEK_END); - bufPos = (int)ftell(f); + 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_FSEEKO + fseeko(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftello(f); +#elif 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; } void FileStream::moveStart(int delta) { - this->start += delta; + start += delta; bufPtr = bufEnd = buf; bufPos = start; } //------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): + BaseStream(dictA) { + buf = bufA; + start = startA; + length = lengthA; + bufEnd = buf + start + length; + bufPtr = buf + start; + needFree = gFalse; +} + +MemStream::~MemStream() { + if (needFree) { + gfree(buf); + } +} + +Stream *MemStream::makeSubStream(Guint startA, GBool limited, + Guint lengthA, Object *dictA) { + MemStream *subStr; + Guint newLength; + + if (!limited || startA + lengthA > start + length) { + newLength = start + length - startA; + } else { + newLength = lengthA; + } + subStr = new MemStream(buf, startA, newLength, dictA); + return subStr; +} + +void MemStream::reset() { + bufPtr = buf + start; + if (decrypt) { + decrypt->reset(); + } +} + +void MemStream::close() { +} + +void MemStream::setPos(Guint pos, int dir) { + Guint i; + + if (dir >= 0) { + i = pos; + } else { + 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) { + start += delta; + length -= delta; + bufPtr = buf + start; +} + +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(length); + for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { + *q = (char)decrypt->decryptByte((Guchar)*p); + } + bufEnd = newBuf + length; + bufPtr = newBuf + (bufPtr - (buf + start)); + start = 0; + buf = newBuf; + needFree = gTrue; + } +} + +//------------------------------------------------------------------------ // EmbedStream //------------------------------------------------------------------------ -EmbedStream::EmbedStream(Stream *str, Object *dict): - BaseStream(dict) { - this->str = str; +EmbedStream::EmbedStream(Stream *strA, Object *dictA, + GBool limitedA, Guint lengthA): + BaseStream(dictA) { + str = strA; + limited = limitedA; + length = lengthA; } EmbedStream::~EmbedStream() { } -Stream *EmbedStream::makeSubStream(int start, int length, Object *dict) { +Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA) { error(-1, "Internal: called makeSubStream() on EmbedStream"); return NULL; } -void EmbedStream::setPos(int pos) { +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"); } -int EmbedStream::getStart() { +Guint EmbedStream::getStart() { error(-1, "Internal: called getStart() on EmbedStream"); return 0; } -void EmbedStream::moveStart(int start) { +void EmbedStream::moveStart(int delta) { error(-1, "Internal: called moveStart() on EmbedStream"); } @@ -676,8 +845,8 @@ void EmbedStream::moveStart(int start) { // ASCIIHexStream //------------------------------------------------------------------------ -ASCIIHexStream::ASCIIHexStream(Stream *str): - FilterStream(str) { +ASCIIHexStream::ASCIIHexStream(Stream *strA): + FilterStream(strA) { buf = EOF; eof = gFalse; } @@ -745,10 +914,15 @@ int ASCIIHexStream::lookChar() { return buf; } -GString *ASCIIHexStream::getPSFilter(char *indent) { +GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) { GString *s; - s = str->getPSFilter(indent); + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } s->append(indent)->append("/ASCIIHexDecode filter\n"); return s; } @@ -761,8 +935,8 @@ GBool ASCIIHexStream::isBinary(GBool last) { // ASCII85Stream //------------------------------------------------------------------------ -ASCII85Stream::ASCII85Stream(Stream *str): - FilterStream(str) { +ASCII85Stream::ASCII85Stream(Stream *strA): + FilterStream(strA) { index = n = 0; eof = gFalse; } @@ -787,7 +961,7 @@ int ASCII85Stream::lookChar() { index = 0; do { c[0] = str->getChar(); - } while (c[0] == '\n' || c[0] == '\r'); + } while (Lexer::isSpace(c[0])); if (c[0] == '~' || c[0] == EOF) { eof = gTrue; n = 0; @@ -799,7 +973,7 @@ int ASCII85Stream::lookChar() { for (k = 1; k < 5; ++k) { do { c[k] = str->getChar(); - } while (c[k] == '\n' || c[k] == '\r'); + } while (Lexer::isSpace(c[k])); if (c[k] == '~' || c[k] == EOF) break; } @@ -821,10 +995,15 @@ int ASCII85Stream::lookChar() { return b[index]; } -GString *ASCII85Stream::getPSFilter(char *indent) { +GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) { GString *s; - s = str->getPSFilter(indent); + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } s->append(indent)->append("/ASCII85Decode filter\n"); return s; } @@ -837,30 +1016,25 @@ GBool ASCII85Stream::isBinary(GBool last) { // LZWStream //------------------------------------------------------------------------ -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); +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); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } } else { pred = NULL; } - early = early1; - zPipe = NULL; - bufPtr = bufEnd = buf; + early = earlyA; + eof = gFalse; + inputBits = 0; + clearTable(); } LZWStream::~LZWStream() { - if (zPipe) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } if (pred) { delete pred; } @@ -871,276 +1045,156 @@ int LZWStream::getChar() { if (pred) { return pred->getChar(); } - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; } int LZWStream::lookChar() { if (pred) { return pred->lookChar(); } - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex]; } int LZWStream::getRawChar() { - return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; } void LZWStream::reset() { - FILE *f; - GString *zCmd; + str->reset(); + eof = gFalse; + inputBits = 0; + clearTable(); +} - //----- close old LZW stream - if (zPipe) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } +GBool LZWStream::processNextCode() { + int code; + int nextLength; + int i, j; - //----- tell Delorie runtime to spawn a new instance of COMMAND.COM - // to run gzip -#if __DJGPP__ - if (!setDJSYSFLAGS) { - setenv("DJSYSFLAGS", "0x0002", 0); - setDJSYSFLAGS = gTrue; + // check for EOF + if (eof) { + return gFalse; } -#endif - //----- create the .Z file - if (!openTempFile(&zName, &f, "wb", ".Z")) { - error(getPos(), "Couldn't create temporary file for LZW stream"); - return; + // check for eod and clear-table codes + start: + code = getCode(); + if (code == EOF || code == 257) { + eof = gTrue; + return gFalse; } - dumpFile(f); - fclose(f); - - //----- 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; + if (code == 256) { + clearTable(); + goto start; } -#else // HAVE_POPEN -#ifdef VMS - if (!system(zCmd->getCString())) { -#else - if (system(zCmd->getCString())) { -#endif - error(getPos(), "Couldn't execute '%s'", zCmd->getCString()); - unlink(zName->getCString()); - delete zName; - return; + if (nextCode >= 4097) { + error(getPos(), "Bad LZW stream - expected clear-table code"); + clearTable(); } - 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; + + // process the next code + nextLength = seqLength + 1; + if (code < 256) { + seqBuf[0] = code; + seqLength = 1; + } else if (code < nextCode) { + seqLength = table[code].length; + for (i = seqLength - 1, j = code; i > 0; --i) { + seqBuf[i] = table[j].tail; + j = table[j].head; + } + seqBuf[0] = j; + } else if (code == nextCode) { + seqBuf[seqLength] = newChar; + ++seqLength; + } else { + error(getPos(), "Bad LZW stream - unexpected code"); + eof = gTrue; + return gFalse; + } + newChar = seqBuf[0]; + if (first) { + first = gFalse; + } else { + table[nextCode].length = nextLength; + table[nextCode].head = prevCode; + table[nextCode].tail = newChar; + ++nextCode; + if (nextCode + early == 512) + nextBits = 10; + else if (nextCode + early == 1024) + nextBits = 11; + else if (nextCode + early == 2048) + nextBits = 12; } -#endif // HAVE_POPEN + prevCode = code; - //----- clean up - delete zCmd; + // reset buffer + seqIndex = 0; - //----- initialize buffer - bufPtr = bufEnd = buf; + return gTrue; } -void LZWStream::dumpFile(FILE *f) { - int outCodeBits; // size of output code - int outBits; // max output code - int outBuf[8]; // output buffer - int outData; // temporary output buffer - int inCode, outCode; // input and output codes - int nextCode; // next code index - GBool eof; // set when EOF is reached - GBool clear; // set if table needs to be cleared - GBool first; // indicates first code word after clear - int i, j; - - str->reset(); - - // magic number - fputc(0x1f, f); - fputc(0x9d, f); - - // max code length, block mode flag - fputc(0x8c, f); - - // init input side - inCodeBits = 9; - inputBuf = 0; - inputBits = 0; - eof = gFalse; - - // init output side - outCodeBits = 9; - - // clear table - first = gTrue; +void LZWStream::clearTable() { nextCode = 258; - - clear = gFalse; - do { - for (i = 0; i < 8; ++i) { - // check for table overflow - if (nextCode + early > 0x1001) { - inCode = 256; - - // read input code - } else { - do { - inCode = getCode(); - if (inCode == EOF) { - eof = gTrue; - inCode = 0; - } - } while (first && inCode == 256); - } - - // compute output code - if (inCode < 256) { - outCode = inCode; - } else if (inCode == 256) { - outCode = 256; - clear = gTrue; - } else if (inCode == 257) { - outCode = 0; - eof = gTrue; - } else { - outCode = inCode - 1; - } - outBuf[i] = outCode; - - // next code index - if (first) - first = gFalse; - else - ++nextCode; - - // check input code size - if (nextCode + early == 0x200) - inCodeBits = 10; - else if (nextCode + early == 0x400) { - inCodeBits = 11; - } else if (nextCode + early == 0x800) { - inCodeBits = 12; - } - - // check for eof/clear - if (eof) - break; - if (clear) { - i = 8; - break; - } - } - - // write output block - outData = 0; - outBits = 0; - j = 0; - while (j < i || outBits > 0) { - if (outBits < 8 && j < i) { - outData = outData | (outBuf[j++] << outBits); - outBits += outCodeBits; - } - fputc(outData & 0xff, f); - outData >>= 8; - outBits -= 8; - } - - // check output code size - if (nextCode - 1 == 512 || - nextCode - 1 == 1024 || - nextCode - 1 == 2048 || - nextCode - 1 == 4096) { - outCodeBits = inCodeBits; - } - - // clear table if necessary - if (clear) { - inCodeBits = 9; - outCodeBits = 9; - first = gTrue; - nextCode = 258; - clear = gFalse; - } - } while (!eof); + nextBits = 9; + seqIndex = seqLength = 0; + first = gTrue; } int LZWStream::getCode() { int c; int code; - while (inputBits < inCodeBits) { + while (inputBits < nextBits) { if ((c = str->getChar()) == EOF) return EOF; inputBuf = (inputBuf << 8) | (c & 0xff); inputBits += 8; } - code = (inputBuf >> (inputBits - inCodeBits)) & ((1 << inCodeBits) - 1); - inputBits -= inCodeBits; + code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); + inputBits -= nextBits; return code; } -GBool LZWStream::fillBuf() { - int n; - - if (!zPipe) - return gFalse; - if ((n = fread(buf, 1, 256, zPipe)) < 256) { -#ifdef HAVE_POPEN - pclose(zPipe); -#else - fclose(zPipe); -#endif - zPipe = NULL; - unlink(zName->getCString()); - delete zName; - } - bufPtr = buf; - bufEnd = buf + n; - return n > 0; -} - -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(psLevel, indent))) { return NULL; } - s = str->getPSFilter(indent); - s->append(indent)->append("/LZWDecode filter\n"); + s->append(indent)->append("<< "); + if (!early) { + s->append("/EarlyChange 0 "); + } + s->append(">> /LZWDecode filter\n"); return s; } @@ -1152,8 +1206,8 @@ GBool LZWStream::isBinary(GBool last) { // RunLengthStream //------------------------------------------------------------------------ -RunLengthStream::RunLengthStream(Stream *str): - FilterStream(str) { +RunLengthStream::RunLengthStream(Stream *strA): + FilterStream(strA) { bufPtr = bufEnd = buf; eof = gFalse; } @@ -1168,10 +1222,15 @@ void RunLengthStream::reset() { eof = gFalse; } -GString *RunLengthStream::getPSFilter(char *indent) { +GString *RunLengthStream::getPSFilter(int psLevel, char *indent) { GString *s; - s = str->getPSFilter(indent); + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } s->append(indent)->append("/RunLengthDecode filter\n"); return s; } @@ -1210,19 +1269,22 @@ GBool RunLengthStream::fillBuf() { // CCITTFaxStream //------------------------------------------------------------------------ -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 + 3) * sizeof(short)); - codingLine = (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; + if (columns < 1) { + columns = 1; + } + rows = rowsA; + endOfBlock = endOfBlockA; + black = blackA; + refLine = (short *)gmallocn(columns + 4, sizeof(short)); + codingLine = (short *)gmallocn(columns + 3, sizeof(short)); eof = gFalse; row = 0; @@ -1242,7 +1304,7 @@ CCITTFaxStream::~CCITTFaxStream() { } void CCITTFaxStream::reset() { - int n; + short code1; str->reset(); eof = gFalse; @@ -1254,16 +1316,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); @@ -1274,10 +1333,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; @@ -1287,9 +1343,7 @@ int CCITTFaxStream::lookChar() { } // read the next row -#if 0 //~ err = gFalse; -#endif if (codingLine[a0] >= columns) { // 2-D encoding @@ -1326,12 +1380,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]; @@ -1350,10 +1406,12 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL1: - a0New = codingLine[++a0] = refLine[b1] - 1; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; + if (a0 == 0 || refLine[b1] - 1 > a0New) { + a0New = codingLine[++a0] = refLine[b1] - 1; + --b1; + while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + b1 += 2; + } break; case twoDimVertR2: a0New = codingLine[++a0] = refLine[b1] + 2; @@ -1364,10 +1422,12 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL2: - a0New = codingLine[++a0] = refLine[b1] - 2; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; + if (a0 == 0 || refLine[b1] - 2 > a0New) { + a0New = codingLine[++a0] = refLine[b1] - 2; + --b1; + while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + b1 += 2; + } break; case twoDimVertR3: a0New = codingLine[++a0] = refLine[b1] + 3; @@ -1378,10 +1438,12 @@ int CCITTFaxStream::lookChar() { } break; case twoDimVertL3: - a0New = codingLine[++a0] = refLine[b1] - 3; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; + if (a0 == 0 || refLine[b1] - 3 > a0New) { + a0New = codingLine[++a0] = refLine[b1] - 3; + --b1; + while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + b1 += 2; + } break; case EOF: eof = gTrue; @@ -1389,13 +1451,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); @@ -1424,9 +1481,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 @@ -1482,30 +1542,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]; @@ -1716,11 +1771,16 @@ 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]; - s = str->getPSFilter(indent); + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } s->append(indent)->append("<< "); if (encoding != 0) { sprintf(s1, "/K %d ", encoding); @@ -1757,7 +1817,6 @@ GBool CCITTFaxStream::isBinary(GBool last) { //------------------------------------------------------------------------ // IDCT constants (20.12 fixed point format) -#ifndef FP_IDCT #define dctCos1 4017 // cos(pi/16) #define dctSin1 799 // sin(pi/16) #define dctCos3 3406 // cos(3*pi/16) @@ -1766,19 +1825,6 @@ GBool CCITTFaxStream::isBinary(GBool last) { #define dctSin6 3784 // sin(6*pi/16) #define dctSqrt2 5793 // sqrt(2) #define dctSqrt1d2 2896 // sqrt(2) / 2 -#endif - -// IDCT constants -#ifdef FP_IDCT -#define dctCos1 0.98078528 // cos(pi/16) -#define dctSin1 0.19509032 // sin(pi/16) -#define dctCos3 0.83146961 // cos(3*pi/16) -#define dctSin3 0.55557023 // sin(3*pi/16) -#define dctCos6 0.38268343 // cos(6*pi/16) -#define dctSin6 0.92387953 // sin(6*pi/16) -#define dctSqrt2 1.41421356 // sqrt(2) -#define dctSqrt1d2 0.70710678 // sqrt(2) / 2 -#endif // color conversion parameters (16.16 fixed point format) #define dctCrToR 91881 // 1.4020 @@ -1810,18 +1856,22 @@ static int dctZigZag[64] = { 63 }; -DCTStream::DCTStream(Stream *str): - FilterStream(str) { +DCTStream::DCTStream(Stream *strA): + FilterStream(strA) { int i, j; + progressive = interleaved = gFalse; width = height = 0; mcuWidth = mcuHeight = 0; numComps = 0; comp = 0; x = y = dy = 0; - for (i = 0; i < 4; ++i) - for (j = 0; j < 32; ++j) + for (i = 0; i < 4; ++i) { + for (j = 0; j < 32; ++j) { rowBuf[i][j] = NULL; + } + frameBuf[i] = NULL; + } if (!dctClipInit) { for (i = -256; i < 0; ++i) @@ -1838,53 +1888,174 @@ DCTStream::~DCTStream() { int i, j; delete str; - for (i = 0; i < numComps; ++i) - for (j = 0; j < mcuHeight; ++j) - gfree(rowBuf[i][j]); + if (progressive || !interleaved) { + for (i = 0; i < numComps; ++i) { + gfree(frameBuf[i]); + } + } else { + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + gfree(rowBuf[i][j]); + } + } + } } void DCTStream::reset() { + int i, j; + str->reset(); + + progressive = interleaved = gFalse; + width = height = 0; + numComps = 0; + numQuantTables = 0; + numDCHuffTables = 0; + numACHuffTables = 0; + colorXform = 0; + gotJFIFMarker = gFalse; + gotAdobeMarker = gFalse; + restartInterval = 0; + if (!readHeader()) { y = height; return; } - restartMarker = 0xd0; - restart(); + + // compute MCU size + if (numComps == 1) { + compInfo[0].hSample = compInfo[0].vSample = 1; + } + mcuWidth = compInfo[0].hSample; + mcuHeight = compInfo[0].vSample; + for (i = 1; i < numComps; ++i) { + if (compInfo[i].hSample > mcuWidth) { + mcuWidth = compInfo[i].hSample; + } + if (compInfo[i].vSample > mcuHeight) { + mcuHeight = compInfo[i].vSample; + } + } + mcuWidth *= 8; + mcuHeight *= 8; + + // figure out color transform + if (!gotAdobeMarker && numComps == 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; + } + } + + if (progressive || !interleaved) { + + // allocate a buffer for the whole image + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; + for (i = 0; i < numComps; ++i) { + frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int)); + memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); + } + + // read the image data + do { + restartMarker = 0xd0; + restart(); + readScan(); + } while (readHeader()); + + // decode + decodeImage(); + + // initialize counters + comp = 0; + x = 0; + y = 0; + + } else { + + // allocate a buffer for one row of MCUs + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar)); + } + } + + // initialize counters + comp = 0; + x = 0; + y = 0; + dy = mcuHeight; + + restartMarker = 0xd0; + restart(); + } } int DCTStream::getChar() { int c; - c = lookChar(); - if (c == EOF) + if (y >= height) { return EOF; - if (++comp == numComps) { - comp = 0; - if (++x == width) { + } + if (progressive || !interleaved) { + c = frameBuf[comp][y * bufWidth + x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + } + } + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; x = 0; - ++y; - ++dy; + dy = 0; + } + c = rowBuf[comp][dy][x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + ++dy; + if (y == height) { + readTrailer(); + } + } } } - if (y == height) - readTrailer(); return c; } int DCTStream::lookChar() { - if (y >= height) + if (y >= height) { return EOF; - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; + } + if (progressive || !interleaved) { + return frameBuf[comp][y * bufWidth + x]; + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; } - comp = 0; - x = 0; - dy = 0; + return rowBuf[comp][dy][x]; } - return rowBuf[comp][dy][x]; } void DCTStream::restart() { @@ -1892,12 +2063,16 @@ void DCTStream::restart() { inputBits = 0; restartCtr = restartInterval; - for (i = 0; i < numComps; ++i) + for (i = 0; i < numComps; ++i) { compInfo[i].prevDC = 0; + } + eobRun = 0; } +// Read one row of MCUs from a sequential JPEG stream. GBool DCTStream::readMCURow() { - Guchar data[64]; + int data1[64]; + Guchar data2[64]; Guchar *p1, *p2; int pY, pCb, pCr, pR, pG, pB; int h, v, horiz, vert, hSub, vSub; @@ -1928,36 +2103,38 @@ GBool DCTStream::readMCURow() { vSub = vert / 8; for (y2 = 0; y2 < mcuHeight; y2 += vert) { for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - if (!readDataUnit(&dcHuffTables[compInfo[cc].dcHuffTable], - &acHuffTables[compInfo[cc].acHuffTable], - quantTables[compInfo[cc].quantTable], + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], &compInfo[cc].prevDC, - data)) + data1)) { return gFalse; + } + transformDataUnit(quantTables[compInfo[cc].quantTable], + data1, data2); if (hSub == 1 && vSub == 1) { for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; - p1[0] = data[i]; - p1[1] = data[i+1]; - p1[2] = data[i+2]; - p1[3] = data[i+3]; - p1[4] = data[i+4]; - p1[5] = data[i+5]; - p1[6] = data[i+6]; - p1[7] = data[i+7]; + p1[0] = data2[i]; + p1[1] = data2[i+1]; + p1[2] = data2[i+2]; + p1[3] = data2[i+3]; + p1[4] = data2[i+4]; + p1[5] = data2[i+5]; + p1[6] = data2[i+6]; + p1[7] = data2[i+7]; } } else if (hSub == 2 && vSub == 2) { for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; p2 = &rowBuf[cc][y2+y3+1][x1+x2]; - p1[0] = p1[1] = p2[0] = p2[1] = data[i]; - p1[2] = p1[3] = p2[2] = p2[3] = data[i+1]; - p1[4] = p1[5] = p2[4] = p2[5] = data[i+2]; - p1[6] = p1[7] = p2[6] = p2[7] = data[i+3]; - p1[8] = p1[9] = p2[8] = p2[9] = data[i+4]; - p1[10] = p1[11] = p2[10] = p2[11] = data[i+5]; - p1[12] = p1[13] = p2[12] = p2[13] = data[i+6]; - p1[14] = p1[15] = p2[14] = p2[15] = data[i+7]; + p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; + p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; + p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; + p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; + p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; + p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; + p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; + p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; } } else { i = 0; @@ -1965,7 +2142,7 @@ GBool DCTStream::readMCURow() { for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { for (y5 = 0; y5 < vSub; ++y5) for (x5 = 0; x5 < hSub; ++x5) - rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data[i]; + rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; ++i; } } @@ -2001,7 +2178,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]; @@ -2013,71 +2190,469 @@ GBool DCTStream::readMCURow() { return gTrue; } -// This IDCT algorithm is taken from: -// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, -// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", -// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, -// 988-991. -// The stage numbers mentioned in the comments refer to Figure 1 in this -// paper. -#ifndef FP_IDCT +// Read one scan from a progressive or non-interleaved JPEG stream. +void DCTStream::readScan() { + int data[64]; + int x1, y1, dx1, dy1, x2, y2, y3, cc, i; + int h, v, horiz, vert, vSub; + int *p1; + int c; + + if (scanInfo.numComps == 1) { + for (cc = 0; cc < numComps; ++cc) { + if (scanInfo.comp[cc]) { + break; + } + } + dx1 = mcuWidth / compInfo[cc].hSample; + dy1 = mcuHeight / compInfo[cc].vSample; + } else { + dx1 = mcuWidth; + dy1 = mcuHeight; + } + + for (y1 = 0; y1 < height; y1 += dy1) { + for (x1 = 0; x1 < width; x1 += dx1) { + + // deal with restart marker + if (restartInterval > 0 && restartCtr == 0) { + c = readMarker(); + if (c != restartMarker) { + error(getPos(), "Bad DCT data: incorrect restart marker"); + return; + } + if (++restartMarker == 0xd8) { + restartMarker = 0xd0; + } + restart(); + } + + // read one MCU + for (cc = 0; cc < numComps; ++cc) { + if (!scanInfo.comp[cc]) { + continue; + } + + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + vSub = vert / 8; + for (y2 = 0; y2 < dy1; y2 += vert) { + for (x2 = 0; x2 < dx1; x2 += horiz) { + + // pull out the current values + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + data[i] = p1[0]; + data[i+1] = p1[1]; + data[i+2] = p1[2]; + data[i+3] = p1[3]; + data[i+4] = p1[4]; + data[i+5] = p1[5]; + data[i+6] = p1[6]; + data[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // read one data unit + if (progressive) { + if (!readProgressiveDataUnit( + &dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } else { + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } + + // add the data unit into frameBuf + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = data[i]; + p1[1] = data[i+1]; + p1[2] = data[i+2]; + p1[3] = data[i+3]; + p1[4] = data[i+4]; + p1[5] = data[i+5]; + p1[6] = data[i+6]; + p1[7] = data[i+7]; + p1 += bufWidth * vSub; + } + } + } + } + --restartCtr; + } + } +} + +// Read one data unit from a sequential JPEG stream. GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, - Guchar data[64]) { - int tmp1[64]; - int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *prevDC, int data[64]) { int run, size, amp; int c; int i, j; - // Huffman decode and dequantize - size = readHuffSym(dcHuffTable); - if (size == 9999) + if ((size = readHuffSym(dcHuffTable)) == 9999) { return gFalse; + } if (size > 0) { - amp = readAmp(size); - if (amp == 9999) + if ((amp = readAmp(size)) == 9999) { return gFalse; + } } else { amp = 0; } - tmp1[0] = (*prevDC += amp) * quantTable[0]; - for (i = 1; i < 64; ++i) - tmp1[i] = 0; + data[0] = *prevDC += amp; + for (i = 1; i < 64; ++i) { + data[i] = 0; + } i = 1; while (i < 64) { run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) + while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { run += 0x10; - if (c == 9999) + } + if (c == 9999) { return gFalse; + } if (c == 0x00) { break; } else { run += (c >> 4) & 0x0f; size = c & 0x0f; amp = readAmp(size); - if (amp == 9999) + if (amp == 9999) { return gFalse; + } i += run; + if (i < 64) { + j = dctZigZag[i++]; + data[j] = amp; + } + } + } + return gTrue; +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp, bit, c; + int i, j, k; + + // get the DC coefficient + i = scanInfo.firstCoeff; + if (i == 0) { + if (scanInfo.ah == 0) { + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] += (*prevDC += amp) << scanInfo.al; + } else { + if ((bit = readBit()) == 9999) { + return gFalse; + } + data[0] += bit << scanInfo.al; + } + ++i; + } + if (scanInfo.lastCoeff == 0) { + return gTrue; + } + + // check for an EOB run + if (eobRun > 0) { + while (i <= scanInfo.lastCoeff) { j = dctZigZag[i++]; - tmp1[j] = amp * quantTable[j]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } } + --eobRun; + return gTrue; + } + + // read the AC coefficients + while (i <= scanInfo.lastCoeff) { + if ((c = readHuffSym(acHuffTable)) == 9999) { + return gFalse; + } + + // ZRL + if (c == 0xf0) { + k = 0; + while (k < 16) { + j = dctZigZag[i++]; + if (data[j] == 0) { + ++k; + } else { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + + // EOB run + } else if ((c & 0x0f) == 0x00) { + j = c >> 4; + eobRun = 0; + for (k = 0; k < j; ++k) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + eobRun = (eobRun << 1) | bit; + } + eobRun += 1 << j; + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + break; + + // zero run and one AC coefficient + } else { + run = (c >> 4) & 0x0f; + size = c & 0x0f; + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + k = 0; + do { + j = dctZigZag[i++]; + while (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + j = dctZigZag[i++]; + } + ++k; + } while (k <= run); + data[j] = amp << scanInfo.al; + } + } + + return gTrue; +} + +// Decode a progressive JPEG image. +void DCTStream::decodeImage() { + int dataIn[64]; + Guchar dataOut[64]; + Gushort *quantTable; + int pY, pCb, pCr, pR, pG, pB; + int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; + int h, v, horiz, vert, hSub, vSub; + int *p0, *p1, *p2; + + for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { + for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (cc = 0; cc < numComps; ++cc) { + quantTable = quantTables[compInfo[cc].quantTable]; + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + hSub = horiz / 8; + vSub = vert / 8; + for (y2 = 0; y2 < mcuHeight; y2 += vert) { + for (x2 = 0; x2 < mcuWidth; x2 += horiz) { + + // pull out the coded data unit + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + dataIn[i] = p1[0]; + dataIn[i+1] = p1[1]; + dataIn[i+2] = p1[2]; + dataIn[i+3] = p1[3]; + dataIn[i+4] = p1[4]; + dataIn[i+5] = p1[5]; + dataIn[i+6] = p1[6]; + dataIn[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // transform + transformDataUnit(quantTable, dataIn, dataOut); + + // store back into frameBuf, doing replication for + // subsampled components + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = dataOut[i] & 0xff; + p1[1] = dataOut[i+1] & 0xff; + p1[2] = dataOut[i+2] & 0xff; + p1[3] = dataOut[i+3] & 0xff; + p1[4] = dataOut[i+4] & 0xff; + p1[5] = dataOut[i+5] & 0xff; + p1[6] = dataOut[i+6] & 0xff; + p1[7] = dataOut[i+7] & 0xff; + p1 += bufWidth; + } + } else if (hSub == 2 && vSub == 2) { + p2 = p1 + bufWidth; + for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { + p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; + p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; + p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; + p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; + p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; + p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; + p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; + p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; + p1 += bufWidth * 2; + p2 += bufWidth * 2; + } + } else { + i = 0; + for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { + for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { + p2 = p1 + x4; + for (y5 = 0; y5 < vSub; ++y5) { + for (x5 = 0; x5 < hSub; ++x5) { + p2[x5] = dataOut[i] & 0xff; + } + p2 += bufWidth; + } + ++i; + } + p1 += bufWidth * vSub; + } + } + } + } + } + + // color space conversion + if (colorXform) { + // convert YCbCr to RGB + if (numComps == 3) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = dctClip[dctClipOffset + pB]; + } + } + // convert YCbCrK to CMYK (K is passed through unchanged) + } else if (numComps == 4) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = 255 - dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = 255 - dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = 255 - dctClip[dctClipOffset + pB]; + } + } + } + } + } + } +} + +// Transform one data unit -- this performs the dequantization and +// IDCT steps. This IDCT algorithm is taken from: +// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, +// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", +// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, +// 988-991. +// The stage numbers mentioned in the comments refer to Figure 1 in this +// paper. +void DCTStream::transformDataUnit(Gushort *quantTable, + int dataIn[64], Guchar dataOut[64]) { + int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *p; + int i; + + // dequant + for (i = 0; i < 64; ++i) { + dataIn[i] *= quantTable[i]; } // inverse DCT on rows for (i = 0; i < 64; i += 8) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1] == 0 && p[2] == 0 && p[3] == 0 && + p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { + t = (dctSqrt2 * p[0] + 512) >> 10; + p[0] = t; + p[1] = t; + p[2] = t; + p[3] = t; + p[4] = t; + p[5] = t; + p[6] = t; + p[7] = t; + continue; + } // stage 4 - v0 = (dctSqrt2 * tmp1[i+0] + 128) >> 8; - v1 = (dctSqrt2 * tmp1[i+4] + 128) >> 8; - v2 = tmp1[i+2]; - v3 = tmp1[i+6]; - v4 = (dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]) + 128) >> 8; - v7 = (dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]) + 128) >> 8; - v5 = tmp1[i+3] << 4; - v6 = tmp1[i+5] << 4; + v0 = (dctSqrt2 * p[0] + 128) >> 8; + v1 = (dctSqrt2 * p[4] + 128) >> 8; + v2 = p[2]; + v3 = p[6]; + v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; + v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; + v5 = p[3] << 4; + v6 = p[5] << 4; // stage 3 t = (v0 - v1+ 1) >> 1; @@ -2108,233 +2683,89 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, v6 = t; // stage 1 - tmp1[i+0] = v0 + v7; - tmp1[i+7] = v0 - v7; - tmp1[i+1] = v1 + v6; - tmp1[i+6] = v1 - v6; - tmp1[i+2] = v2 + v5; - tmp1[i+5] = v2 - v5; - tmp1[i+3] = v3 + v4; - tmp1[i+4] = v3 - v4; + p[0] = v0 + v7; + p[7] = v0 - v7; + p[1] = v1 + v6; + p[6] = v1 - v6; + p[2] = v2 + v5; + p[5] = v2 - v5; + p[3] = v3 + v4; + p[4] = v3 - v4; } // inverse DCT on columns for (i = 0; i < 8; ++i) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && + p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { + t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; + p[0*8] = t; + p[1*8] = t; + p[2*8] = t; + p[3*8] = t; + p[4*8] = t; + p[5*8] = t; + p[6*8] = t; + p[7*8] = t; + continue; + } // stage 4 - v0 = (dctSqrt2 * tmp1[0*8+i] + 2048) >> 12; - v1 = (dctSqrt2 * tmp1[4*8+i] + 2048) >> 12; - v2 = tmp1[2*8+i]; - v3 = tmp1[6*8+i]; - v4 = (dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]) + 2048) >> 12; - v7 = (dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]) + 2048) >> 12; - v5 = tmp1[3*8+i]; - v6 = tmp1[5*8+i]; + v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; + v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; + v2 = p[2*8]; + v3 = p[6*8]; + v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; + v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; + v5 = p[3*8]; + v6 = p[5*8]; // stage 3 t = (v0 - v1 + 1) >> 1; v0 = (v0 + v1 + 1) >> 1; v1 = t; - t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; - v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; - v3 = t; - t = (v4 - v6 + 1) >> 1; - v4 = (v4 + v6 + 1) >> 1; - v6 = t; - t = (v7 + v5 + 1) >> 1; - v5 = (v7 - v5 + 1) >> 1; - v7 = t; - - // stage 2 - t = (v0 - v3 + 1) >> 1; - v0 = (v0 + v3 + 1) >> 1; - v3 = t; - t = (v1 - v2 + 1) >> 1; - v1 = (v1 + v2 + 1) >> 1; - v2 = t; - t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; - v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; - v7 = t; - t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; - v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; - v6 = t; - - // stage 1 - tmp1[0*8+i] = v0 + v7; - tmp1[7*8+i] = v0 - v7; - tmp1[1*8+i] = v1 + v6; - tmp1[6*8+i] = v1 - v6; - tmp1[2*8+i] = v2 + v5; - tmp1[5*8+i] = v2 - v5; - tmp1[3*8+i] = v3 + v4; - tmp1[4*8+i] = v3 - v4; - } - - // convert to 8-bit integers - for (i = 0; i < 64; ++i) - data[i] = dctClip[dctClipOffset + 128 + ((tmp1[i] + 8) >> 4)]; - - return gTrue; -} -#endif - -#ifdef FP_IDCT -GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - Guchar quantTable[64], int *prevDC, - Guchar data[64]) { - double tmp1[64]; - double v0, v1, v2, v3, v4, v5, v6, v7, t; - int run, size, amp; - int c; - int i, j; - - // Huffman decode and dequantize - size = readHuffSym(dcHuffTable); - if (size == 9999) - return gFalse; - if (size > 0) { - amp = readAmp(size); - if (amp == 9999) - return gFalse; - } else { - amp = 0; - } - tmp1[0] = (*prevDC += amp) * quantTable[0]; - for (i = 1; i < 64; ++i) - tmp1[i] = 0; - i = 1; - while (i < 64) { - run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) - run += 0x10; - if (c == 9999) - return gFalse; - if (c == 0x00) { - break; - } else { - run += (c >> 4) & 0x0f; - size = c & 0x0f; - amp = readAmp(size); - if (amp == 9999) - return gFalse; - i += run; - j = dctZigZag[i++]; - tmp1[j] = amp * quantTable[j]; - } - } - - // inverse DCT on rows - for (i = 0; i < 64; i += 8) { - - // stage 4 - v0 = dctSqrt2 * tmp1[i+0]; - v1 = dctSqrt2 * tmp1[i+4]; - v2 = tmp1[i+2]; - v3 = tmp1[i+6]; - v4 = dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]); - v7 = dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]); - v5 = tmp1[i+3]; - v6 = tmp1[i+5]; - - // stage 3 - t = 0.5 * (v0 - v1); - v0 = 0.5 * (v0 + v1); - v1 = t; - t = v2 * dctSin6 + v3 * dctCos6; - v2 = v2 * dctCos6 - v3 * dctSin6; - v3 = t; - t = 0.5 * (v4 - v6); - v4 = 0.5 * (v4 + v6); - v6 = t; - t = 0.5 * (v7 + v5); - v5 = 0.5 * (v7 - v5); - v7 = t; - - // stage 2 - t = 0.5 * (v0 - v3); - v0 = 0.5 * (v0 + v3); - v3 = t; - t = 0.5 * (v1 - v2); - v1 = 0.5 * (v1 + v2); - v2 = t; - t = v4 * dctSin3 + v7 * dctCos3; - v4 = v4 * dctCos3 - v7 * dctSin3; - v7 = t; - t = v5 * dctSin1 + v6 * dctCos1; - v5 = v5 * dctCos1 - v6 * dctSin1; - v6 = t; - - // stage 1 - tmp1[i+0] = v0 + v7; - tmp1[i+7] = v0 - v7; - tmp1[i+1] = v1 + v6; - tmp1[i+6] = v1 - v6; - tmp1[i+2] = v2 + v5; - tmp1[i+5] = v2 - v5; - tmp1[i+3] = v3 + v4; - tmp1[i+4] = v3 - v4; - } - - // inverse DCT on columns - for (i = 0; i < 8; ++i) { - - // stage 4 - v0 = dctSqrt2 * tmp1[0*8+i]; - v1 = dctSqrt2 * tmp1[4*8+i]; - v2 = tmp1[2*8+i]; - v3 = tmp1[6*8+i]; - v4 = dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]); - v7 = dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]); - v5 = tmp1[3*8+i]; - v6 = tmp1[5*8+i]; - - // stage 3 - t = 0.5 * (v0 - v1); - v0 = 0.5 * (v0 + v1); - v1 = t; - t = v2 * dctSin6 + v3 * dctCos6; - v2 = v2 * dctCos6 - v3 * dctSin6; + t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; + v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; v3 = t; - t = 0.5 * (v4 - v6); - v4 = 0.5 * (v4 + v6); + t = (v4 - v6 + 1) >> 1; + v4 = (v4 + v6 + 1) >> 1; v6 = t; - t = 0.5 * (v7 + v5); - v5 = 0.5 * (v7 - v5); + t = (v7 + v5 + 1) >> 1; + v5 = (v7 - v5 + 1) >> 1; v7 = t; // stage 2 - t = 0.5 * (v0 - v3); - v0 = 0.5 * (v0 + v3); + t = (v0 - v3 + 1) >> 1; + v0 = (v0 + v3 + 1) >> 1; v3 = t; - t = 0.5 * (v1 - v2); - v1 = 0.5 * (v1 + v2); + t = (v1 - v2 + 1) >> 1; + v1 = (v1 + v2 + 1) >> 1; v2 = t; - t = v4 * dctSin3 + v7 * dctCos3; - v4 = v4 * dctCos3 - v7 * dctSin3; + t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; + v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; v7 = t; - t = v5 * dctSin1 + v6 * dctCos1; - v5 = v5 * dctCos1 - v6 * dctSin1; + t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; + v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; v6 = t; // stage 1 - tmp1[0*8+i] = v0 + v7; - tmp1[7*8+i] = v0 - v7; - tmp1[1*8+i] = v1 + v6; - tmp1[6*8+i] = v1 - v6; - tmp1[2*8+i] = v2 + v5; - tmp1[5*8+i] = v2 - v5; - tmp1[3*8+i] = v3 + v4; - tmp1[4*8+i] = v3 - v4; + p[0*8] = v0 + v7; + p[7*8] = v0 - v7; + p[1*8] = v1 + v6; + p[6*8] = v1 - v6; + p[2*8] = v2 + v5; + p[5*8] = v2 - v5; + p[3*8] = v3 + v4; + p[4*8] = v3 - v4; } // convert to 8-bit integers - for (i = 0; i < 64; ++i) - data[i] = dctClip[dctClipOffset + (int)(tmp1[i] + 128.5)]; - - return gTrue; + for (i = 0; i < 64; ++i) { + dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; + } } -#endif int DCTStream::readHuffSym(DCTHuffTable *table) { Gushort code; @@ -2402,52 +2833,60 @@ int DCTStream::readBit() { GBool DCTStream::readHeader() { GBool doScan; - int minHSample, minVSample; - int bufWidth; int n; int c = 0; - int i, j; - - width = height = 0; - numComps = 0; - numQuantTables = 0; - numDCHuffTables = 0; - numACHuffTables = 0; - colorXform = 0; - gotAdobeMarker = gFalse; - restartInterval = 0; + int i; // read headers doScan = gFalse; while (!doScan) { c = readMarker(); switch (c) { - case 0xc0: // SOF0 - if (!readFrameInfo()) + case 0xc0: // SOF0 (sequential) + case 0xc1: // SOF1 (extended sequential) + if (!readBaselineSOF()) { + return gFalse; + } + break; + case 0xc2: // SOF2 (progressive) + if (!readProgressiveSOF()) { return gFalse; + } break; case 0xc4: // DHT - if (!readHuffmanTables()) + if (!readHuffmanTables()) { return gFalse; + } break; case 0xd8: // SOI break; + case 0xd9: // EOI + return gFalse; case 0xda: // SOS - if (!readScanInfo()) + if (!readScanInfo()) { return gFalse; + } doScan = gTrue; break; case 0xdb: // DQT - if (!readQuantTables()) + if (!readQuantTables()) { return gFalse; + } break; case 0xdd: // DRI - if (!readRestartInterval()) + if (!readRestartInterval()) { + return gFalse; + } + break; + case 0xe0: // APP0 + if (!readJFIFMarker()) { return gFalse; + } break; case 0xee: // APP14 - if (!readAdobeMarker()) + if (!readAdobeMarker()) { return gFalse; + } break; case EOF: error(getPos(), "Bad DCT header"); @@ -2456,8 +2895,9 @@ GBool DCTStream::readHeader() { // skip APPn / COM / etc. if (c >= 0xe0) { n = read16() - 2; - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { str->getChar(); + } } else { error(getPos(), "Unknown DCT marker <%02x>", c); return gFalse; @@ -2466,127 +2906,143 @@ GBool DCTStream::readHeader() { } } - // compute MCU size - mcuWidth = minHSample = compInfo[0].hSample; - mcuHeight = minVSample = compInfo[0].vSample; - for (i = 1; i < numComps; ++i) { - if (compInfo[i].hSample < minHSample) - minHSample = compInfo[i].hSample; - if (compInfo[i].vSample < minVSample) - minVSample = compInfo[i].vSample; - if (compInfo[i].hSample > mcuWidth) - mcuWidth = compInfo[i].hSample; - if (compInfo[i].vSample > mcuHeight) - mcuHeight = compInfo[i].vSample; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].hSample /= minHSample; - compInfo[i].vSample /= minVSample; - } - mcuWidth = (mcuWidth / minHSample) * 8; - mcuHeight = (mcuHeight / minVSample) * 8; + return gTrue; +} - // allocate buffers - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - for (i = 0; i < numComps; ++i) - for (j = 0; j < mcuHeight; ++j) - rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); +GBool DCTStream::readBaselineSOF() { + int length; + int prec; + int i; + int c; - // figure out color transform - if (!gotAdobeMarker && numComps == 3) { - if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { - colorXform = 1; - } + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream", prec); + return gFalse; } - - // initialize counters - comp = 0; - x = 0; - y = 0; - dy = mcuHeight; - + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream", prec); + return gFalse; + } + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; + } + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gFalse; return gTrue; } -GBool DCTStream::readFrameInfo() { +GBool DCTStream::readProgressiveSOF() { int length; int prec; int i; int c; - length = read16() - 2; + length = read16(); prec = str->getChar(); height = read16(); width = read16(); numComps = str->getChar(); - length -= 6; if (prec != 8) { error(getPos(), "Bad DCT precision %d", prec); return gFalse; } for (i = 0; i < numComps; ++i) { compInfo[i].id = str->getChar(); - compInfo[i].inScan = gFalse; c = str->getChar(); compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); - compInfo[i].dcHuffTable = 0; - compInfo[i].acHuffTable = 0; } + progressive = gTrue; return gTrue; } GBool DCTStream::readScanInfo() { int length; - int scanComps, id, c; + int id, c; int i, j; length = read16() - 2; - scanComps = str->getChar(); + scanInfo.numComps = str->getChar(); --length; - if (length != 2 * scanComps + 3) { + if (length != 2 * scanInfo.numComps + 3) { error(getPos(), "Bad DCT scan info block"); return gFalse; } - for (i = 0; i < scanComps; ++i) { + interleaved = scanInfo.numComps == numComps; + for (j = 0; j < numComps; ++j) { + scanInfo.comp[j] = gFalse; + } + for (i = 0; i < scanInfo.numComps; ++i) { id = str->getChar(); - 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; + // 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; + } } - compInfo[j].inScan = gTrue; + scanInfo.comp[j] = gTrue; c = str->getChar(); - compInfo[j].dcHuffTable = (c >> 4) & 0x0f; - compInfo[j].acHuffTable = c & 0x0f; + scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; + scanInfo.acHuffTable[j] = c & 0x0f; } - str->getChar(); - str->getChar(); - str->getChar(); + scanInfo.firstCoeff = str->getChar(); + scanInfo.lastCoeff = str->getChar(); + c = str->getChar(); + scanInfo.ah = (c >> 4) & 0x0f; + scanInfo.al = c & 0x0f; return gTrue; } GBool DCTStream::readQuantTables() { - int length; - int i; - int index; + int length, prec, i, index; length = read16() - 2; while (length > 0) { index = str->getChar(); - if ((index & 0xf0) || index >= 4) { + prec = (index >> 4) & 0x0f; + index &= 0x0f; + if (prec > 1 || index >= 4) { error(getPos(), "Bad DCT quantization table"); return gFalse; } - if (index == numQuantTables) + if (index == numQuantTables) { numQuantTables = index + 1; - for (i = 0; i < 64; ++i) - quantTables[index][dctZigZag[i]] = str->getChar(); - length -= 65; + } + for (i = 0; i < 64; ++i) { + if (prec) { + quantTables[index][dctZigZag[i]] = read16(); + } else { + quantTables[index][dctZigZag[i]] = str->getChar(); + } + } + if (prec) { + length -= 129; + } else { + length -= 65; + } } return gTrue; } @@ -2648,23 +3104,61 @@ 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]; int c; length = read16(); - if (length != 14) + if (length < 14) { goto err; + } for (i = 0; i < 12; ++i) { - if ((c = str->getChar()) == EOF) + if ((c = str->getChar()) == EOF) { goto err; + } buf[i] = c; } - if (strncmp(buf, "Adobe", 5)) + if (strncmp(buf, "Adobe", 5)) { goto err; + } colorXform = buf[11]; gotAdobeMarker = gTrue; + for (i = 14; i < length; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } return gTrue; err: @@ -2689,7 +3183,7 @@ int DCTStream::readMarker() { do { do { c = str->getChar(); - } while (c != 0xff); + } while (c != 0xff && c != EOF); do { c = str->getChar(); } while (c == 0xff); @@ -2707,10 +3201,15 @@ int DCTStream::read16() { return (c1 << 8) + c2; } -GString *DCTStream::getPSFilter(char *indent) { +GString *DCTStream::getPSFilter(int psLevel, char *indent) { GString *s; - s = str->getPSFilter(indent); + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } s->append(indent)->append("<< >> /DCTDecode filter\n"); return s; } @@ -2756,6 +3255,8 @@ FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { {5, 163}, {5, 195}, {5, 227}, + {0, 258}, + {0, 258}, {0, 258} }; @@ -2792,17 +3293,587 @@ FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { {13, 24577} }; -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); +static FlateCode flateFixedLitCodeTabCodes[512] = { + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c0}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a0}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e0}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0090}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d0}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b0}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f0}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c8}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a8}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e8}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0098}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d8}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b8}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f8}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c4}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a4}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e4}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0094}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d4}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b4}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f4}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cc}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ac}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ec}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009c}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dc}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bc}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fc}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c2}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a2}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e2}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0092}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d2}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b2}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f2}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00ca}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00aa}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00ea}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009a}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00da}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00ba}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fa}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c6}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a6}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e6}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0096}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d6}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b6}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f6}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00ce}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00ae}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ee}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009e}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00de}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00be}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00fe}, + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c1}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a1}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e1}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0091}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d1}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b1}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f1}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c9}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a9}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e9}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0099}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d9}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b9}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f9}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c5}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a5}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e5}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0095}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d5}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b5}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f5}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cd}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ad}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ed}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009d}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dd}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bd}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fd}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c3}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a3}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e3}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0093}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d3}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b3}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f3}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00cb}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00ab}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00eb}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009b}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00db}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00bb}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fb}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c7}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a7}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e7}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0097}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d7}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b7}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f7}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00cf}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00af}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ef}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009f}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00df}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00bf}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00ff} +}; + +FlateHuffmanTab FlateStream::fixedLitCodeTab = { + flateFixedLitCodeTabCodes, 9 +}; + +static FlateCode flateFixedDistCodeTabCodes[32] = { + {5, 0x0000}, + {5, 0x0010}, + {5, 0x0008}, + {5, 0x0018}, + {5, 0x0004}, + {5, 0x0014}, + {5, 0x000c}, + {5, 0x001c}, + {5, 0x0002}, + {5, 0x0012}, + {5, 0x000a}, + {5, 0x001a}, + {5, 0x0006}, + {5, 0x0016}, + {5, 0x000e}, + {0, 0x0000}, + {5, 0x0001}, + {5, 0x0011}, + {5, 0x0009}, + {5, 0x0019}, + {5, 0x0005}, + {5, 0x0015}, + {5, 0x000d}, + {5, 0x001d}, + {5, 0x0003}, + {5, 0x0013}, + {5, 0x000b}, + {5, 0x001b}, + {5, 0x0007}, + {5, 0x0017}, + {5, 0x000f}, + {0, 0x0000} +}; + +FlateHuffmanTab FlateStream::fixedDistCodeTab = { + flateFixedDistCodeTabCodes, 5 +}; + +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); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } } else { pred = NULL; } + litCodeTab.codes = NULL; + distCodeTab.codes = NULL; } FlateStream::~FlateStream() { + if (litCodeTab.codes != fixedLitCodeTab.codes) { + gfree(litCodeTab.codes); + } + if (distCodeTab.codes != fixedDistCodeTab.codes) { + gfree(distCodeTab.codes); + } if (pred) { delete pred; } @@ -2891,8 +3962,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) { @@ -2969,6 +4049,16 @@ GBool FlateStream::startBlock() { int c; int check; + // free the code tables from the previous block + if (litCodeTab.codes != fixedLitCodeTab.codes) { + gfree(litCodeTab.codes); + } + litCodeTab.codes = NULL; + if (distCodeTab.codes != fixedDistCodeTab.codes) { + gfree(distCodeTab.codes); + } + distCodeTab.codes = NULL; + // read block header blockHdr = getCodeWord(3); if (blockHdr & 1) @@ -3003,8 +4093,9 @@ GBool FlateStream::startBlock() { // compressed block with dynamic codes } else if (blockHdr == 2) { compressedBlock = gTrue; - if (!readDynamicCodes()) + if (!readDynamicCodes()) { goto err; + } // unknown block type } else { @@ -3021,188 +4112,180 @@ err: } void FlateStream::loadFixedCodes() { - int i; - - // set up code arrays - litCodeTab.codes = allCodes; - distCodeTab.codes = allCodes + flateMaxLitCodes; - - // initialize literal code table - for (i = 0; i <= 143; ++i) - litCodeTab.codes[i].len = 8; - for (i = 144; i <= 255; ++i) - litCodeTab.codes[i].len = 9; - for (i = 256; i <= 279; ++i) - litCodeTab.codes[i].len = 7; - for (i = 280; i <= 287; ++i) - litCodeTab.codes[i].len = 8; - compHuffmanCodes(&litCodeTab, flateMaxLitCodes); - - // initialize distance code table - for (i = 0; i <= 5; ++i) { - distCodeTab.start[i] = 0; - } - 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; - distCodeTab.codes[i].val = i; - } + litCodeTab.codes = fixedLitCodeTab.codes; + litCodeTab.maxLen = fixedLitCodeTab.maxLen; + distCodeTab.codes = fixedDistCodeTab.codes; + distCodeTab.maxLen = fixedDistCodeTab.maxLen; } GBool FlateStream::readDynamicCodes() { int numCodeLenCodes; int numLitCodes; int numDistCodes; - FlateCode codeLenCodes[flateMaxCodeLenCodes]; + int codeLenCodeLengths[flateMaxCodeLenCodes]; FlateHuffmanTab codeLenCodeTab; int len, repeat, code; int i; + codeLenCodeTab.codes = NULL; + // read lengths - if ((numLitCodes = getCodeWord(5)) == EOF) + if ((numLitCodes = getCodeWord(5)) == EOF) { goto err; + } numLitCodes += 257; - if ((numDistCodes = getCodeWord(5)) == EOF) + if ((numDistCodes = getCodeWord(5)) == EOF) { goto err; + } numDistCodes += 1; - if ((numCodeLenCodes = getCodeWord(4)) == EOF) + if ((numCodeLenCodes = getCodeWord(4)) == EOF) { goto err; + } numCodeLenCodes += 4; if (numLitCodes > flateMaxLitCodes || numDistCodes > flateMaxDistCodes || - numCodeLenCodes > flateMaxCodeLenCodes) + numCodeLenCodes > flateMaxCodeLenCodes) { goto err; + } - // read code length code table - codeLenCodeTab.codes = codeLenCodes; - for (i = 0; i < flateMaxCodeLenCodes; ++i) - codeLenCodes[i].len = 0; + // build the code length code table + for (i = 0; i < flateMaxCodeLenCodes; ++i) { + codeLenCodeLengths[i] = 0; + } for (i = 0; i < numCodeLenCodes; ++i) { - if ((codeLenCodes[codeLenCodeMap[i]].len = getCodeWord(3)) == -1) + if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { goto err; + } } - compHuffmanCodes(&codeLenCodeTab, flateMaxCodeLenCodes); - - // set up code arrays - litCodeTab.codes = allCodes; - distCodeTab.codes = allCodes + numLitCodes; + compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); - // read literal and distance code tables + // build the literal and distance code tables len = 0; repeat = 0; i = 0; while (i < numLitCodes + numDistCodes) { - if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) + if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { goto err; + } if (code == 16) { - if ((repeat = getCodeWord(2)) == EOF) + if ((repeat = getCodeWord(2)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { goto err; - for (repeat += 3; repeat > 0; --repeat) - allCodes[i++].len = len; + } + for (; repeat > 0; --repeat) { + codeLengths[i++] = len; + } } else if (code == 17) { - if ((repeat = getCodeWord(3)) == EOF) + if ((repeat = getCodeWord(3)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { goto err; + } len = 0; - for (repeat += 3; repeat > 0; --repeat) - allCodes[i++].len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } } else if (code == 18) { - if ((repeat = getCodeWord(7)) == EOF) + if ((repeat = getCodeWord(7)) == EOF) { + goto err; + } + repeat += 11; + if (i + repeat > numLitCodes + numDistCodes) { goto err; + } len = 0; - for (repeat += 11; repeat > 0; --repeat) - allCodes[i++].len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } } else { - allCodes[i++].len = len = code; + codeLengths[i++] = len = code; } } - compHuffmanCodes(&litCodeTab, numLitCodes); - compHuffmanCodes(&distCodeTab, numDistCodes); + compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); + compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); + gfree(codeLenCodeTab.codes); return gTrue; err: error(getPos(), "Bad dynamic code table in flate stream"); + gfree(codeLenCodeTab.codes); return gFalse; } -// On entry, the codes> array contains the lengths of each code, -// stored in code value order. This function computes the code words. -// The result is sorted in order of (1) code length and (2) code word. -// The length values are no longer valid. The start> array is -// filled with the indexes of the first code of each length. -void FlateStream::compHuffmanCodes(FlateHuffmanTab *tab, int n) { - int numLengths[flateMaxHuffman+1]; - int nextCode[flateMaxHuffman+1]; - int nextIndex[flateMaxHuffman+2]; - int code; - int i, j; +// Convert an array of lengths, in value order, into a +// Huffman code lookup table. +void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { + int tabSize, len, code, code2, skip, val, i, t; - // count number of codes for each code length - for (i = 0; i <= flateMaxHuffman; ++i) - numLengths[i] = 0; - for (i = 0; i < n; ++i) - ++numLengths[tab->codes[i].len]; + // find max code length + tab->maxLen = 0; + for (val = 0; val < n; ++val) { + if (lengths[val] > tab->maxLen) { + tab->maxLen = lengths[val]; + } + } - // compute first index for each length - tab->start[0] = nextIndex[0] = 0; - for (i = 1; i <= flateMaxHuffman + 1; ++i) - tab->start[i] = nextIndex[i] = tab->start[i-1] + numLengths[i-1]; + // allocate the table + tabSize = 1 << tab->maxLen; + tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode)); - // compute first code for each length - code = 0; - numLengths[0] = 0; - for (i = 1; i <= flateMaxHuffman; ++i) { - code = (code + numLengths[i-1]) << 1; - nextCode[i] = code; + // clear the table + for (i = 0; i < tabSize; ++i) { + tab->codes[i].len = 0; + tab->codes[i].val = 0; } - // compute the codes -- this permutes the codes array from value - // order to length/code order - for (i = 0; i < n; ++i) { - j = nextIndex[tab->codes[i].len]++; - if (tab->codes[i].len == 0) - tab->codes[j].code = 0; - else - tab->codes[j].code = nextCode[tab->codes[i].len]++; - tab->codes[j].val = i; + // build the table + for (len = 1, code = 0, skip = 2; + len <= tab->maxLen; + ++len, code <<= 1, skip <<= 1) { + for (val = 0; val < n; ++val) { + if (lengths[val] == len) { + + // bit-reverse the code + code2 = 0; + t = code; + for (i = 0; i < len; ++i) { + code2 = (code2 << 1) | (t & 1); + t >>= 1; + } + + // fill in the table entries + for (i = code2; i < tabSize; i += skip) { + tab->codes[i].len = (Gushort)len; + tab->codes[i].val = (Gushort)val; + } + + ++code; + } + } } } int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { - int len; - int code; + FlateCode *code; int c; - int i, j; - - code = 0; - for (len = 1; len <= flateMaxHuffman; ++len) { - - // add a bit to the code - if (codeSize == 0) { - if ((c = str->getChar()) == EOF) - return EOF; - codeBuf = c & 0xff; - codeSize = 8; - } - code = (code << 1) | (codeBuf & 1); - codeBuf >>= 1; - --codeSize; - // look for code - i = tab->start[len]; - j = tab->start[len + 1]; - if (i < j && code >= tab->codes[i].code && code <= tab->codes[j-1].code) { - i += code - tab->codes[i].code; - return tab->codes[i].val; + while (codeSize < tab->maxLen) { + if ((c = str->getChar()) == EOF) { + break; } + codeBuf |= (c & 0xff) << codeSize; + codeSize += 8; } - - // not found - error(getPos(), "Bad code (%04x) in flate stream", code); - return EOF; + code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; + if (codeSize == 0 || codeSize < code->len || code->len == 0) { + return EOF; + } + codeBuf >>= code->len; + codeSize -= code->len; + return (int)code->val; } int FlateStream::getCodeWord(int bits) { @@ -3224,8 +4307,8 @@ int FlateStream::getCodeWord(int bits) { // EOFStream //------------------------------------------------------------------------ -EOFStream::EOFStream(Stream *str): - FilterStream(str) { +EOFStream::EOFStream(Stream *strA): + FilterStream(strA) { } EOFStream::~EOFStream() { @@ -3236,9 +4319,9 @@ EOFStream::~EOFStream() { // FixedLengthEncoder //------------------------------------------------------------------------ -FixedLengthEncoder::FixedLengthEncoder(Stream *str, int length1): - FilterStream(str) { - length = length1; +FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): + FilterStream(strA) { + length = lengthA; count = 0; } @@ -3252,9 +4335,6 @@ void FixedLengthEncoder::reset() { count = 0; } -void FixedLengthEncoder::close() { -} - int FixedLengthEncoder::getChar() { if (length >= 0 && count >= length) return EOF; @@ -3268,12 +4348,63 @@ int FixedLengthEncoder::lookChar() { return str->getChar(); } +GBool FixedLengthEncoder::isBinary(GBool last) { + return str->isBinary(gTrue); +} + +//------------------------------------------------------------------------ +// 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; +} + +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 *str): - FilterStream(str) { +ASCII85Encoder::ASCII85Encoder(Stream *strA): + FilterStream(strA) { bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; @@ -3291,9 +4422,6 @@ void ASCII85Encoder::reset() { eof = gFalse; } -void ASCII85Encoder::close() { -} - GBool ASCII85Encoder::fillBuf() { Gulong t; char buf1[5]; @@ -3344,8 +4472,8 @@ GBool ASCII85Encoder::fillBuf() { // RunLengthEncoder //------------------------------------------------------------------------ -RunLengthEncoder::RunLengthEncoder(Stream *str): - FilterStream(str) { +RunLengthEncoder::RunLengthEncoder(Stream *strA): + FilterStream(strA) { bufPtr = bufEnd = nextEnd = buf; eof = gFalse; } @@ -3361,9 +4489,6 @@ void RunLengthEncoder::reset() { eof = gFalse; } -void RunLengthEncoder::close() { -} - // // When fillBuf finishes, buf[] looks like this: // +-----+--------------+-----------------+--