diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/qpdf/Constants.h | 2 | ||||
-rw-r--r-- | include/qpdf/QPDF.hh | 25 | ||||
-rw-r--r-- | include/qpdf/QPDFObject.hh | 140 | ||||
-rw-r--r-- | include/qpdf/QPDFObjectHandle.hh | 84 | ||||
-rw-r--r-- | include/qpdf/QPDFValue.hh | 130 |
5 files changed, 320 insertions, 61 deletions
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/QPDF.hh b/include/qpdf/QPDF.hh index 12d41eff..bcd85cd2 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -843,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; @@ -1174,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( @@ -1727,7 +1729,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/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 c1bed81f..16e8dc8b 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -43,8 +43,18 @@ 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; @@ -316,7 +326,7 @@ class QPDFObjectHandle }; QPDF_DLL - QPDFObjectHandle(); + QPDFObjectHandle() = default; QPDF_DLL QPDFObjectHandle(QPDFObjectHandle const&) = default; QPDF_DLL @@ -963,8 +973,8 @@ class QPDFObjectHandle // null for a direct object if allow_nullptr is set to true or // throws a runtime error otherwise. QPDF_DLL - inline QPDF* - getOwningQPDF(bool allow_nullptr = true, std::string const& error_msg = ""); + 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, @@ -1443,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( @@ -1458,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; @@ -1483,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; @@ -1563,18 +1577,32 @@ class QPDFObjectHandle bool isImage(bool exclude_imagemask = true); private: - QPDFObjectHandle(QPDF*, QPDFObjGen const& og); - QPDFObjectHandle(std::shared_ptr<QPDFObject> const&); + 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); @@ -1601,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 @@ -1832,44 +1855,45 @@ class QPDFObjectHandle::QPDFArrayItems inline QPDFObjGen QPDFObjectHandle::getObjGen() const { - return og; + return isInitialized() ? obj->getObjGen() : QPDFObjGen(); } inline int QPDFObjectHandle::getObjectID() const { - return og.getObj(); + return getObjGen().getObj(); } inline int QPDFObjectHandle::getGeneration() const { - return og.getGen(); + return getObjGen().getGen(); } inline bool QPDFObjectHandle::isIndirect() const { - return initialized && (getObjectID() != 0); + return (obj != nullptr) && (getObjectID() != 0); } inline bool QPDFObjectHandle::isInitialized() const { - return initialized; + return obj != nullptr; } // Indirect object accessors inline QPDF* QPDFObjectHandle::getOwningQPDF( - bool allow_nullptr, std::string const& error_msg) + bool allow_nullptr, std::string const& error_msg) const { // Will be null for direct objects - if (!allow_nullptr && (this->qpdf == nullptr)) { + 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 this->qpdf; + return result; } inline void @@ -1877,7 +1901,7 @@ QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset) { // This is called during parsing on newly created direct objects, // so we can't call dereference() here. - if (this->obj.get()) { + if (isInitialized()) { this->obj->setParsedOffset(offset); } } 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 |