| //======================================================================== |
| // |
| // 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 <jeff@infidigm.net> |
| // Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net> |
| // Copyright (C) 2008, 2010, 2011, 2016-2019 Albert Astals Cid <aacid@kde.org> |
| // Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org> |
| // Copyright (C) 2009 Stefan Thomas <thomas@eload24.com> |
| // Copyright (C) 2010 Hib Eris <hib@hiberis.nl> |
| // Copyright (C) 2011, 2012, 2016 William Bader <williambader@hotmail.com> |
| // Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de> |
| // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it> |
| // Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com> |
| // Copyright (C) 2013 Peter Breitenlohner <peb@mppmu.mpg.de> |
| // Copyright (C) 2013, 2018 Adam Reichold <adamreichold@myopera.com> |
| // Copyright (C) 2013 Pino Toscano <pino@kde.org> |
| // |
| // 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 <atomic> |
| #include <cstdio> |
| |
| #include "poppler-config.h" |
| #include "Object.h" |
| |
| class GooFile; |
| class BaseStream; |
| class CachedFile; |
| |
| //------------------------------------------------------------------------ |
| |
| 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() = 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 fillGooString(GooString *s) |
| { |
| unsigned char readBuf[4096]; |
| int readChars; |
| reset(); |
| while ((readChars = doGetChars(4096, readBuf)) != 0) { |
| s->append((const char *)readBuf, readChars); |
| } |
| } |
| |
| 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 <dir> 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() { return nullptr; } |
| |
| // Add filters to this stream according to the parameters in <dict>. |
| // Returns the new stream. |
| Stream *addFilters(Dict *dict, int recursion = 0); |
| |
| 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 (); |
| |
| 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(); |
| 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; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FilterStream |
| // |
| // This is the base class for all streams that filter another stream. |
| //------------------------------------------------------------------------ |
| |
| class FilterStream: public Stream { |
| public: |
| |
| FilterStream(Stream *strA); |
| ~FilterStream(); |
| 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() 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. <pix> 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(); |
| BaseStream *copy() override; |
| Stream *makeSubStream(Goffset startA, bool limitedA, |
| Goffset lengthA, Object &&dictA) override; |
| StreamKind getKind() 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(); |
| BaseStream *copy() override; |
| Stream *makeSubStream(Goffset startA, bool limitedA, |
| Goffset lengthA, Object &&dictA) override; |
| StreamKind getKind() 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<typename T> |
| 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() 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 (nChars <= 0) { |
| 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<const char> |
| { |
| public: |
| MemStream(const char *bufA, Goffset startA, Goffset lengthA, Object &&dictA) |
| : BaseMemStream(bufA, startA, lengthA, std::move(dictA)) |
| { } |
| }; |
| |
| class AutoFreeMemStream : public BaseMemStream<char> |
| { |
| public: |
| AutoFreeMemStream(char *bufA, Goffset startA, Goffset lengthA, Object &&dictA) |
| : BaseMemStream(bufA, startA, lengthA, std::move(dictA)) |
| { } |
| |
| ~AutoFreeMemStream() |
| { gfree(buf); } |
| }; |
| |
| |
| //------------------------------------------------------------------------ |
| // 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(); |
| BaseStream *copy() override; |
| Stream *makeSubStream(Goffset start, bool limitedA, |
| Goffset lengthA, Object &&dictA) override; |
| StreamKind getKind() 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; |
| |
| }; |
| |
| //------------------------------------------------------------------------ |
| // ASCIIHexStream |
| //------------------------------------------------------------------------ |
| |
| class ASCIIHexStream: public FilterStream { |
| public: |
| |
| ASCIIHexStream(Stream *strA); |
| ~ASCIIHexStream(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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); |
| virtual ~DCTStream(); |
| StreamKind getKind() 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 { |
| 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(); |
| StreamKind getKind() 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 int // code length code reordering |
| codeLenCodeMap[flateMaxCodeLenCodes]; |
| static FlateDecode // length decoding info |
| lengthDecode[flateMaxLitCodes-257]; |
| static 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(); |
| void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); |
| int getHuffmanCodeWord(FlateHuffmanTab *tab); |
| int getCodeWord(int bits); |
| }; |
| #endif |
| |
| //------------------------------------------------------------------------ |
| // EOFStream |
| //------------------------------------------------------------------------ |
| |
| class EOFStream: public FilterStream { |
| public: |
| |
| EOFStream(Stream *strA); |
| ~EOFStream(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| StreamKind getKind() 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(); |
| }; |
| |
| #endif |