//======================================================================== // // Stream.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== //======================================================================== // // Modified under the Poppler project - http://poppler.freedesktop.org // // All changes made under the Poppler project to this file are licensed // under GPL version 2 or later // // Copyright (C) 2005 Jeff Muizelaar // Copyright (C) 2008 Julien Rebetez // Copyright (C) 2008, 2010, 2011, 2016-2020 Albert Astals Cid // Copyright (C) 2009 Carlos Garcia Campos // Copyright (C) 2009 Stefan Thomas // Copyright (C) 2010 Hib Eris // Copyright (C) 2011, 2012, 2016, 2020 William Bader // Copyright (C) 2012, 2013 Thomas Freitag // Copyright (C) 2012, 2013 Fabio D'Urso // Copyright (C) 2013, 2017 Adrian Johnson // Copyright (C) 2013 Peter Breitenlohner // Copyright (C) 2013, 2018 Adam Reichold // Copyright (C) 2013 Pino Toscano // Copyright (C) 2019 Volker Krause // Copyright (C) 2019 Alexander Volkov // Copyright (C) 2020 Oliver Sander // Copyright (C) 2020 Philipp Knechtges // // To see a description of the changes please see the Changelog file that // came with your tarball or type make ChangeLog if you are building from git // //======================================================================== #ifndef STREAM_H #define STREAM_H #include #include #include "poppler-config.h" #include "Object.h" class GooFile; class BaseStream; class CachedFile; #ifdef HAVE_SPLASH class SplashBitmap; #endif //------------------------------------------------------------------------ enum StreamKind { strFile, strCachedFile, strASCIIHex, strASCII85, strLZW, strRunLength, strCCITTFax, strDCT, strFlate, strJBIG2, strJPX, strWeird, // internal-use stream types strCrypt // internal-use to detect decode streams }; enum StreamColorSpaceMode { streamCSNone, streamCSDeviceGray, streamCSDeviceRGB, streamCSDeviceCMYK }; //------------------------------------------------------------------------ // This is in Stream.h instead of Decrypt.h to avoid really annoying // include file dependency loops. enum CryptAlgorithm { cryptRC4, cryptAES, cryptAES256, cryptNone }; //------------------------------------------------------------------------ typedef struct _ByteRange { unsigned int offset; unsigned int length; } ByteRange; //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ class Stream { public: // Constructor. Stream(); // Destructor. virtual ~Stream(); Stream(const Stream &) = delete; Stream &operator=(const Stream &other) = delete; // Get kind of stream. virtual StreamKind getKind() const = 0; // Reset stream to beginning. virtual void reset() = 0; // Close down the stream. virtual void close(); inline int doGetChars(int nChars, unsigned char *buffer) { if (hasGetChars()) { return getChars(nChars, buffer); } else { for (int i = 0; i < nChars; ++i) { const int c = getChar(); if (likely(c != EOF)) buffer[i] = c; else return i; } return nChars; } } inline void fillString(std::string &s) { unsigned char readBuf[4096]; int readChars; reset(); while ((readChars = doGetChars(4096, readBuf)) != 0) { s.append((const char *)readBuf, readChars); } } inline void fillGooString(GooString *s) { fillString(s->toNonConstStr()); } inline unsigned char *toUnsignedChars(int *length, int initialSize = 4096, int sizeIncrement = 4096) { int readChars; unsigned char *buf = (unsigned char *)gmalloc(initialSize); int size = initialSize; *length = 0; int charsToRead = initialSize; bool continueReading = true; reset(); while (continueReading && (readChars = doGetChars(charsToRead, &buf[*length])) != 0) { *length += readChars; if (readChars == charsToRead) { if (lookChar() != EOF) { size += sizeIncrement; charsToRead = sizeIncrement; buf = (unsigned char *)grealloc(buf, size); } else { continueReading = false; } } else { continueReading = false; } } return buf; } // Get next char from stream. virtual int getChar() = 0; // Peek at next char in stream. virtual int lookChar() = 0; // Get next char from stream without using the predictor. // This is only used by StreamPredictor. virtual int getRawChar(); virtual void getRawChars(int nChars, int *buffer); // Get next char directly from stream source, without filtering it virtual int getUnfilteredChar() = 0; // Resets the stream without reading anything (even not the headers) // WARNING: Reading the stream with something else than getUnfilteredChar // may lead to unexcepted behaviour until you call reset () virtual void unfilteredReset() = 0; // Get next line from stream. virtual char *getLine(char *buf, int size); // Get current position in file. virtual Goffset getPos() = 0; // Go to a position in the stream. If is negative, the // position is from the end of the file; otherwise the position is // from the start of the file. virtual void setPos(Goffset pos, int dir = 0) = 0; // Get PostScript command for the filter(s). virtual GooString *getPSFilter(int psLevel, const char *indent); // Does this stream type potentially contain non-printable chars? virtual bool isBinary(bool last = true) = 0; // Get the BaseStream of this stream. virtual BaseStream *getBaseStream() = 0; // Get the stream after the last decoder (this may be a BaseStream // or a DecryptStream). virtual Stream *getUndecodedStream() = 0; // Get the dictionary associated with this stream. virtual Dict *getDict() = 0; virtual Object *getDictObject() = 0; // Is this an encoding filter? virtual bool isEncoder() { return false; } // Get image parameters which are defined by the stream contents. virtual void getImageParams(int * /*bitsPerComponent*/, StreamColorSpaceMode * /*csMode*/) { } // Return the next stream in the "stack". virtual Stream *getNextStream() const { return nullptr; } // Add filters to this stream according to the parameters in . // Returns the new stream. Stream *addFilters(Dict *dict, int recursion = 0); // Returns true if this stream includes a crypt filter. bool isEncrypted() const; private: friend class Object; // for incRef/decRef // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } virtual bool hasGetChars() { return false; } virtual int getChars(int nChars, unsigned char *buffer); Stream *makeFilter(const char *name, Stream *str, Object *params, int recursion = 0, Dict *dict = nullptr); std::atomic_int ref; // reference count }; //------------------------------------------------------------------------ // OutStream // // This is the base class for all streams that output to a file //------------------------------------------------------------------------ class OutStream { public: // Constructor. OutStream(); // Desctructor. virtual ~OutStream(); OutStream(const OutStream &) = delete; OutStream &operator=(const OutStream &other) = delete; // Close the stream virtual void close() = 0; // Return position in stream virtual Goffset getPos() = 0; // Put a char in the stream virtual void put(char c) = 0; virtual void printf(const char *format, ...) GCC_PRINTF_FORMAT(2, 3) = 0; }; //------------------------------------------------------------------------ // FileOutStream //------------------------------------------------------------------------ class FileOutStream : public OutStream { public: FileOutStream(FILE *fa, Goffset startA); ~FileOutStream() override; void close() override; Goffset getPos() override; void put(char c) override; void printf(const char *format, ...) override GCC_PRINTF_FORMAT(2, 3); private: FILE *f; Goffset start; }; //------------------------------------------------------------------------ // BaseStream // // This is the base class for all streams that read directly from a file. //------------------------------------------------------------------------ class BaseStream : public Stream { public: // TODO Mirar si puedo hacer que dictA sea un puntero BaseStream(Object &&dictA, Goffset lengthA); ~BaseStream() override; virtual BaseStream *copy() = 0; virtual Stream *makeSubStream(Goffset start, bool limited, Goffset length, Object &&dict) = 0; void setPos(Goffset pos, int dir = 0) override = 0; bool isBinary(bool last = true) override { return last; } BaseStream *getBaseStream() override { return this; } Stream *getUndecodedStream() override { return this; } Dict *getDict() override { return dict.getDict(); } Object *getDictObject() override { return &dict; } virtual GooString *getFileName() { return nullptr; } virtual Goffset getLength() { return length; } // Get/set position of first byte of stream within the file. virtual Goffset getStart() = 0; virtual void moveStart(Goffset delta) = 0; protected: Goffset length; Object dict; }; //------------------------------------------------------------------------ // BaseInputStream //------------------------------------------------------------------------ class BaseSeekInputStream : public BaseStream { public: // This enum is used to tell the seek() method how it must reposition // the stream offset. enum SeekType { SeekSet, // the offset is set to offset bytes SeekCur, // the offset is set to its current location plus offset bytes SeekEnd // the offset is set to the size of the stream plus offset bytes }; BaseSeekInputStream(Goffset startA, bool limitedA, Goffset lengthA, Object &&dictA); ~BaseSeekInputStream() override; StreamKind getKind() const override { return strWeird; } void reset() override; void close() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } Goffset getPos() override { return bufPos + (bufPtr - buf); } void setPos(Goffset pos, int dir = 0) override; Goffset getStart() override { return start; } void moveStart(Goffset delta) override; int getUnfilteredChar() override { return getChar(); } void unfilteredReset() override { reset(); } protected: Goffset start; bool limited; private: bool fillBuf(); bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override; virtual Goffset currentPos() const = 0; virtual void setCurrentPos(Goffset offset) = 0; virtual Goffset read(char *buf, Goffset size) = 0; static constexpr int seekInputStreamBufSize = 1024; char buf[seekInputStreamBufSize]; char *bufPtr; char *bufEnd; Goffset bufPos; Goffset savePos; bool saved; }; //------------------------------------------------------------------------ // FilterStream // // This is the base class for all streams that filter another stream. //------------------------------------------------------------------------ class FilterStream : public Stream { public: FilterStream(Stream *strA); ~FilterStream() override; void close() override; Goffset getPos() override { return str->getPos(); } void setPos(Goffset pos, int dir = 0) override; BaseStream *getBaseStream() override { return str->getBaseStream(); } Stream *getUndecodedStream() override { return str->getUndecodedStream(); } Dict *getDict() override { return str->getDict(); } Object *getDictObject() override { return str->getDictObject(); } Stream *getNextStream() const override { return str; } int getUnfilteredChar() override { return str->getUnfilteredChar(); } void unfilteredReset() override { str->unfilteredReset(); } protected: Stream *str; }; //------------------------------------------------------------------------ // ImageStream //------------------------------------------------------------------------ class ImageStream { public: // Create an image stream object for an image with the specified // parameters. Note that these are the actual image parameters, // which may be different from the predictor parameters. ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA); ~ImageStream(); ImageStream(const ImageStream &) = delete; ImageStream &operator=(const ImageStream &other) = delete; // Reset the stream. void reset(); // Close the stream previously reset void close(); // Gets the next pixel from the stream. should be able to hold // at least nComps elements. Returns false at end of file. bool getPixel(unsigned char *pix); // Returns a pointer to the next line of pixels. Returns NULL at // end of file. unsigned char *getLine(); // Skip an entire line from the image. void skipLine(); private: Stream *str; // base stream int width; // pixels per line int nComps; // components per pixel int nBits; // bits per component int nVals; // components per line int inputLineSize; // input line buffer size unsigned char *inputLine; // input line buffer unsigned char *imgLine; // line buffer int imgIdx; // current index in imgLine }; //------------------------------------------------------------------------ // StreamPredictor //------------------------------------------------------------------------ class StreamPredictor { public: // Create a predictor object. Note that the parameters are for the // predictor, and may not match the actual image parameters. StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA); ~StreamPredictor(); StreamPredictor(const StreamPredictor &) = delete; StreamPredictor &operator=(const StreamPredictor &) = delete; bool isOk() { return ok; } int lookChar(); int getChar(); int getChars(int nChars, unsigned char *buffer); private: bool getNextLine(); Stream *str; // base stream int predictor; // predictor int width; // pixels per line int nComps; // components per pixel int nBits; // bits per component int nVals; // components per line int pixBytes; // bytes per pixel int rowBytes; // bytes per line unsigned char *predLine; // line buffer int predIdx; // current index in predLine bool ok; }; //------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ #define fileStreamBufSize 256 class FileStream : public BaseStream { public: FileStream(GooFile *fileA, Goffset startA, bool limitedA, Goffset lengthA, Object &&dictA); ~FileStream() override; BaseStream *copy() override; Stream *makeSubStream(Goffset startA, bool limitedA, Goffset lengthA, Object &&dictA) override; StreamKind getKind() const override { return strFile; } void reset() override; void close() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } Goffset getPos() override { return bufPos + (bufPtr - buf); } void setPos(Goffset pos, int dir = 0) override; Goffset getStart() override { return start; } void moveStart(Goffset delta) override; int getUnfilteredChar() override { return getChar(); } void unfilteredReset() override { reset(); } bool getNeedsEncryptionOnSave() const { return needsEncryptionOnSave; } void setNeedsEncryptionOnSave(bool needsEncryptionOnSaveA) { needsEncryptionOnSave = needsEncryptionOnSaveA; } private: bool fillBuf(); bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override { int n, m; n = 0; while (n < nChars) { if (bufPtr >= bufEnd) { if (!fillBuf()) { break; } } m = (int)(bufEnd - bufPtr); if (m > nChars - n) { m = nChars - n; } memcpy(buffer + n, bufPtr, m); bufPtr += m; n += m; } return n; } private: GooFile *file; Goffset offset; Goffset start; bool limited; char buf[fileStreamBufSize]; char *bufPtr; char *bufEnd; Goffset bufPos; Goffset savePos; bool saved; bool needsEncryptionOnSave; // Needed for FileStreams that point to "external" files // and thus when saving we can't do a raw copy }; //------------------------------------------------------------------------ // CachedFileStream //------------------------------------------------------------------------ #define cachedStreamBufSize 1024 class CachedFileStream : public BaseStream { public: CachedFileStream(CachedFile *ccA, Goffset startA, bool limitedA, Goffset lengthA, Object &&dictA); ~CachedFileStream() override; BaseStream *copy() override; Stream *makeSubStream(Goffset startA, bool limitedA, Goffset lengthA, Object &&dictA) override; StreamKind getKind() const override { return strCachedFile; } void reset() override; void close() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } Goffset getPos() override { return bufPos + (bufPtr - buf); } void setPos(Goffset pos, int dir = 0) override; Goffset getStart() override { return start; } void moveStart(Goffset delta) override; int getUnfilteredChar() override { return getChar(); } void unfilteredReset() override { reset(); } private: bool fillBuf(); CachedFile *cc; Goffset start; bool limited; char buf[cachedStreamBufSize]; char *bufPtr; char *bufEnd; unsigned int bufPos; int savePos; bool saved; }; //------------------------------------------------------------------------ // MemStream //------------------------------------------------------------------------ template class BaseMemStream : public BaseStream { public: BaseMemStream(T *bufA, Goffset startA, Goffset lengthA, Object &&dictA) : BaseStream(std::move(dictA), lengthA) { buf = bufA; start = startA; length = lengthA; bufEnd = buf + start + length; bufPtr = buf + start; } BaseStream *copy() override { return new BaseMemStream(buf, start, length, dict.copy()); } Stream *makeSubStream(Goffset startA, bool limited, Goffset lengthA, Object &&dictA) override { Goffset newLength; if (!limited || startA + lengthA > start + length) { newLength = start + length - startA; } else { newLength = lengthA; } return new BaseMemStream(buf, startA, newLength, std::move(dictA)); } StreamKind getKind() const override { return strWeird; } void reset() override { bufPtr = buf + start; } void close() override { } int getChar() override { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } int lookChar() override { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } Goffset getPos() override { return (int)(bufPtr - buf); } void setPos(Goffset pos, int dir = 0) override { unsigned int 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; } Goffset getStart() override { return start; } void moveStart(Goffset delta) override { start += delta; length -= delta; bufPtr = buf + start; } int getUnfilteredChar() override { return getChar(); } void unfilteredReset() override { reset(); } protected: T *buf; private: bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override { int n; if (unlikely(nChars <= 0)) { return 0; } if (unlikely(bufPtr >= bufEnd)) { return 0; } if (bufEnd - bufPtr < nChars) { n = (int)(bufEnd - bufPtr); } else { n = nChars; } memcpy(buffer, bufPtr, n); bufPtr += n; return n; } Goffset start; T *bufEnd; T *bufPtr; }; class MemStream : public BaseMemStream { public: MemStream(const char *bufA, Goffset startA, Goffset lengthA, Object &&dictA) : BaseMemStream(bufA, startA, lengthA, std::move(dictA)) { } ~MemStream() override; }; class AutoFreeMemStream : public BaseMemStream { public: AutoFreeMemStream(char *bufA, Goffset startA, Goffset lengthA, Object &&dictA) : BaseMemStream(bufA, startA, lengthA, std::move(dictA)) { } ~AutoFreeMemStream() override; }; //------------------------------------------------------------------------ // EmbedStream // // This is a special stream type used for embedded streams (inline // images). It reads directly from the base stream -- after the // EmbedStream is deleted, reads from the base stream will proceed where // the BaseStream left off. Note that this is very different behavior // that creating a new FileStream (using makeSubStream). //------------------------------------------------------------------------ class EmbedStream : public BaseStream { public: EmbedStream(Stream *strA, Object &&dictA, bool limitedA, Goffset lengthA, bool reusableA = false); ~EmbedStream() override; BaseStream *copy() override; Stream *makeSubStream(Goffset start, bool limitedA, Goffset lengthA, Object &&dictA) override; StreamKind getKind() const override { return str->getKind(); } void reset() override; int getChar() override; int lookChar() override; Goffset getPos() override; void setPos(Goffset pos, int dir = 0) override; Goffset getStart() override; void moveStart(Goffset delta) override; int getUnfilteredChar() override { return str->getUnfilteredChar(); } void unfilteredReset() override { str->unfilteredReset(); } void rewind(); void restore(); private: bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override; Stream *str; bool limited; bool reusable; bool record; bool replay; unsigned char *bufData; long bufMax; long bufLen; long bufPos; Goffset start; }; //------------------------------------------------------------------------ // ASCIIHexStream //------------------------------------------------------------------------ class ASCIIHexStream : public FilterStream { public: ASCIIHexStream(Stream *strA); ~ASCIIHexStream() override; StreamKind getKind() const override { return strASCIIHex; } void reset() override; int getChar() override { int c = lookChar(); buf = EOF; return c; } int lookChar() override; GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; private: int buf; bool eof; }; //------------------------------------------------------------------------ // ASCII85Stream //------------------------------------------------------------------------ class ASCII85Stream : public FilterStream { public: ASCII85Stream(Stream *strA); ~ASCII85Stream() override; StreamKind getKind() const override { return strASCII85; } void reset() override; int getChar() override { int ch = lookChar(); ++index; return ch; } int lookChar() override; GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; private: int c[5]; int b[4]; int index, n; bool eof; }; //------------------------------------------------------------------------ // LZWStream //------------------------------------------------------------------------ class LZWStream : public FilterStream { public: LZWStream(Stream *strA, int predictor, int columns, int colors, int bits, int earlyA); ~LZWStream() override; StreamKind getKind() const override { return strLZW; } void reset() override; int getChar() override; int lookChar() override; int getRawChar() override; void getRawChars(int nChars, int *buffer) override; GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; private: bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override; inline int doGetRawChar() { if (eof) { return EOF; } if (seqIndex >= seqLength) { if (!processNextCode()) { return EOF; } } return seqBuf[seqIndex++]; } StreamPredictor *pred; // predictor int early; // early parameter bool eof; // true if at eof unsigned int inputBuf; // input buffer int inputBits; // number of bits in input buffer struct { // decoding table int length; int head; unsigned char tail; } table[4097]; int nextCode; // next code to be used int nextBits; // number of bits in next code word int prevCode; // previous code used in stream int newChar; // next char to be added to table unsigned char seqBuf[4097]; // buffer for current sequence int seqLength; // length of current sequence int seqIndex; // index into current sequence bool first; // first code after a table clear bool processNextCode(); void clearTable(); int getCode(); }; //------------------------------------------------------------------------ // RunLengthStream //------------------------------------------------------------------------ class RunLengthStream : public FilterStream { public: RunLengthStream(Stream *strA); ~RunLengthStream() override; StreamKind getKind() const override { return strRunLength; } void reset() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; private: bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override; char buf[128]; // buffer char *bufPtr; // next char to read char *bufEnd; // end of buffer bool eof; bool fillBuf(); }; //------------------------------------------------------------------------ // CCITTFaxStream //------------------------------------------------------------------------ struct CCITTCodeTable; class CCITTFaxStream : public FilterStream { public: CCITTFaxStream(Stream *strA, int encodingA, bool endOfLineA, bool byteAlignA, int columnsA, int rowsA, bool endOfBlockA, bool blackA, int damagedRowsBeforeErrorA); ~CCITTFaxStream() override; StreamKind getKind() const override { return strCCITTFax; } void reset() override; int getChar() override { int c = lookChar(); buf = EOF; return c; } int lookChar() override; GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; void unfilteredReset() override; int getEncoding() { return encoding; } bool getEndOfLine() { return endOfLine; } bool getEncodedByteAlign() { return byteAlign; } bool getEndOfBlock() { return endOfBlock; } int getColumns() { return columns; } bool getBlackIs1() { return black; } int getDamagedRowsBeforeError() { return damagedRowsBeforeError; } private: void ccittReset(bool unfiltered); int encoding; // 'K' parameter bool endOfLine; // 'EndOfLine' parameter bool byteAlign; // 'EncodedByteAlign' parameter int columns; // 'Columns' parameter int rows; // 'Rows' parameter bool endOfBlock; // 'EndOfBlock' parameter bool black; // 'BlackIs1' parameter int damagedRowsBeforeError; // 'DamagedRowsBeforeError' parameter bool eof; // true if at eof bool nextLine2D; // true if next line uses 2D encoding int row; // current row unsigned int inputBuf; // input buffer int inputBits; // number of bits in input buffer int *codingLine; // coding line changing elements int *refLine; // reference line changing elements int a0i; // index into codingLine bool err; // error on current line int outputBits; // remaining ouput bits int buf; // character buffer void addPixels(int a1, int blackPixels); void addPixelsNeg(int a1, int blackPixels); short getTwoDimCode(); short getWhiteCode(); short getBlackCode(); short lookBits(int n); void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; } }; #ifndef ENABLE_LIBJPEG //------------------------------------------------------------------------ // DCTStream //------------------------------------------------------------------------ // DCT component info struct DCTCompInfo { int id; // component ID int hSample, vSample; // horiz/vert sampling resolutions int quantTable; // quantization table number int prevDC; // DC coefficient accumulator }; struct DCTScanInfo { bool comp[4]; // comp[i] is set if component i is // included in this scan int numComps; // number of components in the scan int dcHuffTable[4]; // DC Huffman table numbers int acHuffTable[4]; // AC Huffman table numbers int firstCoeff, lastCoeff; // first and last DCT coefficient int ah, al; // successive approximation parameters }; // DCT Huffman decoding table struct DCTHuffTable { unsigned char firstSym[17]; // first symbol for this bit length unsigned short firstCode[17]; // first code for this bit length unsigned short numCodes[17]; // number of codes of this bit length unsigned char sym[256]; // symbols }; class DCTStream : public FilterStream { public: DCTStream(Stream *strA, int colorXformA, Dict *dict, int recursion); ~DCTStream() override; StreamKind getKind() const override { return strDCT; } void reset() override; void close() override; int getChar() override; int lookChar() override; GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; void unfilteredReset() override; private: void dctReset(bool unfiltered); bool progressive; // set if in progressive mode bool interleaved; // set if in interleaved mode int width, height; // image size int mcuWidth, mcuHeight; // size of min coding unit, in data units int bufWidth, bufHeight; // frameBuf size DCTCompInfo compInfo[4]; // info for each component DCTScanInfo scanInfo; // info for the current scan int numComps; // number of components in image int colorXform; // color transform: -1 = unspecified // 0 = none // 1 = YUV/YUVK -> RGB/CMYK bool gotJFIFMarker; // set if APP0 JFIF marker was present bool gotAdobeMarker; // set if APP14 Adobe marker was present int restartInterval; // restart interval, in MCUs unsigned short quantTables[4][64]; // quantization tables int numQuantTables; // number of quantization tables DCTHuffTable dcHuffTables[4]; // DC Huffman tables DCTHuffTable acHuffTables[4]; // AC Huffman tables int numDCHuffTables; // number of DC Huffman tables int numACHuffTables; // number of AC Huffman tables unsigned char *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) int *frameBuf[4]; // buffer for frame (progressive mode) int comp, x, y, dy; // current position within image/MCU int restartCtr; // MCUs left until restart int restartMarker; // next restart marker int eobRun; // number of EOBs left in the current run int inputBuf; // input buffer for variable length codes int inputBits; // number of valid bits in input buffer void restart(); bool readMCURow(); void readScan(); bool readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, int *prevDC, int data[64]); bool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, int *prevDC, int data[64]); void decodeImage(); void transformDataUnit(unsigned short *quantTable, int dataIn[64], unsigned char dataOut[64]); int readHuffSym(DCTHuffTable *table); int readAmp(int size); int readBit(); bool readHeader(); bool readBaselineSOF(); bool readProgressiveSOF(); bool readScanInfo(); bool readQuantTables(); bool readHuffmanTables(); bool readRestartInterval(); bool readJFIFMarker(); bool readAdobeMarker(); bool readTrailer(); int readMarker(); int read16(); }; #endif #ifndef ENABLE_ZLIB_UNCOMPRESS //------------------------------------------------------------------------ // FlateStream //------------------------------------------------------------------------ # define flateWindow 32768 // buffer size # define flateMask (flateWindow - 1) # define flateMaxHuffman 15 // max Huffman code length # define flateMaxCodeLenCodes 19 // max # code length codes # define flateMaxLitCodes 288 // max # literal codes # define flateMaxDistCodes 30 // max # distance codes // Huffman code table entry struct FlateCode { unsigned short len; // code length, in bits unsigned short val; // value represented by this code }; struct FlateHuffmanTab { const FlateCode *codes; int maxLen; }; // Decoding info for length and distance code words struct FlateDecode { int bits; // # extra bits int first; // first length/distance }; class FlateStream : public FilterStream { public: FlateStream(Stream *strA, int predictor, int columns, int colors, int bits); ~FlateStream() override; StreamKind getKind() const override { return strFlate; } void reset() override; int getChar() override; int lookChar() override; int getRawChar() override; void getRawChars(int nChars, int *buffer) override; GooString *getPSFilter(int psLevel, const char *indent) override; bool isBinary(bool last = true) override; void unfilteredReset() override; private: void flateReset(bool unfiltered); inline int doGetRawChar() { int c; while (remain == 0) { if (endOfBlock && eof) return EOF; readSome(); } c = buf[index]; index = (index + 1) & flateMask; --remain; return c; } bool hasGetChars() override { return true; } int getChars(int nChars, unsigned char *buffer) override; StreamPredictor *pred; // predictor unsigned char buf[flateWindow]; // output data buffer int index; // current index into output buffer int remain; // number valid bytes in output buffer int codeBuf; // input buffer int codeSize; // number of bits in input buffer int // literal and distance code lengths codeLengths[flateMaxLitCodes + flateMaxDistCodes]; FlateHuffmanTab litCodeTab; // literal code table FlateHuffmanTab distCodeTab; // distance code table bool compressedBlock; // set if reading a compressed block int blockLen; // remaining length of uncompressed block bool endOfBlock; // set when end of block is reached bool eof; // set when end of stream is reached static const int // code length code reordering codeLenCodeMap[flateMaxCodeLenCodes]; static const FlateDecode // length decoding info lengthDecode[flateMaxLitCodes - 257]; static const FlateDecode // distance decoding info distDecode[flateMaxDistCodes]; static FlateHuffmanTab // fixed literal code table fixedLitCodeTab; static FlateHuffmanTab // fixed distance code table fixedDistCodeTab; void readSome(); bool startBlock(); void loadFixedCodes(); bool readDynamicCodes(); FlateCode *compHuffmanCodes(const int *lengths, int n, int *maxLen); int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; #endif //------------------------------------------------------------------------ // EOFStream //------------------------------------------------------------------------ class EOFStream : public FilterStream { public: EOFStream(Stream *strA); ~EOFStream() override; StreamKind getKind() const override { return strWeird; } void reset() override { } int getChar() override { return EOF; } int lookChar() override { return EOF; } GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return false; } }; //------------------------------------------------------------------------ // BufStream //------------------------------------------------------------------------ class BufStream : public FilterStream { public: BufStream(Stream *strA, int bufSizeA); ~BufStream() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override; int lookChar() override; GooString *getPSFilter(int psLevel, const char *indent) override { return nullptr; } bool isBinary(bool last = true) override; int lookChar(int idx); private: int *buf; int bufSize; }; //------------------------------------------------------------------------ // FixedLengthEncoder //------------------------------------------------------------------------ class FixedLengthEncoder : public FilterStream { public: FixedLengthEncoder(Stream *strA, int lengthA); ~FixedLengthEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override; int lookChar() override; GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override; bool isEncoder() override { return true; } private: int length; int count; }; //------------------------------------------------------------------------ // ASCIIHexEncoder //------------------------------------------------------------------------ class ASCIIHexEncoder : public FilterStream { public: ASCIIHexEncoder(Stream *strA); ~ASCIIHexEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return false; } bool isEncoder() override { return true; } private: char buf[4]; char *bufPtr; char *bufEnd; int lineLen; bool eof; bool fillBuf(); }; //------------------------------------------------------------------------ // ASCII85Encoder //------------------------------------------------------------------------ class ASCII85Encoder : public FilterStream { public: ASCII85Encoder(Stream *strA); ~ASCII85Encoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return false; } bool isEncoder() override { return true; } private: char buf[8]; char *bufPtr; char *bufEnd; int lineLen; bool eof; bool fillBuf(); }; //------------------------------------------------------------------------ // RunLengthEncoder //------------------------------------------------------------------------ class RunLengthEncoder : public FilterStream { public: RunLengthEncoder(Stream *strA); ~RunLengthEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return true; } bool isEncoder() override { return true; } private: char buf[131]; char *bufPtr; char *bufEnd; char *nextEnd; bool eof; bool fillBuf(); }; //------------------------------------------------------------------------ // LZWEncoder //------------------------------------------------------------------------ struct LZWEncoderNode { int byte; LZWEncoderNode *next; // next sibling LZWEncoderNode *children; // first child }; class LZWEncoder : public FilterStream { public: LZWEncoder(Stream *strA); ~LZWEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override; int lookChar() override; GooString *getPSFilter(int psLevel, const char *indent) override { return nullptr; } bool isBinary(bool last = true) override { return true; } bool isEncoder() override { return true; } private: LZWEncoderNode table[4096]; int nextSeq; int codeLen; unsigned char inBuf[4096]; int inBufLen; int outBuf; int outBufLen; bool needEOD; void fillBuf(); }; //------------------------------------------------------------------------ // CMYKGrayEncoder //------------------------------------------------------------------------ class CMYKGrayEncoder : public FilterStream { public: CMYKGrayEncoder(Stream *strA); ~CMYKGrayEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return false; } bool isEncoder() override { return true; } private: char buf[2]; char *bufPtr; char *bufEnd; bool eof; bool fillBuf(); }; //------------------------------------------------------------------------ // RGBGrayEncoder //------------------------------------------------------------------------ class RGBGrayEncoder : public FilterStream { public: RGBGrayEncoder(Stream *strA); ~RGBGrayEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } int lookChar() override { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return false; } bool isEncoder() override { return true; } private: char buf[2]; char *bufPtr; char *bufEnd; bool eof; bool fillBuf(); }; //------------------------------------------------------------------------ // SplashBitmapCMYKEncoder // // This stream helps to condense SplashBitmaps (mostly of DeviceN8 type) into // pure CMYK colors. In particular for a DeviceN8 bitmap it redacts the spot colorants. //------------------------------------------------------------------------ #ifdef HAVE_SPLASH class SplashBitmapCMYKEncoder : public Stream { public: SplashBitmapCMYKEncoder(SplashBitmap *bitmapA); ~SplashBitmapCMYKEncoder() override; StreamKind getKind() const override { return strWeird; } void reset() override; int getChar() override; int lookChar() override; GooString *getPSFilter(int /*psLevel*/, const char * /*indent*/) override { return nullptr; } bool isBinary(bool /*last = true*/) override { return true; } // Although we are an encoder, we return false here, since we do not want do be auto-deleted by // successive streams. bool isEncoder() override { return false; } int getUnfilteredChar() override { return getChar(); } void unfilteredReset() override { reset(); } BaseStream *getBaseStream() override { return nullptr; } Stream *getUndecodedStream() override { return this; } Dict *getDict() override { return nullptr; } Object *getDictObject() override { return nullptr; } Goffset getPos() override; void setPos(Goffset pos, int dir = 0) override; private: SplashBitmap *bitmap; size_t width; int height; std::vector buf; size_t bufPtr; int curLine; bool fillBuf(); }; #endif #endif