diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/qpdf/BufferInputSource.hh | 25 | ||||
-rw-r--r-- | include/qpdf/ClosedFileInputSource.hh | 21 | ||||
-rw-r--r-- | include/qpdf/Constants.h | 2 | ||||
-rw-r--r-- | include/qpdf/FileInputSource.hh | 21 | ||||
-rw-r--r-- | include/qpdf/InputSource.hh | 68 | ||||
-rw-r--r-- | include/qpdf/QPDF.hh | 39 | ||||
-rw-r--r-- | include/qpdf/QPDFJob.hh | 1 | ||||
-rw-r--r-- | include/qpdf/QPDFNameTreeObjectHelper.hh | 8 | ||||
-rw-r--r-- | include/qpdf/QPDFNumberTreeObjectHelper.hh | 8 | ||||
-rw-r--r-- | include/qpdf/QPDFObject.hh | 140 | ||||
-rw-r--r-- | include/qpdf/QPDFObjectHandle.hh | 160 | ||||
-rw-r--r-- | include/qpdf/QPDFTokenizer.hh | 94 | ||||
-rw-r--r-- | include/qpdf/QPDFValue.hh | 130 | ||||
-rw-r--r-- | include/qpdf/QTC.hh | 16 | ||||
-rw-r--r-- | include/qpdf/QUtil.hh | 67 | ||||
-rw-r--r-- | include/qpdf/auto_job_c_main.hh | 1 |
16 files changed, 612 insertions, 189 deletions
diff --git a/include/qpdf/BufferInputSource.hh b/include/qpdf/BufferInputSource.hh index b965704f..1a93815b 100644 --- a/include/qpdf/BufferInputSource.hh +++ b/include/qpdf/BufferInputSource.hh @@ -54,26 +54,11 @@ class QPDF_DLL_CLASS BufferInputSource: public InputSource virtual void unreadCh(char ch); private: - class QPDF_DLL_PRIVATE Members - { - friend class BufferInputSource; - - public: - QPDF_DLL - ~Members() = default; - - private: - Members(bool own_memory, std::string const& description, Buffer* buf); - Members(Members const&) = delete; - - bool own_memory; - std::string description; - Buffer* buf; - qpdf_offset_t cur_offset; - qpdf_offset_t max_offset; - }; - - std::shared_ptr<Members> m; + bool own_memory; + std::string description; + Buffer* buf; + qpdf_offset_t cur_offset; + qpdf_offset_t max_offset; }; #endif // QPDF_BUFFERINPUTSOURCE_HH diff --git a/include/qpdf/ClosedFileInputSource.hh b/include/qpdf/ClosedFileInputSource.hh index c72a1df8..b23c2767 100644 --- a/include/qpdf/ClosedFileInputSource.hh +++ b/include/qpdf/ClosedFileInputSource.hh @@ -73,23 +73,10 @@ class QPDF_DLL_CLASS ClosedFileInputSource: public InputSource QPDF_DLL_PRIVATE void after(); - class QPDF_DLL_PRIVATE Members - { - friend class ClosedFileInputSource; - - public: - QPDF_DLL - ~Members() = default; - - private: - Members(char const* filename); - - std::string filename; - qpdf_offset_t offset; - std::shared_ptr<FileInputSource> fis; - bool stay_open; - }; - std::shared_ptr<Members> m; + std::string filename; + qpdf_offset_t offset; + std::shared_ptr<FileInputSource> fis; + bool stay_open; }; #endif // QPDF_CLOSEDFILEINPUTSOURCE_HH diff --git a/include/qpdf/Constants.h b/include/qpdf/Constants.h index 5d2113bd..cf6bdaef 100644 --- a/include/qpdf/Constants.h +++ b/include/qpdf/Constants.h @@ -82,6 +82,8 @@ enum qpdf_object_type_e { /* Additional object types that can occur in content streams */ ot_operator, ot_inlineimage, + /* Object types internal to qpdf */ + ot_unresolved, /* NOTE: if adding to this list, update QPDFObject.hh */ }; diff --git a/include/qpdf/FileInputSource.hh b/include/qpdf/FileInputSource.hh index f1e7edf4..9e0d57fb 100644 --- a/include/qpdf/FileInputSource.hh +++ b/include/qpdf/FileInputSource.hh @@ -58,24 +58,9 @@ class QPDF_DLL_CLASS FileInputSource: public InputSource FileInputSource(FileInputSource const&) = delete; FileInputSource& operator=(FileInputSource const&) = delete; - class QPDF_DLL_PRIVATE Members - { - friend class FileInputSource; - - public: - QPDF_DLL - ~Members(); - - private: - Members(bool close_file); - Members(Members const&) = delete; - - bool close_file; - std::string filename; - FILE* file; - }; - - std::shared_ptr<Members> m; + bool close_file; + std::string filename; + FILE* file; }; #endif // QPDF_FILEINPUTSOURCE_HH diff --git a/include/qpdf/InputSource.hh b/include/qpdf/InputSource.hh index 9feb8ec3..e9d99cdb 100644 --- a/include/qpdf/InputSource.hh +++ b/include/qpdf/InputSource.hh @@ -93,6 +93,12 @@ class QPDF_DLL_CLASS InputSource // efficient. virtual void unreadCh(char ch) = 0; + // The following methods are for use by QPDFTokenizer + inline qpdf_offset_t fastTell(); + inline bool fastRead(char&); + inline void fastUnread(bool); + inline void loadBuffer(); + protected: qpdf_offset_t last_offset; @@ -111,6 +117,68 @@ class QPDF_DLL_CLASS InputSource }; std::shared_ptr<Members> m; + + // State for fast... methods + static const qpdf_offset_t buf_size = 128; + char buffer[buf_size]; + qpdf_offset_t buf_len = 0; + qpdf_offset_t buf_idx = 0; + qpdf_offset_t buf_start = 0; }; +inline void +InputSource::loadBuffer() +{ + this->buf_idx = 0; + this->buf_len = qpdf_offset_t(read(this->buffer, this->buf_size)); + // NB read sets last_offset + this->buf_start = this->last_offset; +} + +inline qpdf_offset_t +InputSource::fastTell() +{ + if (this->buf_len == 0) { + loadBuffer(); + } else { + auto curr = tell(); + if (curr < this->buf_start || + curr >= (this->buf_start + this->buf_len)) { + loadBuffer(); + } else { + this->last_offset = curr; + this->buf_idx = curr - this->buf_start; + } + } + return this->last_offset; +} + +inline bool +InputSource::fastRead(char& ch) +{ + // Before calling fastRead, fastTell must be called to prepare the buffer. + // Once reading is complete, fastUnread must be called to set the correct + // file position. + if (this->buf_idx < this->buf_len) { + ch = this->buffer[this->buf_idx]; + ++(this->buf_idx); + ++(this->last_offset); + return true; + + } else if (this->buf_len == 0) { + return false; + } else { + seek(this->buf_start + this->buf_len, SEEK_SET); + fastTell(); + return fastRead(ch); + } +} + +inline void +InputSource::fastUnread(bool back) +{ + this->last_offset -= back ? 1 : 0; + seek(this->last_offset, SEEK_SET); +} + #endif // QPDF_INPUTSOURCE_HH diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 64f31edd..81169fbd 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -49,6 +49,7 @@ class QPDF_Stream; class BitStream; class BitWriter; class QPDFLogger; +class QPDFParser; class QPDF { @@ -382,8 +383,15 @@ class QPDF QPDF_DLL QPDFObjectHandle makeIndirectObject(QPDFObjectHandle); - // Retrieve an object by object ID and generation. Returns an - // indirect reference to it. + // Retrieve an object by object ID and generation. Returns an + // indirect reference to it. The getObject() methods were added + // for qpdf 11. + QPDF_DLL + QPDFObjectHandle getObject(QPDFObjGen const&); + QPDF_DLL + QPDFObjectHandle getObject(int objid, int generation); + // These are older methods, but there is no intention to deprecate + // them. QPDF_DLL QPDFObjectHandle getObjectByObjGen(QPDFObjGen const&); QPDF_DLL @@ -835,19 +843,13 @@ class QPDF // it can resolve indirect references. class Resolver { - friend class QPDFObjectHandle; + friend class QPDFObject; private: - static std::shared_ptr<QPDFObject> + static void resolve(QPDF* qpdf, QPDFObjGen const& og) { - return qpdf->resolve(og); - } - static bool - objectChanged( - QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph) - { - return qpdf->objectChanged(og, oph); + qpdf->resolve(og); } }; friend class Resolver; @@ -874,7 +876,7 @@ class QPDF // resolution class ParseGuard { - friend class QPDFObjectHandle; + friend class QPDFParser; private: ParseGuard(QPDF* qpdf) : @@ -1166,12 +1168,20 @@ class QPDF std::string const& description, QPDFObjGen const& exp_og, QPDFObjGen& og); - bool objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph); - std::shared_ptr<QPDFObject> resolve(QPDFObjGen const& og); + void resolve(QPDFObjGen const& og); void resolveObjectsInStream(int obj_stream_number); void stopOnError(std::string const& message); QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); QPDFObjectHandle reserveStream(QPDFObjGen const& og); + QPDFObjectHandle + newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&); + bool isCached(QPDFObjGen const& og); + bool isUnresolved(QPDFObjGen const& og); + void updateCache( + QPDFObjGen const& og, + std::shared_ptr<QPDFObject> const& object, + qpdf_offset_t end_before_space, + qpdf_offset_t end_after_space); // Calls finish() on the pipeline when done but does not delete it bool pipeStreamData( @@ -1716,7 +1726,6 @@ class QPDF bool in_parse; bool parsed; std::set<int> resolved_object_streams; - bool ever_replaced_objects; // Linearization data qpdf_offset_t first_xref_item_offset; // actual value from file diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh index 0e4d8a2e..2d4ab0d2 100644 --- a/include/qpdf/QPDFJob.hh +++ b/include/qpdf/QPDFJob.hh @@ -711,6 +711,7 @@ class QPDFJob bool json_input; bool json_output; std::string update_from_json; + bool report_mem_usage; }; std::shared_ptr<Members> m; }; diff --git a/include/qpdf/QPDFNameTreeObjectHelper.hh b/include/qpdf/QPDFNameTreeObjectHelper.hh index 7093ca2e..006ab158 100644 --- a/include/qpdf/QPDFNameTreeObjectHelper.hh +++ b/include/qpdf/QPDFNameTreeObjectHelper.hh @@ -42,7 +42,7 @@ class NNTreeImpl; class NNTreeIterator; class NNTreeDetails; -class QPDFNameTreeObjectHelper: public QPDFObjectHelper +class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper { public: // The qpdf object is required so that this class can issue @@ -55,7 +55,7 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper static QPDFNameTreeObjectHelper newEmpty(QPDF&, bool auto_repair = true); QPDF_DLL - virtual ~QPDFNameTreeObjectHelper() = default; + virtual ~QPDFNameTreeObjectHelper(); // Return whether the number tree has an explicit entry for this // number. @@ -67,7 +67,7 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper QPDF_DLL bool findObject(std::string const& utf8, QPDFObjectHandle& oh); - class iterator + class QPDF_DLL_PRIVATE iterator { friend class QPDFNameTreeObjectHelper; @@ -181,7 +181,7 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper void setSplitThreshold(int); private: - class Members + class QPDF_DLL_PRIVATE Members { friend class QPDFNameTreeObjectHelper; diff --git a/include/qpdf/QPDFNumberTreeObjectHelper.hh b/include/qpdf/QPDFNumberTreeObjectHelper.hh index b053b5f4..c1ffc251 100644 --- a/include/qpdf/QPDFNumberTreeObjectHelper.hh +++ b/include/qpdf/QPDFNumberTreeObjectHelper.hh @@ -39,7 +39,7 @@ class NNTreeImpl; class NNTreeIterator; class NNTreeDetails; -class QPDFNumberTreeObjectHelper: public QPDFObjectHelper +class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper { public: // The qpdf object is required so that this class can issue @@ -49,7 +49,7 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper QPDFObjectHandle, QPDF&, bool auto_repair = true); QPDF_DLL - virtual ~QPDFNumberTreeObjectHelper() = default; + virtual ~QPDFNumberTreeObjectHelper(); // Create an empty number tree QPDF_DLL @@ -85,7 +85,7 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper bool findObjectAtOrBelow( numtree_number idx, QPDFObjectHandle& oh, numtree_number& offset); - class iterator + class QPDF_DLL_PRIVATE iterator { friend class QPDFNumberTreeObjectHelper; @@ -200,7 +200,7 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper void setSplitThreshold(int); private: - class Members + class QPDF_DLL_PRIVATE Members { friend class QPDFNumberTreeObjectHelper; typedef QPDFNumberTreeObjectHelper::numtree_number numtree_number; diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index eb7c4b90..e6d1d18b 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -25,6 +25,7 @@ #include <qpdf/Constants.h> #include <qpdf/DLL.h> #include <qpdf/JSON.hh> +#include <qpdf/QPDFValue.hh> #include <qpdf/Types.h> #include <string> @@ -34,9 +35,9 @@ class QPDFObjectHandle; class QPDFObject { - public: - QPDFObject(); + friend class QPDFValue; + public: // Objects derived from QPDFObject are accessible through // QPDFObjectHandle. Each object returns a unique type code that // has one of the valid qpdf_object_type_e values. As new object @@ -61,18 +62,128 @@ class QPDFObject static constexpr object_type_e ot_stream = ::ot_stream; static constexpr object_type_e ot_operator = ::ot_operator; static constexpr object_type_e ot_inlineimage = ::ot_inlineimage; + static constexpr object_type_e ot_unresolved = ::ot_unresolved; + QPDFObject() = default; virtual ~QPDFObject() = default; - virtual std::shared_ptr<QPDFObject> shallowCopy() = 0; - virtual std::string unparse() = 0; - virtual JSON getJSON(int json_version) = 0; + + std::shared_ptr<QPDFObject> + shallowCopy() + { + return value->shallowCopy(); + } + std::string + unparse() + { + return value->unparse(); + } + JSON + getJSON(int json_version) + { + return value->getJSON(json_version); + } // Return a unique type code for the object - virtual object_type_e getTypeCode() const = 0; + object_type_e + getTypeCode() const + { + return value->type_code; + } // Return a string literal that describes the type, useful for // debugging and testing - virtual char const* getTypeName() const = 0; + char const* + getTypeName() const + { + return value->type_name; + } + // Returns nullptr for direct objects + QPDF* + getQPDF() const + { + return value->qpdf; + } + QPDFObjGen + getObjGen() const + { + return value->og; + } + + void + setDescription(QPDF* qpdf, std::string const& description) + { + return value->setDescription(qpdf, description); + } + bool + getDescription(QPDF*& qpdf, std::string& description) + { + return value->getDescription(qpdf, description); + } + bool + hasDescription() + { + return value->hasDescription(); + } + void + setParsedOffset(qpdf_offset_t offset) + { + value->setParsedOffset(offset); + } + qpdf_offset_t + getParsedOffset() + { + return value->getParsedOffset(); + } + void + assign(std::shared_ptr<QPDFObject> o) + { + value = o->value; + } + void + swapWith(std::shared_ptr<QPDFObject> o) + { + auto v = value; + value = o->value; + o->value = v; + auto og = value->og; + value->og = o->value->og; + o->value->og = og; + } + + // The following two methods are for use by class QPDF only + void + setObjGen(QPDF* qpdf, QPDFObjGen const& og) + { + value->qpdf = qpdf; + value->og = og; + } + void + resetObjGen() + { + value->qpdf = nullptr; + value->og = QPDFObjGen(); + } + + bool + isUnresolved() const + { + return value->type_code == ::ot_unresolved; + } + void + resolve() + { + if (isUnresolved()) { + doResolve(); + } + } + void doResolve(); + + template <typename T> + T* + as() + { + return dynamic_cast<T*>(value.get()); + } // Accessor to give specific access to non-public methods class ObjAccessor @@ -89,29 +200,20 @@ class QPDFObject } } }; - friend class ObjAccessor; - virtual void setDescription(QPDF*, std::string const&); - bool getDescription(QPDF*&, std::string&); - bool hasDescription(); - - void setParsedOffset(qpdf_offset_t offset); - qpdf_offset_t getParsedOffset(); + friend class ObjAccessor; protected: virtual void releaseResolved() { + value->releaseResolved(); } - static std::shared_ptr<QPDFObject> do_create(QPDFObject*); private: QPDFObject(QPDFObject const&) = delete; QPDFObject& operator=(QPDFObject const&) = delete; - - QPDF* owning_qpdf; - std::string object_description; - qpdf_offset_t parsed_offset; + std::shared_ptr<QPDFValue> value; }; #endif // QPDFOBJECT_HH diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 7ea6b062..16e8dc8b 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -43,15 +43,28 @@ class Pipeline; class QPDF; -class QPDF_Dictionary; class QPDF_Array; +class QPDF_Bool; +class QPDF_Dictionary; +class QPDF_InlineImage; +class QPDF_Integer; +class QPDF_Name; +class QPDF_Null; +class QPDF_Operator; +class QPDF_Real; +class QPDF_Reserved; +class QPDF_Stream; +class QPDF_String; class QPDFTokenizer; class QPDFExc; class Pl_QPDFTokenizer; class QPDFMatrix; +class QPDFParser; class QPDFObjectHandle { + friend class QPDFParser; + public: // This class is used by replaceStreamData. It provides an // alternative way of associating stream data with a stream. See @@ -313,13 +326,13 @@ class QPDFObjectHandle }; QPDF_DLL - QPDFObjectHandle(); + QPDFObjectHandle() = default; QPDF_DLL QPDFObjectHandle(QPDFObjectHandle const&) = default; QPDF_DLL QPDFObjectHandle& operator=(QPDFObjectHandle const&) = default; QPDF_DLL - bool isInitialized() const; + inline bool isInitialized() const; // Return type code and type name of underlying object. These are // useful for doing rapid type tests (like switch statements) or @@ -367,7 +380,7 @@ class QPDFObjectHandle // This returns true in addition to the query for the specific // type for indirect objects. QPDF_DLL - bool isIndirect(); + inline bool isIndirect() const; // True for everything except array, dictionary, stream, word, and // inline image. @@ -957,9 +970,11 @@ class QPDFObjectHandle std::set<std::string>* resource_names = nullptr); // Return the QPDF object that owns an indirect object. Returns - // null for a direct object. + // null for a direct object if allow_nullptr is set to true or + // throws a runtime error otherwise. QPDF_DLL - QPDF* getOwningQPDF(); + inline QPDF* getOwningQPDF( + bool allow_nullptr = true, std::string const& error_msg = "") const; // Create a shallow copy of an object as a direct object, but do not // traverse across indirect object boundaries. That means that, @@ -1300,11 +1315,11 @@ class QPDFObjectHandle // QPDFObjGen instead. QPDF_DLL - QPDFObjGen getObjGen() const; + inline QPDFObjGen getObjGen() const; QPDF_DLL - int getObjectID() const; + inline int getObjectID() const; QPDF_DLL - int getGeneration() const; + inline int getGeneration() const; QPDF_DLL std::string unparse(); @@ -1438,9 +1453,9 @@ class QPDFObjectHandle private: static QPDFObjectHandle - newIndirect(QPDF* qpdf, QPDFObjGen const& og) + newIndirect(std::shared_ptr<QPDFObject> const& obj) { - return QPDFObjectHandle::newIndirect(qpdf, og); + return QPDFObjectHandle(obj); } static QPDFObjectHandle newStream( @@ -1453,12 +1468,6 @@ class QPDFObjectHandle return QPDFObjectHandle::newStream( qpdf, og, stream_dict, offset, length); } - // Reserve an object with a specific ID - static QPDFObjectHandle - makeReserved() - { - return QPDFObjectHandle::makeReserved(); - } }; friend class Factory; @@ -1478,6 +1487,16 @@ class QPDFObjectHandle }; return o.obj; } + static QPDF_Array* + asArray(QPDFObjectHandle& oh) + { + return oh.asArray(); + } + static QPDF_Stream* + asStream(QPDFObjectHandle& oh) + { + return oh.asStream(); + } }; friend class ObjAccessor; @@ -1558,27 +1577,32 @@ class QPDFObjectHandle bool isImage(bool exclude_imagemask = true); private: - QPDFObjectHandle(QPDF*, QPDFObjGen const& og); - QPDFObjectHandle(std::shared_ptr<QPDFObject> const&); - - enum parser_state_e { - st_top, - st_start, - st_stop, - st_eof, - st_dictionary, - st_array - }; + QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) : + obj(obj) + { + } // Private object factory methods - static QPDFObjectHandle newIndirect(QPDF*, QPDFObjGen const& og); static QPDFObjectHandle newStream( QPDF* qpdf, QPDFObjGen const& og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); - static QPDFObjectHandle makeReserved(); + + QPDF_Array* asArray(); + QPDF_Bool* asBool(); + QPDF_Dictionary* asDictionary(); + QPDF_InlineImage* asInlineImage(); + QPDF_Integer* asInteger(); + QPDF_Name* asName(); + QPDF_Null* asNull(); + QPDF_Operator* asOperator(); + QPDF_Real* asReal(); + QPDF_Reserved* asReserved(); + QPDF_Stream* asStream(); + QPDF_Stream* asStreamWithAssert(); + QPDF_String* asString(); void typeWarning(char const* expected_type, std::string const& warning); void objectWarning(std::string const& warning); @@ -1591,21 +1615,8 @@ class QPDFObjectHandle bool stop_at_streams); void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only); void releaseResolved(); - static void setObjectDescriptionFromInput( - QPDFObjectHandle, - QPDF*, - std::string const&, - std::shared_ptr<InputSource>, - qpdf_offset_t); - static QPDFObjectHandle parseInternal( - std::shared_ptr<InputSource> input, - std::string const& object_description, - QPDFTokenizer& tokenizer, - bool& empty, - StringDecrypter* decrypter, - QPDF* context, - bool content_stream); - void setParsedOffset(qpdf_offset_t offset); + + inline void setParsedOffset(qpdf_offset_t offset); void parseContentStream_internal( std::string const& description, ParserCallbacks* callbacks); static void parseContentStream_data( @@ -1618,15 +1629,10 @@ class QPDFObjectHandle static void warn(QPDF*, QPDFExc const&); void checkOwnership(QPDFObjectHandle const&) const; - bool initialized; - // Moving members of QPDFObjectHandle into a smart pointer incurs // a substantial performance penalty since QPDFObjectHandle // objects are copied around so frequently. - QPDF* qpdf; - QPDFObjGen og; std::shared_ptr<QPDFObject> obj; - bool reserved; }; #ifndef QPDF_NO_QPDF_STRING @@ -1846,4 +1852,58 @@ class QPDFObjectHandle::QPDFArrayItems QPDFObjectHandle oh; }; +inline QPDFObjGen +QPDFObjectHandle::getObjGen() const +{ + return isInitialized() ? obj->getObjGen() : QPDFObjGen(); +} + +inline int +QPDFObjectHandle::getObjectID() const +{ + return getObjGen().getObj(); +} + +inline int +QPDFObjectHandle::getGeneration() const +{ + return getObjGen().getGen(); +} + +inline bool +QPDFObjectHandle::isIndirect() const +{ + return (obj != nullptr) && (getObjectID() != 0); +} + +inline bool +QPDFObjectHandle::isInitialized() const +{ + return obj != nullptr; +} + +// Indirect object accessors +inline QPDF* +QPDFObjectHandle::getOwningQPDF( + bool allow_nullptr, std::string const& error_msg) const +{ + // Will be null for direct objects + auto result = isInitialized() ? this->obj->getQPDF() : nullptr; + if (!allow_nullptr && (result == nullptr)) { + throw std::runtime_error( + error_msg == "" ? "attempt to use a null qpdf object" : error_msg); + } + return result; +} + +inline void +QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset) +{ + // This is called during parsing on newly created direct objects, + // so we can't call dereference() here. + if (isInitialized()) { + this->obj->setParsedOffset(offset); + } +} + #endif // QPDFOBJECTHANDLE_HH diff --git a/include/qpdf/QPDFTokenizer.hh b/include/qpdf/QPDFTokenizer.hh index 2187f21e..33b2e710 100644 --- a/include/qpdf/QPDFTokenizer.hh +++ b/include/qpdf/QPDFTokenizer.hh @@ -193,60 +193,82 @@ class QPDFTokenizer QPDFTokenizer(QPDFTokenizer const&) = delete; QPDFTokenizer& operator=(QPDFTokenizer const&) = delete; - void resolveLiteral(); bool isSpace(char); bool isDelimiter(char); void findEI(std::shared_ptr<InputSource> input); enum state_e { st_top, + st_in_hexstring, + st_in_string, + st_in_hexstring_2nd, + st_name, + st_literal, st_in_space, st_in_comment, - st_in_string, + st_string_escape, + st_char_code, + st_string_after_cr, st_lt, st_gt, - st_literal, - st_in_hexstring, st_inline_image, + st_sign, + st_number, + st_real, + st_decimal, + st_name_hex1, + st_name_hex2, + st_before_token, st_token_ready }; - class Members - { - friend class QPDFTokenizer; - - public: - QPDF_DLL - ~Members() = default; + void handleCharacter(char); + void inBeforeToken(char); + void inTop(char); + void inSpace(char); + void inComment(char); + void inString(char); + void inName(char); + void inLt(char); + void inGt(char); + void inStringAfterCR(char); + void inStringEscape(char); + void inLiteral(char); + void inCharCode(char); + void inHexstring(char); + void inHexstring2nd(char); + void inInlineImage(char); + void inTokenReady(char); + void inNameHex1(char); + void inNameHex2(char); + void inSign(char); + void inDecimal(char); + void inNumber(char); + void inReal(char); + void reset(); - private: - Members(); - Members(Members const&) = delete; - void reset(); + // Lexer state + state_e state; - // Lexer state - state_e state; + bool allow_eof; + bool include_ignorable; - bool allow_eof; - bool include_ignorable; + // Current token accumulation + token_type_e type; + std::string val; + std::string raw_val; + std::string error_message; + bool before_token; + bool in_token; + char char_to_unread; + size_t inline_image_bytes; + bool bad; - // Current token accumulation - token_type_e type; - std::string val; - std::string raw_val; - std::string error_message; - bool unread_char; - char char_to_unread; - size_t inline_image_bytes; - - // State for strings - int string_depth; - bool string_ignoring_newline; - char bs_num_register[4]; - bool last_char_was_bs; - bool last_char_was_cr; - }; - std::shared_ptr<Members> m; + // State for strings + int string_depth; + int char_code; + char hex_char; + int digit_count; }; #endif // QPDFTOKENIZER_HH diff --git a/include/qpdf/QPDFValue.hh b/include/qpdf/QPDFValue.hh new file mode 100644 index 00000000..8b4f53b5 --- /dev/null +++ b/include/qpdf/QPDFValue.hh @@ -0,0 +1,130 @@ +// Copyright (c) 2005-2022 Jay Berkenbilt +// +// This file is part of qpdf. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. + +#ifndef QPDFVALUE_HH +#define QPDFVALUE_HH + +#include <qpdf/Constants.h> +#include <qpdf/DLL.h> +#include <qpdf/JSON.hh> +#include <qpdf/QPDFObjGen.hh> +#include <qpdf/Types.h> + +#include <string> + +class QPDF; +class QPDFObjectHandle; +class QPDFObject; + +class QPDFValue +{ + friend class QPDFObject; + + public: + virtual ~QPDFValue() = default; + + virtual std::shared_ptr<QPDFObject> shallowCopy() = 0; + virtual std::string unparse() = 0; + virtual JSON getJSON(int json_version) = 0; + virtual void + setDescription(QPDF* qpdf, std::string const& description) + { + owning_qpdf = qpdf; + object_description = description; + } + bool + getDescription(QPDF*& qpdf, std::string& description) + { + qpdf = owning_qpdf; + description = object_description; + return owning_qpdf != nullptr; + } + bool + hasDescription() + { + return owning_qpdf != nullptr; + } + void + setParsedOffset(qpdf_offset_t offset) + { + if (parsed_offset < 0) { + parsed_offset = offset; + } + } + qpdf_offset_t + getParsedOffset() + { + return parsed_offset; + } + QPDF* + getQPDF() + { + return qpdf; + } + QPDFObjGen + getObjGen() + { + return og; + } + + protected: + QPDFValue() : + type_code(::ot_uninitialized), + type_name("uninitialized") + { + } + QPDFValue(qpdf_object_type_e type_code, char const* type_name) : + type_code(type_code), + type_name(type_name) + { + } + QPDFValue( + qpdf_object_type_e type_code, + char const* type_name, + QPDF* qpdf, + QPDFObjGen const& og) : + type_code(type_code), + type_name(type_name), + qpdf(qpdf), + og(og) + { + } + virtual void + releaseResolved() + { + } + static std::shared_ptr<QPDFObject> do_create(QPDFValue*); + + private: + QPDFValue(QPDFValue const&) = delete; + QPDFValue& operator=(QPDFValue const&) = delete; + QPDF* owning_qpdf{nullptr}; + std::string object_description; + qpdf_offset_t parsed_offset{-1}; + const qpdf_object_type_e type_code; + char const* type_name; + + protected: + QPDF* qpdf{nullptr}; + QPDFObjGen og; +}; + +#endif // QPDFVALUE_HH diff --git a/include/qpdf/QTC.hh b/include/qpdf/QTC.hh index 1fa55901..70115981 100644 --- a/include/qpdf/QTC.hh +++ b/include/qpdf/QTC.hh @@ -24,10 +24,24 @@ #include <qpdf/DLL.h> +// Defining QPDF_DISABLE_QTC will effectively compile out any QTC::TC +// calls in any code that includes this file, but QTC will still be +// built into the library. That way, it is possible to build and +// package qpdf with QPDF_DISABLE_QTC while still making QTC::TC +// available to end users. + namespace QTC { QPDF_DLL - void TC(char const* const scope, char const* const ccase, int n = 0); + void TC_real(char const* const scope, char const* const ccase, int n = 0); + + inline void + TC(char const* const scope, char const* const ccase, int n = 0) + { +#ifndef QPDF_DISABLE_QTC + TC_real(scope, ccase, n); +#endif // QPDF_DISABLE_QTC + } }; // namespace QTC #endif // QTC_HH diff --git a/include/qpdf/QUtil.hh b/include/qpdf/QUtil.hh index 32aeae1f..96f4f7ed 100644 --- a/include/qpdf/QUtil.hh +++ b/include/qpdf/QUtil.hh @@ -25,6 +25,7 @@ #include <qpdf/DLL.h> #include <qpdf/PointerHolder.hh> #include <qpdf/Types.h> +#include <cstring> #include <functional> #include <list> #include <memory> @@ -489,16 +490,16 @@ namespace QUtil // classes without using ctype, which we avoid because of locale // considerations. QPDF_DLL - bool is_hex_digit(char); + inline bool is_hex_digit(char); QPDF_DLL - bool is_space(char); + inline bool is_space(char); QPDF_DLL - bool is_digit(char); + inline bool is_digit(char); QPDF_DLL - bool is_number(char const*); + inline bool is_number(char const*); // This method parses the numeric range syntax used by the qpdf // command-line tool. May throw std::runtime_error. @@ -524,6 +525,62 @@ namespace QUtil wchar_t const* const argv[], std::function<int(int, char const* const[])> realmain); #endif // QPDF_NO_WCHAR_T -}; // namespace QUtil + + // Try to return the maximum amount of memory allocated by the + // current process and its threads. Return 0 if unable to + // determine. This is Linux-specific and not implemented to be + // completely reliable. It is used during development for + // performance testing to detect changes that may significantly + // change memory usage. It is not recommended for use for other + // purposes. + QPDF_DLL + size_t get_max_memory_usage(); +}; // namespace QUtil + +inline bool +QUtil::is_hex_digit(char ch) +{ + return (ch && (strchr("0123456789abcdefABCDEF", ch) != nullptr)); +} + +inline bool +QUtil::is_space(char ch) +{ + return (ch && (strchr(" \f\n\r\t\v", ch) != nullptr)); +} + +inline bool +QUtil::is_digit(char ch) +{ + return ((ch >= '0') && (ch <= '9')); +} + +inline bool +QUtil::is_number(char const* p) +{ + // ^[\+\-]?(\.\d*|\d+(\.\d*)?)$ + if (!*p) { + return false; + } + if ((*p == '-') || (*p == '+')) { + ++p; + } + bool found_dot = false; + bool found_digit = false; + for (; *p; ++p) { + if (*p == '.') { + if (found_dot) { + // only one dot + return false; + } + found_dot = true; + } else if (QUtil::is_digit(*p)) { + found_digit = true; + } else { + return false; + } + } + return found_digit; +} #endif // QUTIL_HH diff --git a/include/qpdf/auto_job_c_main.hh b/include/qpdf/auto_job_c_main.hh index 90927ded..cc655c23 100644 --- a/include/qpdf/auto_job_c_main.hh +++ b/include/qpdf/auto_job_c_main.hh @@ -33,6 +33,7 @@ QPDF_DLL Config* qdf(); QPDF_DLL Config* rawStreamData(); QPDF_DLL Config* recompressFlate(); QPDF_DLL Config* removePageLabels(); +QPDF_DLL Config* reportMemUsage(); QPDF_DLL Config* requiresPassword(); QPDF_DLL Config* showEncryption(); QPDF_DLL Config* showEncryptionKey(); |