| //======================================================================== |
| // |
| // XRef.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 Brad Hards <bradh@frogmouth.net> |
| // Copyright (C) 2006, 2008, 2010-2013, 2017-2019 Albert Astals Cid <aacid@kde.org> |
| // Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org> |
| // Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org> |
| // Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com> |
| // Copyright (C) 2010 Hib Eris <hib@hiberis.nl> |
| // Copyright (C) 2012, 2013, 2016 Thomas Freitag <Thomas.Freitag@kabelmail.de> |
| // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it> |
| // Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com> |
| // Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> |
| // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
| // Copyright (C) 2018 Marek Kasik <mkasik@redhat.com> |
| // |
| // 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 XREF_H |
| #define XREF_H |
| |
| #include "poppler-config.h" |
| #include "Object.h" |
| #include "Stream.h" |
| #include "PopplerCache.h" |
| |
| class Dict; |
| class Stream; |
| class Parser; |
| class ObjectStream; |
| |
| //------------------------------------------------------------------------ |
| // XRef |
| //------------------------------------------------------------------------ |
| |
| enum XRefEntryType { |
| xrefEntryFree, |
| xrefEntryUncompressed, |
| xrefEntryCompressed, |
| xrefEntryNone |
| }; |
| |
| struct XRefEntry { |
| Goffset offset; |
| int gen; |
| XRefEntryType type; |
| int flags; |
| Object obj; //if this entry was updated, obj will contains the updated object |
| |
| enum Flag { |
| // Regular flags |
| Updated, // Entry was modified |
| Parsing, // Entry is currently being parsed |
| |
| // Special flags -- available only after xref->scanSpecialFlags() is run |
| Unencrypted, // Entry is stored in unencrypted form (meaningless in unencrypted documents) |
| DontRewrite // Entry must not be written back in case of full rewrite |
| }; |
| |
| inline bool getFlag(Flag flag) const { |
| const int mask = (1 << (int)flag); |
| return (flags & mask) != 0; |
| } |
| |
| inline void setFlag(Flag flag, bool value) { |
| const int mask = (1 << (int)flag); |
| if (value) { |
| flags |= mask; |
| } else { |
| flags &= ~mask; |
| } |
| } |
| }; |
| |
| class XRef { |
| public: |
| |
| // Constructor, create an empty XRef, used for PDF writing |
| XRef(); |
| // Constructor, create an empty XRef but with info dict, used for PDF writing |
| XRef(const Object *trailerDictA); |
| // Constructor. Read xref table from stream. |
| XRef(BaseStream *strA, Goffset pos, Goffset mainXRefEntriesOffsetA = 0, bool *wasReconstructed = nullptr, bool reconstruct = false); |
| |
| // Destructor. |
| ~XRef(); |
| |
| XRef(const XRef &) = delete; |
| XRef& operator=(const XRef &) = delete; |
| |
| // Copy xref but with new base stream! |
| XRef *copy() const; |
| |
| // Is xref table valid? |
| bool isOk() const { return ok; } |
| |
| // Is the last XRef section a stream or a table? |
| bool isXRefStream() const { return xRefStream; } |
| |
| // Get the error code (if isOk() returns false). |
| int getErrorCode() const { return errCode; } |
| |
| // Set the encryption parameters. |
| void setEncryption(int permFlagsA, bool ownerPasswordOkA, |
| const unsigned char *fileKeyA, int keyLengthA, |
| int encVersionA, int encRevisionA, |
| CryptAlgorithm encAlgorithmA); |
| // Mark Encrypt entry as Unencrypted |
| void markUnencrypted(); |
| |
| void getEncryptionParameters(unsigned char **fileKeyA, CryptAlgorithm *encAlgorithmA, int *keyLengthA); |
| |
| // Is the file encrypted? |
| bool isEncrypted() const { return encrypted; } |
| |
| // Check various permissions. |
| bool okToPrint(bool ignoreOwnerPW = false) const; |
| bool okToPrintHighRes(bool ignoreOwnerPW = false) const; |
| bool okToChange(bool ignoreOwnerPW = false) const; |
| bool okToCopy(bool ignoreOwnerPW = false) const; |
| bool okToAddNotes(bool ignoreOwnerPW = false) const; |
| bool okToFillForm(bool ignoreOwnerPW = false) const; |
| bool okToAccessibility(bool ignoreOwnerPW = false) const; |
| bool okToAssemble(bool ignoreOwnerPW = false) const; |
| int getPermFlags() const { return permFlags; } |
| |
| // Get catalog object. |
| Object getCatalog(); |
| |
| // Fetch an indirect reference. |
| Object fetch(const Ref ref, int recursion = 0); |
| Object fetch(int num, int gen, int recursion = 0); |
| |
| // Return the document's Info dictionary (if any). |
| Object getDocInfo(); |
| Object getDocInfoNF(); |
| |
| // Create and return the document's Info dictionary if none exists. |
| // Otherwise return the existing one. |
| Object createDocInfoIfNoneExists(); |
| |
| // Remove the document's Info dictionary and update the trailer dictionary. |
| void removeDocInfo(); |
| |
| // Return the number of objects in the xref table. |
| int getNumObjects() const { return size; } |
| |
| // Return the catalog object reference. |
| int getRootNum() const { return rootNum; } |
| int getRootGen() const { return rootGen; } |
| |
| // Get end position for a stream in a damaged file. |
| // Returns false if unknown or file is not damaged. |
| bool getStreamEnd(Goffset streamStart, Goffset *streamEnd); |
| |
| // Retuns the entry that belongs to the offset |
| int getNumEntry(Goffset offset); |
| |
| // Scans the document and sets special flags in all xref entries. One of those |
| // flags is Unencrypted, which affects how the object is fetched. Therefore, |
| // this function must be called before fetching unencrypted objects (e.g. |
| // Encrypt dictionary, XRef streams). Note that the code that initializes |
| // decryption doesn't need to call this function, because it runs before |
| // decryption is enabled, and therefore the Unencrypted flag is ignored. |
| void scanSpecialFlags(); |
| |
| // Direct access. |
| XRefEntry *getEntry(int i, bool complainIfMissing = true); |
| Object *getTrailerDict() { return &trailerDict; } |
| |
| // Was the XRef modified? |
| bool isModified() const { return modified; } |
| // Set the modification flag for XRef to true. |
| void setModified() { modified = true; } |
| |
| // Write access |
| void setModifiedObject(const Object* o, Ref r); |
| Ref addIndirectObject (const Object* o); |
| void removeIndirectObject(Ref r); |
| void add(int num, int gen, Goffset offs, bool used); |
| void add(Ref ref, Goffset offs, bool used); |
| |
| // Output XRef table to stream |
| void writeTableToFile(OutStream* outStr, bool writeAllEntries); |
| // Output XRef stream contents to GooString and fill trailerDict fields accordingly |
| void writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref); |
| |
| // to be thread safe during write where changes are not allowed |
| void lock(); |
| void unlock(); |
| |
| private: |
| |
| BaseStream *str; // input stream |
| Goffset start; // offset in file (to allow for garbage |
| // at beginning of file) |
| XRefEntry *entries; // xref entries |
| int capacity; // size of <entries> array |
| int size; // number of entries |
| int rootNum, rootGen; // catalog dict |
| bool ok; // true if xref table is valid |
| int errCode; // error code (if <ok> is false) |
| bool xrefReconstructed; // marker, true if xref was already reconstructed |
| Object trailerDict; // trailer dictionary |
| bool modified; |
| Goffset *streamEnds; // 'endstream' positions - only used in |
| // damaged files |
| int streamEndsLen; // number of valid entries in streamEnds |
| PopplerCache<Goffset, ObjectStream> objStrs; // cached object streams |
| bool encrypted; // true if file is encrypted |
| int encRevision; |
| int encVersion; // encryption algorithm |
| CryptAlgorithm encAlgorithm; // encryption algorithm |
| int keyLength; // length of key, in bytes |
| int permFlags; // permission bits |
| unsigned char fileKey[32]; // file decryption key |
| bool ownerPasswordOk; // true if owner password is correct |
| Goffset prevXRefOffset; // position of prev XRef section (= next to read) |
| Goffset mainXRefEntriesOffset; // offset of entries in main XRef table |
| bool xRefStream; // true if last XRef section is a stream |
| Goffset mainXRefOffset; // position of the main XRef table/stream |
| bool scannedSpecialFlags; // true if scanSpecialFlags has been called |
| bool strOwner; // true if str is owned by the instance |
| mutable std::recursive_mutex mutex; |
| |
| int reserve(int newSize); |
| int resize(int newSize); |
| bool readXRef(Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum); |
| bool readXRefTable(Parser *parser, Goffset *pos, std::vector<Goffset> *followedXRefStm, std::vector<int> *xrefStreamObjsNum); |
| bool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); |
| bool readXRefStream(Stream *xrefStr, Goffset *pos); |
| bool constructXRef(bool *wasReconstructed, bool needCatalogDict = false); |
| bool parseEntry(Goffset offset, XRefEntry *entry); |
| void readXRefUntil(int untilEntryNum, std::vector<int> *xrefStreamObjsNum = nullptr); |
| void markUnencrypted(Object *obj); |
| |
| class XRefWriter { |
| public: |
| XRefWriter() = default; |
| virtual void startSection(int first, int count) = 0; |
| virtual void writeEntry(Goffset offset, int gen, XRefEntryType type) = 0; |
| virtual ~XRefWriter() {}; |
| |
| XRefWriter(const XRefWriter &) = delete; |
| XRefWriter& operator=(const XRefWriter &other) = delete; |
| }; |
| |
| // XRefWriter subclass that writes a XRef table |
| class XRefTableWriter: public XRefWriter { |
| public: |
| XRefTableWriter(OutStream* outStrA); |
| void startSection(int first, int count) override; |
| void writeEntry(Goffset offset, int gen, XRefEntryType type) override; |
| private: |
| OutStream* outStr; |
| }; |
| |
| // XRefWriter subclass that writes a XRef stream |
| class XRefStreamWriter: public XRefWriter { |
| public: |
| XRefStreamWriter(Array *index, GooString *stmBuf, int offsetSize); |
| void startSection(int first, int count) override; |
| void writeEntry(Goffset offset, int gen, XRefEntryType type) override; |
| private: |
| Array *index; |
| GooString *stmBuf; |
| int offsetSize; |
| }; |
| |
| // Dummy XRefWriter subclass that only checks if all offsets fit in 4 bytes |
| class XRefPreScanWriter: public XRefWriter { |
| public: |
| XRefPreScanWriter(); |
| void startSection(int first, int count) override; |
| void writeEntry(Goffset offset, int gen, XRefEntryType type) override; |
| |
| bool hasOffsetsBeyond4GB; |
| }; |
| |
| void writeXRef(XRefWriter *writer, bool writeAllEntries); |
| }; |
| |
| #endif |