From bd300be08d94add92657aef1d46afd100459302b Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 12:33:07 +0100 Subject: Replace calls to QPDFObjectHandle::Factory::newIndirect where possible --- libqpdf/QPDF.cc | 4 ++-- libqpdf/QPDF_linearization.cc | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 6ae74b25..c39e2456 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1397,7 +1397,7 @@ QPDF::fixDanglingReferences(bool force) std::list queue; queue.push_back(this->m->trailer); for (auto const& og: to_process) { - QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect(this, og); + auto obj = getObjectByObjGen(og); if (obj.isDictionary() || obj.isArray()) { queue.push_back(obj); } else if (obj.isStream()) { @@ -1463,7 +1463,7 @@ QPDF::getAllObjects() std::vector result; for (auto const& iter: this->m->obj_cache) { QPDFObjGen const& og = iter.first; - result.push_back(QPDFObjectHandle::Factory::newIndirect(this, og)); + result.push_back(getObjectByObjGen(og)); } return result; } diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index e988092e..e09f7b68 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -137,8 +137,7 @@ QPDF::isLinearized() return false; } - QPDFObjectHandle candidate = QPDFObjectHandle::Factory::newIndirect( - this, QPDFObjGen(lindict_obj, 0)); + auto candidate = getObjectByID(lindict_obj, 0); if (!candidate.isDictionary()) { return false; } -- cgit v1.2.3-54-g00ecf From 7248cab71b69efe1e5efa3f1400d4d3970271a77 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 13:12:17 +0100 Subject: Add class QPDF_Unresolved Allow QPDFObjectHandle::obj to be set prior resolving object. ot_unresolved has been appended to the list object types in order to preserve the output of existing test cases. --- include/qpdf/Constants.h | 2 ++ include/qpdf/QPDFObject.hh | 1 + libqpdf/CMakeLists.txt | 1 + libqpdf/QPDF_Unresolved.cc | 41 +++++++++++++++++++++++++++++++++++++++++ libqpdf/qpdf/QPDF_Unresolved.hh | 21 +++++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 libqpdf/QPDF_Unresolved.cc create mode 100644 libqpdf/qpdf/QPDF_Unresolved.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/QPDFObject.hh b/include/qpdf/QPDFObject.hh index eb7c4b90..8b6f7403 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -61,6 +61,7 @@ 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; virtual ~QPDFObject() = default; virtual std::shared_ptr shallowCopy() = 0; diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt index 51f7476d..7a4ef333 100644 --- a/libqpdf/CMakeLists.txt +++ b/libqpdf/CMakeLists.txt @@ -99,6 +99,7 @@ set(libqpdf_SOURCES QPDF_Reserved.cc QPDF_Stream.cc QPDF_String.cc + QPDF_Unresolved.cc QPDF_encryption.cc QPDF_json.cc QPDF_linearization.cc diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc new file mode 100644 index 00000000..f348ec36 --- /dev/null +++ b/libqpdf/QPDF_Unresolved.cc @@ -0,0 +1,41 @@ +#include + +#include + +std::shared_ptr +QPDF_Unresolved::create() +{ + return do_create(new QPDF_Unresolved()); +} + +std::shared_ptr +QPDF_Unresolved::shallowCopy() +{ + return create(); +} + +std::string +QPDF_Unresolved::unparse() +{ + throw std::logic_error( + "attempted to unparse an unresolveded QPDFObjectHandle"); + return ""; +} + +JSON +QPDF_Unresolved::getJSON(int json_version) +{ + return JSON::makeNull(); +} + +QPDFObject::object_type_e +QPDF_Unresolved::getTypeCode() const +{ + return QPDFObject::ot_unresolved; +} + +char const* +QPDF_Unresolved::getTypeName() const +{ + return "unresolved"; +} diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh new file mode 100644 index 00000000..4f1c5238 --- /dev/null +++ b/libqpdf/qpdf/QPDF_Unresolved.hh @@ -0,0 +1,21 @@ +#ifndef QPDF_UNRESOLVED_HH +#define QPDF_UNRESOLVED_HH + +#include + +class QPDF_Unresolved: public QPDFObject +{ + public: + virtual ~QPDF_Unresolved() = default; + static std::shared_ptr create(); + virtual std::shared_ptr shallowCopy(); + virtual std::string unparse(); + virtual JSON getJSON(int json_version); + virtual QPDFObject::object_type_e getTypeCode() const; + virtual char const* getTypeName() const; + + private: + QPDF_Unresolved() = default; +}; + +#endif // QPDF_UNRESOLVED_HH -- cgit v1.2.3-54-g00ecf From 07b66eb0b688072d408c8eb51eaa1025c4ca4d7d Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 16:39:57 +0100 Subject: Remove QPDFObjectHandle::reserved --- include/qpdf/QPDFObjectHandle.hh | 1 - libqpdf/QPDFObjectHandle.cc | 38 ++++++++++---------------------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index c1bed81f..eeccebf2 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1609,7 +1609,6 @@ class QPDFObjectHandle QPDF* qpdf; QPDFObjGen og; std::shared_ptr obj; - bool reserved; }; #ifndef QPDF_NO_QPDF_STRING diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 2227a77b..5874186e 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -236,24 +236,21 @@ LastChar::getLastChar() QPDFObjectHandle::QPDFObjectHandle() : initialized(false), - qpdf(nullptr), - reserved(false) + qpdf(nullptr) { } QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, QPDFObjGen const& og) : initialized(true), qpdf(qpdf), - og(og), - reserved(false) + og(og) { } QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr const& data) : initialized(true), qpdf(nullptr), - obj(data), - reserved(false) + obj(data) { } @@ -412,7 +409,7 @@ bool QPDFObjectHandle::isReserved() { // dereference will clear reserved if this has been replaced - return dereference() && this->reserved; + return dereference() && QPDFObjectTypeAccessor::check(obj); } bool @@ -1648,7 +1645,7 @@ QPDFObjectHandle::unparseResolved() if (!dereference()) { throw std::logic_error( "attempted to dereference an uninitialized QPDFObjectHandle"); - } else if (this->reserved) { + } else if (isReserved()) { throw std::logic_error( "QPDFObjectHandle: attempting to unparse a reserved object"); } @@ -1680,7 +1677,7 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) } else if (!dereference()) { throw std::logic_error( "attempted to dereference an uninitialized QPDFObjectHandle"); - } else if (this->reserved) { + } else if (isReserved()) { throw std::logic_error( "QPDFObjectHandle: attempting to unparse a reserved object"); } else { @@ -2159,7 +2156,6 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) // number, but then return an unresolved handle to the object. QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved()); QPDFObjectHandle result = newIndirect(qpdf, reserved.getObjGen()); - result.reserved = true; return result; } @@ -2567,24 +2563,10 @@ QPDFObjectHandle::dereference() if (!this->initialized) { return false; } - if (this->obj.get() && getObjectID() && - QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj)) { - this->obj = nullptr; - } - if (this->obj == nullptr) { - std::shared_ptr obj = - QPDF::Resolver::resolve(this->qpdf, getObjGen()); - if (obj == nullptr) { - // QPDF::resolve never returns an uninitialized object, but - // check just in case. - this->obj = QPDF_Null::create(); - } else if (dynamic_cast(obj.get())) { - // Do not resolve - this->reserved = true; - } else { - this->reserved = false; - this->obj = obj; - } + if (this->obj() == nullptr || + (getObjectID() && + QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj))) { + obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); } return true; } -- cgit v1.2.3-54-g00ecf From 16841bec32bb4323a60699cf42f0d74ef495b73f Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 17:18:00 +0100 Subject: Remove QPDFObjectHandle::makeReserved --- include/qpdf/QPDFObjectHandle.hh | 7 ------- libqpdf/QPDF.cc | 5 +++-- libqpdf/QPDFObjectHandle.cc | 12 +----------- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index eeccebf2..beb69421 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1458,12 +1458,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; @@ -1574,7 +1568,6 @@ class QPDFObjectHandle QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length); - static QPDFObjectHandle makeReserved(); void typeWarning(char const* expected_type, std::string const& warning); void objectWarning(std::string const& warning); diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index c39e2456..7b357b13 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -2144,9 +2145,9 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) QPDFObjectHandle QPDF::reserveObjectIfNotExists(QPDFObjGen const& og) { - if ((!this->m->obj_cache.count(og)) && (!this->m->xref_table.count(og))) { + if ((!m->obj_cache.count(og)) && (!m->xref_table.count(og))) { resolve(og); - replaceObject(og, QPDFObjectHandle::Factory::makeReserved()); + m->obj_cache[og].object = QPDF_Reserved::create(); } return getObject(og); } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 5874186e..8c98c87b 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2152,17 +2152,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const& data) QPDFObjectHandle QPDFObjectHandle::newReserved(QPDF* qpdf) { - // Reserve a spot for this object by assigning it an object - // number, but then return an unresolved handle to the object. - QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved()); - QPDFObjectHandle result = newIndirect(qpdf, reserved.getObjGen()); - return result; -} - -QPDFObjectHandle -QPDFObjectHandle::makeReserved() -{ - return QPDFObjectHandle(QPDF_Reserved::create()); + return qpdf->makeIndirectObject(QPDFObjectHandle(QPDF_Reserved::create())); } void -- cgit v1.2.3-54-g00ecf From 2a2eebcaea2b27bc86390dac2ee27ad5620f5eda Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 16:20:24 +0100 Subject: Modify newIndirect to set QPDFObjectHandle::obj --- include/qpdf/QPDF.hh | 2 ++ include/qpdf/QPDFObjectHandle.hh | 18 +++++++++++++++--- libqpdf/QPDF.cc | 23 +++++++++++++++++------ libqpdf/QPDFObjectHandle.cc | 15 +++++---------- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 12d41eff..469bad55 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1180,6 +1180,8 @@ class QPDF void stopOnError(std::string const& message); QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); QPDFObjectHandle reserveStream(QPDFObjGen const& og); + QPDFObjectHandle + newIndirect(QPDFObjGen const&, std::shared_ptr const&); // Calls finish() on the pipeline when done but does not delete it bool pipeStreamData( diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index beb69421..3c7b62f8 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1443,9 +1443,12 @@ class QPDFObjectHandle private: static QPDFObjectHandle - newIndirect(QPDF* qpdf, QPDFObjGen const& og) + newIndirect( + QPDF* qpdf, + QPDFObjGen const& og, + std::shared_ptr const& obj) { - return QPDFObjectHandle::newIndirect(qpdf, og); + return QPDFObjectHandle(qpdf, og, obj); } static QPDFObjectHandle newStream( @@ -1557,7 +1560,16 @@ class QPDFObjectHandle bool isImage(bool exclude_imagemask = true); private: - QPDFObjectHandle(QPDF*, QPDFObjGen const& og); + QPDFObjectHandle( + QPDF* qpdf, + QPDFObjGen const& og, + std::shared_ptr const& obj) : + initialized(true), + qpdf(qpdf), + og(og), + obj(obj) + { + } QPDFObjectHandle(std::shared_ptr const&); // Private object factory methods diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 7b357b13..191d98f3 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1463,8 +1463,7 @@ QPDF::getAllObjects() fixDanglingReferences(true); std::vector result; for (auto const& iter: this->m->obj_cache) { - QPDFObjGen const& og = iter.first; - result.push_back(getObjectByObjGen(og)); + result.push_back(newIndirect(iter.first, iter.second.object)); } return result; } @@ -2128,6 +2127,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number) } } +QPDFObjectHandle +QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) +{ + if (!obj->hasDescription()) { + obj->setDescription(this, "object " + og.unparse(' ')); + } + return QPDFObjectHandle::Factory::newIndirect(this, og, obj); +} + QPDFObjectHandle QPDF::makeIndirectObject(QPDFObjectHandle oh) { @@ -2137,9 +2145,9 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) "max object id is too high to create new objects"); } QPDFObjGen next(max_objid + 1, 0); - this->m->obj_cache[next] = + m->obj_cache[next] = ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); - return QPDFObjectHandle::Factory::newIndirect(this, next); + return newIndirect(next, m->obj_cache[next].object); } QPDFObjectHandle @@ -2148,8 +2156,10 @@ QPDF::reserveObjectIfNotExists(QPDFObjGen const& og) if ((!m->obj_cache.count(og)) && (!m->xref_table.count(og))) { resolve(og); m->obj_cache[og].object = QPDF_Reserved::create(); + return newIndirect(og, m->obj_cache[og].object); + } else { + return getObject(og); } - return getObject(og); } QPDFObjectHandle @@ -2162,7 +2172,8 @@ QPDF::reserveStream(QPDFObjGen const& og) QPDFObjectHandle QPDF::getObject(QPDFObjGen const& og) { - return QPDFObjectHandle::Factory::newIndirect(this, og); + auto obj = (og.getObj() != 0) ? resolve(og) : QPDF_Null::create(); + return newIndirect(og, obj); } QPDFObjectHandle diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 8c98c87b..f872e984 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -240,13 +241,6 @@ QPDFObjectHandle::QPDFObjectHandle() : { } -QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, QPDFObjGen const& og) : - initialized(true), - qpdf(qpdf), - og(og) -{ -} - QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr const& data) : initialized(true), qpdf(nullptr), @@ -1953,7 +1947,7 @@ QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og) return newNull(); } - return QPDFObjectHandle(qpdf, og); + return QPDFObjectHandle(qpdf, og, QPDF_Unresolved::create()); } QPDFObjectHandle @@ -2553,10 +2547,11 @@ QPDFObjectHandle::dereference() if (!this->initialized) { return false; } - if (this->obj() == nullptr || + if ((this->obj->getTypeCode() == QPDFObject::ot_unresolved) || (getObjectID() && QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj))) { - obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); + this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); + } return true; } -- cgit v1.2.3-54-g00ecf From 114bffa0894d8bac7151201404cb6d8d62bd9b4a Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 19:13:29 +0100 Subject: Add private methods QPDFObjectHandle::asArray etc Centralise casting of QPDFObjects and reduce repeated dereferencing. --- include/qpdf/QPDFObjectHandle.hh | 38 +++- libqpdf/QPDF.cc | 9 +- libqpdf/QPDFObjectHandle.cc | 411 +++++++++++++++++++++++---------------- libqpdf/QPDF_Reserved.cc | 6 +- 4 files changed, 287 insertions(+), 177 deletions(-) diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 3c7b62f8..af454e75 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; @@ -1480,6 +1490,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; @@ -1581,6 +1601,20 @@ class QPDFObjectHandle qpdf_offset_t offset, size_t length); + 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); void assertType(char const* type_name, bool istype); @@ -1881,7 +1915,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 (initialized) { this->obj->setParsedOffset(offset); } } diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 191d98f3..22f62a8b 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1420,8 +1420,7 @@ QPDF::fixDanglingReferences(bool force) to_check.push_back(iter.second); } } else if (obj.isArray()) { - QPDF_Array* arr = dynamic_cast( - QPDFObjectHandle::ObjAccessor::getObject(obj).get()); + auto arr = QPDFObjectHandle::ObjAccessor::asArray(obj); arr->addExplicitElementsToList(to_check); } for (auto sub: to_check) { @@ -2468,12 +2467,12 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) QPDFObjGen local_og(result.getObjGen()); // Copy information from the foreign stream so we can pipe its // data later without keeping the original QPDF object around. + QPDF* foreign_stream_qpdf = foreign.getOwningQPDF( false, "unable to retrieve owning qpdf from foreign stream"); - QPDF_Stream* stream = dynamic_cast( - QPDFObjectHandle::ObjAccessor::getObject(foreign).get()); - if (!stream) { + auto stream = QPDFObjectHandle::ObjAccessor::asStream(foreign); + if (stream == nullptr) { throw std::logic_error("unable to retrieve underlying" " stream object from foreign stream"); } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index f872e984..f60d131a 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -277,24 +277,91 @@ QPDFObjectHandle::getTypeName() return dereference() ? this->obj->getTypeName() : "uninitialized"; } -namespace +QPDF_Array* +QPDFObjectHandle::asArray() { - template - class QPDFObjectTypeAccessor - { - public: - static bool - check(std::shared_ptr const& o) - { - return (o && dynamic_cast(o.get())); - } - }; -} // namespace + return isArray() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Bool* +QPDFObjectHandle::asBool() +{ + return isBool() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Dictionary* +QPDFObjectHandle::asDictionary() +{ + return isDictionary() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_InlineImage* +QPDFObjectHandle::asInlineImage() +{ + return isInlineImage() ? dynamic_cast(obj.get()) + : nullptr; +} + +QPDF_Integer* +QPDFObjectHandle::asInteger() +{ + return isInteger() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Name* +QPDFObjectHandle::asName() +{ + return isName() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Null* +QPDFObjectHandle::asNull() +{ + return isNull() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Operator* +QPDFObjectHandle::asOperator() +{ + return isOperator() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Real* +QPDFObjectHandle::asReal() +{ + return isReal() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Reserved* +QPDFObjectHandle::asReserved() +{ + return isReserved() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Stream* +QPDFObjectHandle::asStream() +{ + return isStream() ? dynamic_cast(obj.get()) : nullptr; +} + +QPDF_Stream* +QPDFObjectHandle::asStreamWithAssert() +{ + auto stream = asStream(); + assertType("stream", stream); + return stream; +} + +QPDF_String* +QPDFObjectHandle::asString() +{ + return isString() ? dynamic_cast(obj.get()) : nullptr; +} bool QPDFObjectHandle::isBool() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_boolean); } bool @@ -303,26 +370,26 @@ QPDFObjectHandle::isDirectNull() const // Don't call dereference() -- this is a const method, and we know // objid == 0, so there's nothing to resolve. return ( - this->initialized && (getObjectID() == 0) && - QPDFObjectTypeAccessor::check(obj)); + initialized && (getObjectID() == 0) && + (obj->getTypeCode() == QPDFObject::ot_null)); } bool QPDFObjectHandle::isNull() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_null); } bool QPDFObjectHandle::isInteger() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_integer); } bool QPDFObjectHandle::isReal() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_real); } bool @@ -359,51 +426,49 @@ QPDFObjectHandle::getValueAsNumber(double& value) bool QPDFObjectHandle::isName() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_name); } bool QPDFObjectHandle::isString() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_string); } bool QPDFObjectHandle::isOperator() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_operator); } bool QPDFObjectHandle::isInlineImage() { - return dereference() && - QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_inlineimage); } bool QPDFObjectHandle::isArray() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_array); } bool QPDFObjectHandle::isDictionary() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_dictionary); } bool QPDFObjectHandle::isStream() { - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_stream); } bool QPDFObjectHandle::isReserved() { - // dereference will clear reserved if this has been replaced - return dereference() && QPDFObjectTypeAccessor::check(obj); + return dereference() && (obj->getTypeCode() == QPDFObject::ot_reserved); } bool @@ -441,8 +506,9 @@ QPDFObjectHandle::isStreamOfType( bool QPDFObjectHandle::getBoolValue() { - if (isBool()) { - return dynamic_cast(obj.get())->getVal(); + auto boolean = asBool(); + if (boolean) { + return boolean->getVal(); } else { typeWarning("boolean", "returning false"); QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); @@ -453,10 +519,11 @@ QPDFObjectHandle::getBoolValue() bool QPDFObjectHandle::getValueAsBool(bool& value) { - if (!isBool()) { + auto boolean = asBool(); + if (boolean == nullptr) { return false; } - value = dynamic_cast(obj.get())->getVal(); + value = boolean->getVal(); return true; } @@ -465,8 +532,9 @@ QPDFObjectHandle::getValueAsBool(bool& value) long long QPDFObjectHandle::getIntValue() { - if (isInteger()) { - return dynamic_cast(obj.get())->getVal(); + auto integer = asInteger(); + if (integer) { + return integer->getVal(); } else { typeWarning("integer", "returning 0"); QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); @@ -477,10 +545,11 @@ QPDFObjectHandle::getIntValue() bool QPDFObjectHandle::getValueAsInt(long long& value) { - if (!isInteger()) { + auto integer = asInteger(); + if (integer == nullptr) { return false; } - value = dynamic_cast(obj.get())->getVal(); + value = integer->getVal(); return true; } @@ -576,8 +645,9 @@ QPDFObjectHandle::getValueAsUInt(unsigned int& value) std::string QPDFObjectHandle::getRealValue() { - if (isReal()) { - return dynamic_cast(obj.get())->getVal(); + auto real = asReal(); + if (real) { + return real->getVal(); } else { typeWarning("real", "returning 0.0"); QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0"); @@ -588,10 +658,11 @@ QPDFObjectHandle::getRealValue() bool QPDFObjectHandle::getValueAsReal(std::string& value) { - if (!isReal()) { + auto real = asReal(); + if (real == nullptr) { return false; } - value = dynamic_cast(obj.get())->getVal(); + value = real->getVal(); return true; } @@ -600,8 +671,9 @@ QPDFObjectHandle::getValueAsReal(std::string& value) std::string QPDFObjectHandle::getName() { - if (isName()) { - return dynamic_cast(obj.get())->getName(); + auto name = asName(); + if (name) { + return name->getName(); } else { typeWarning("name", "returning dummy name"); QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name"); @@ -612,10 +684,11 @@ QPDFObjectHandle::getName() bool QPDFObjectHandle::getValueAsName(std::string& value) { - if (!isName()) { + auto name = asName(); + if (name == nullptr) { return false; } - value = dynamic_cast(obj.get())->getName(); + value = name->getName(); return true; } @@ -624,8 +697,9 @@ QPDFObjectHandle::getValueAsName(std::string& value) std::string QPDFObjectHandle::getStringValue() { - if (isString()) { - return dynamic_cast(obj.get())->getVal(); + auto str = asString(); + if (str) { + return str->getVal(); } else { typeWarning("string", "returning empty string"); QTC::TC("qpdf", "QPDFObjectHandle string returning empty string"); @@ -636,18 +710,20 @@ QPDFObjectHandle::getStringValue() bool QPDFObjectHandle::getValueAsString(std::string& value) { - if (!isString()) { + auto str = asString(); + if (str == nullptr) { return false; } - value = dynamic_cast(obj.get())->getVal(); + value = str->getVal(); return true; } std::string QPDFObjectHandle::getUTF8Value() { - if (isString()) { - return dynamic_cast(obj.get())->getUTF8Val(); + auto str = asString(); + if (str) { + return str->getUTF8Val(); } else { typeWarning("string", "returning empty string"); QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8"); @@ -658,10 +734,11 @@ QPDFObjectHandle::getUTF8Value() bool QPDFObjectHandle::getValueAsUTF8(std::string& value) { - if (!isString()) { + auto str = asString(); + if (str == nullptr) { return false; } - value = dynamic_cast(obj.get())->getUTF8Val(); + value = str->getUTF8Val(); return true; } @@ -670,8 +747,9 @@ QPDFObjectHandle::getValueAsUTF8(std::string& value) std::string QPDFObjectHandle::getOperatorValue() { - if (isOperator()) { - return dynamic_cast(obj.get())->getVal(); + auto op = asOperator(); + if (op) { + return op->getVal(); } else { typeWarning("operator", "returning fake value"); QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value"); @@ -682,18 +760,20 @@ QPDFObjectHandle::getOperatorValue() bool QPDFObjectHandle::getValueAsOperator(std::string& value) { - if (!isOperator()) { + auto op = asOperator(); + if (op == nullptr) { return false; } - value = dynamic_cast(obj.get())->getVal(); + value = op->getVal(); return true; } std::string QPDFObjectHandle::getInlineImageValue() { - if (isInlineImage()) { - return dynamic_cast(obj.get())->getVal(); + auto image = asInlineImage(); + if (image) { + return image->getVal(); } else { typeWarning("inlineimage", "returning empty data"); QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data"); @@ -704,10 +784,11 @@ QPDFObjectHandle::getInlineImageValue() bool QPDFObjectHandle::getValueAsInlineImage(std::string& value) { - if (!isInlineImage()) { + auto image = asInlineImage(); + if (image == nullptr) { return false; } - value = dynamic_cast(obj.get())->getVal(); + value = image->getVal(); return true; } @@ -722,8 +803,9 @@ QPDFObjectHandle::aitems() int QPDFObjectHandle::getArrayNItems() { - if (isArray()) { - return dynamic_cast(obj.get())->getNItems(); + auto array = asArray(); + if (array) { + return array->getNItems(); } else { typeWarning("array", "treating as empty"); QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); @@ -735,11 +817,12 @@ QPDFObjectHandle QPDFObjectHandle::getArrayItem(int n) { QPDFObjectHandle result; - if (isArray() && (n < getArrayNItems()) && (n >= 0)) { - result = dynamic_cast(obj.get())->getItem(n); + auto array = asArray(); + if (array && (n < array->getNItems()) && (n >= 0)) { + result = array->getItem(n); } else { result = newNull(); - if (isArray()) { + if (array) { objectWarning("returning null for out of bounds array access"); QTC::TC("qpdf", "QPDFObjectHandle array bounds"); } else { @@ -748,7 +831,7 @@ QPDFObjectHandle::getArrayItem(int n) } QPDF* context = nullptr; std::string description; - if (this->obj->getDescription(context, description)) { + if (obj->getDescription(context, description)) { result.setObjectDescription( context, description + " -> null returned from invalid array access"); @@ -760,14 +843,12 @@ QPDFObjectHandle::getArrayItem(int n) bool QPDFObjectHandle::isRectangle() { - if (!isArray()) { - return false; - } - if (getArrayNItems() != 4) { + auto array = asArray(); + if ((array == nullptr) || (array->getNItems() != 4)) { return false; } for (int i = 0; i < 4; ++i) { - if (!getArrayItem(i).isNumber()) { + if (!array->getItem(i).isNumber()) { return false; } } @@ -777,14 +858,12 @@ QPDFObjectHandle::isRectangle() bool QPDFObjectHandle::isMatrix() { - if (!isArray()) { - return false; - } - if (getArrayNItems() != 6) { + auto array = asArray(); + if ((array == nullptr) || (array->getNItems() != 6)) { return false; } for (int i = 0; i < 6; ++i) { - if (!getArrayItem(i).isNumber()) { + if (!array->getItem(i).isNumber()) { return false; } } @@ -796,13 +875,14 @@ QPDFObjectHandle::getArrayAsRectangle() { Rectangle result; if (isRectangle()) { + auto array = asArray(); // Rectangle coordinates are always supposed to be llx, lly, // urx, ury, but files have been found in the wild where // llx > urx or lly > ury. - double i0 = getArrayItem(0).getNumericValue(); - double i1 = getArrayItem(1).getNumericValue(); - double i2 = getArrayItem(2).getNumericValue(); - double i3 = getArrayItem(3).getNumericValue(); + double i0 = array->getItem(0).getNumericValue(); + double i1 = array->getItem(1).getNumericValue(); + double i2 = array->getItem(2).getNumericValue(); + double i3 = array->getItem(3).getNumericValue(); result = Rectangle( std::min(i0, i2), std::min(i1, i3), @@ -817,13 +897,14 @@ QPDFObjectHandle::getArrayAsMatrix() { Matrix result; if (isMatrix()) { + auto array = asArray(); result = Matrix( - getArrayItem(0).getNumericValue(), - getArrayItem(1).getNumericValue(), - getArrayItem(2).getNumericValue(), - getArrayItem(3).getNumericValue(), - getArrayItem(4).getNumericValue(), - getArrayItem(5).getNumericValue()); + array->getItem(0).getNumericValue(), + array->getItem(1).getNumericValue(), + array->getItem(2).getNumericValue(), + array->getItem(3).getNumericValue(), + array->getItem(4).getNumericValue(), + array->getItem(5).getNumericValue()); } return result; } @@ -832,8 +913,9 @@ std::vector QPDFObjectHandle::getArrayAsVector() { std::vector result; - if (isArray()) { - dynamic_cast(obj.get())->getAsVector(result); + auto array = asArray(); + if (array) { + array->getAsVector(result); } else { typeWarning("array", "treating as empty"); QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector"); @@ -846,9 +928,10 @@ QPDFObjectHandle::getArrayAsVector() void QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) { - if (isArray()) { + auto array = asArray(); + if (array) { checkOwnership(item); - dynamic_cast(obj.get())->setItem(n, item); + array->setItem(n, item); } else { typeWarning("array", "ignoring attempt to set item"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item"); @@ -858,11 +941,12 @@ QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) void QPDFObjectHandle::setArrayFromVector(std::vector const& items) { - if (isArray()) { + auto array = asArray(); + if (array) { for (auto const& item: items) { checkOwnership(item); } - dynamic_cast(obj.get())->setFromVector(items); + array->setFromVector(items); } else { typeWarning("array", "ignoring attempt to replace items"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items"); @@ -872,8 +956,9 @@ QPDFObjectHandle::setArrayFromVector(std::vector const& items) void QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item) { - if (isArray()) { - dynamic_cast(obj.get())->insertItem(at, item); + auto array = asArray(); + if (array) { + array->insertItem(at, item); } else { typeWarning("array", "ignoring attempt to insert item"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item"); @@ -890,9 +975,10 @@ QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const& item) void QPDFObjectHandle::appendItem(QPDFObjectHandle const& item) { - if (isArray()) { + auto array = asArray(); + if (array) { checkOwnership(item); - dynamic_cast(obj.get())->appendItem(item); + array->appendItem(item); } else { typeWarning("array", "ignoring attempt to append item"); QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item"); @@ -909,10 +995,11 @@ QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const& item) void QPDFObjectHandle::eraseItem(int at) { - if (isArray() && (at < getArrayNItems()) && (at >= 0)) { - dynamic_cast(obj.get())->eraseItem(at); + auto array = asArray(); + if (array && (at < array->getNItems()) && (at >= 0)) { + array->eraseItem(at); } else { - if (isArray()) { + if (array) { objectWarning("ignoring attempt to erase out of bounds array item"); QTC::TC("qpdf", "QPDFObjectHandle erase array bounds"); } else { @@ -926,8 +1013,9 @@ QPDFObjectHandle QPDFObjectHandle::eraseItemAndGetOld(int at) { auto result = QPDFObjectHandle::newNull(); - if (isArray() && (at < getArrayNItems()) && (at >= 0)) { - result = getArrayItem(at); + auto array = asArray(); + if (array && (at < array->getNItems()) && (at >= 0)) { + result = array->getItem(at); } eraseItem(at); return result; @@ -944,8 +1032,9 @@ QPDFObjectHandle::ditems() bool QPDFObjectHandle::hasKey(std::string const& key) { - if (isDictionary()) { - return dynamic_cast(obj.get())->hasKey(key); + auto dict = asDictionary(); + if (dict) { + return dict->hasKey(key); } else { typeWarning( "dictionary", "returning false for a key containment request"); @@ -958,15 +1047,16 @@ QPDFObjectHandle QPDFObjectHandle::getKey(std::string const& key) { QPDFObjectHandle result; - if (isDictionary()) { - result = dynamic_cast(obj.get())->getKey(key); + auto dict = asDictionary(); + if (dict) { + result = dict->getKey(key); } else { typeWarning("dictionary", "returning null for attempted key retrieval"); QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); result = newNull(); QPDF* qpdf = nullptr; std::string description; - if (this->obj->getDescription(qpdf, description)) { + if (obj->getDescription(qpdf, description)) { result.setObjectDescription( qpdf, (description + " -> null returned from getting key " + key + @@ -986,8 +1076,9 @@ std::set QPDFObjectHandle::getKeys() { std::set result; - if (isDictionary()) { - result = dynamic_cast(obj.get())->getKeys(); + auto dict = asDictionary(); + if (dict) { + result = dict->getKeys(); } else { typeWarning("dictionary", "treating as empty"); QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys"); @@ -999,8 +1090,9 @@ std::map QPDFObjectHandle::getDictAsMap() { std::map result; - if (isDictionary()) { - result = dynamic_cast(obj.get())->getAsMap(); + auto dict = asDictionary(); + if (dict) { + result = dict->getAsMap(); } else { typeWarning("dictionary", "treating as empty"); QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap"); @@ -1191,9 +1283,10 @@ void QPDFObjectHandle::replaceKey( std::string const& key, QPDFObjectHandle const& value) { - if (isDictionary()) { + auto dict = asDictionary(); + if (dict) { checkOwnership(value); - dynamic_cast(obj.get())->replaceKey(key, value); + dict->replaceKey(key, value); } else { typeWarning("dictionary", "ignoring key replacement request"); QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey"); @@ -1220,8 +1313,9 @@ QPDFObjectHandle::replaceKeyAndGetOld( void QPDFObjectHandle::removeKey(std::string const& key) { - if (isDictionary()) { - dynamic_cast(obj.get())->removeKey(key); + auto dict = asDictionary(); + if (dict) { + dict->removeKey(key); } else { typeWarning("dictionary", "ignoring key removal request"); QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey"); @@ -1232,8 +1326,9 @@ QPDFObjectHandle QPDFObjectHandle::removeKeyAndGetOld(std::string const& key) { auto result = QPDFObjectHandle::newNull(); - if (isDictionary()) { - result = getKey(key); + auto dict = asDictionary(); + if (dict) { + result = dict->getKey(key); } removeKey(key); return result; @@ -1250,50 +1345,43 @@ QPDFObjectHandle::replaceOrRemoveKey( QPDFObjectHandle QPDFObjectHandle::getDict() { - assertStream(); - return dynamic_cast(obj.get())->getDict(); + return asStreamWithAssert()->getDict(); } void QPDFObjectHandle::setFilterOnWrite(bool val) { - assertStream(); - dynamic_cast(obj.get())->setFilterOnWrite(val); + asStreamWithAssert()->setFilterOnWrite(val); } bool QPDFObjectHandle::getFilterOnWrite() { - assertStream(); - return dynamic_cast(obj.get())->getFilterOnWrite(); + return asStreamWithAssert()->getFilterOnWrite(); } bool QPDFObjectHandle::isDataModified() { - assertStream(); - return dynamic_cast(obj.get())->isDataModified(); + return asStreamWithAssert()->isDataModified(); } void QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) { - assertStream(); - dynamic_cast(obj.get())->replaceDict(new_dict); + asStreamWithAssert()->replaceDict(new_dict); } std::shared_ptr QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) { - assertStream(); - return dynamic_cast(obj.get())->getStreamData(level); + return asStreamWithAssert()->getStreamData(level); } std::shared_ptr QPDFObjectHandle::getRawStreamData() { - assertStream(); - return dynamic_cast(obj.get())->getRawStreamData(); + return asStreamWithAssert()->getRawStreamData(); } bool @@ -1305,8 +1393,7 @@ QPDFObjectHandle::pipeStreamData( bool suppress_warnings, bool will_retry) { - assertStream(); - return dynamic_cast(obj.get())->pipeStreamData( + return asStreamWithAssert()->pipeStreamData( p, filtering_attempted, encode_flags, @@ -1323,9 +1410,8 @@ QPDFObjectHandle::pipeStreamData( bool suppress_warnings, bool will_retry) { - assertStream(); bool filtering_attempted; - dynamic_cast(obj.get())->pipeStreamData( + asStreamWithAssert()->pipeStreamData( p, &filtering_attempted, encode_flags, @@ -1359,9 +1445,7 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - assertStream(); - dynamic_cast(obj.get())->replaceStreamData( - data, filter, decode_parms); + asStreamWithAssert()->replaceStreamData(data, filter, decode_parms); } void @@ -1370,14 +1454,12 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - assertStream(); auto b = std::make_shared(data.length()); unsigned char* bp = b->getBuffer(); if (bp) { memcpy(bp, data.c_str(), data.length()); } - dynamic_cast(obj.get())->replaceStreamData( - b, filter, decode_parms); + asStreamWithAssert()->replaceStreamData(b, filter, decode_parms); } void @@ -1386,9 +1468,7 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - assertStream(); - dynamic_cast(obj.get())->replaceStreamData( - provider, filter, decode_parms); + asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms); } namespace @@ -1437,11 +1517,9 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - assertStream(); auto sdp = std::shared_ptr(new FunctionProvider(provider)); - dynamic_cast(obj.get())->replaceStreamData( - sdp, filter, decode_parms); + asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); } void @@ -1450,11 +1528,9 @@ QPDFObjectHandle::replaceStreamData( QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) { - assertStream(); auto sdp = std::shared_ptr(new FunctionProvider(provider)); - dynamic_cast(obj.get())->replaceStreamData( - sdp, filter, decode_parms); + asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms); } std::map @@ -1469,10 +1545,11 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( { all_description = description; std::vector result; - if (isArray()) { - int n_items = getArrayNItems(); + auto array = asArray(); + if (array) { + int n_items = array->getNItems(); for (int i = 0; i < n_items; ++i) { - QPDFObjectHandle item = getArrayItem(i); + QPDFObjectHandle item = array->getItem(i); if (item.isStream()) { result.push_back(item); } else { @@ -1649,8 +1726,9 @@ QPDFObjectHandle::unparseResolved() std::string QPDFObjectHandle::unparseBinary() { - if (this->isString()) { - return dynamic_cast(this->obj.get())->unparse(true); + auto str = asString(); + if (str) { + return str->unparse(true); } else { return unparse(); } @@ -1666,7 +1744,7 @@ QPDFObjectHandle::getJSON(bool dereference_indirect) JSON QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) { - if ((!dereference_indirect) && this->isIndirect()) { + if ((!dereference_indirect) && isIndirect()) { return JSON::makeString(unparse()); } else if (!dereference()) { throw std::logic_error( @@ -1675,7 +1753,7 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) throw std::logic_error( "QPDFObjectHandle: attempting to unparse a reserved object"); } else { - return this->obj->getJSON(json_version); + return obj->getJSON(json_version); } } @@ -1687,8 +1765,7 @@ QPDFObjectHandle::getStreamJSON( Pipeline* p, std::string const& data_filename) { - assertStream(); - return dynamic_cast(obj.get())->getStreamJSON( + return asStreamWithAssert()->getStreamJSON( json_version, json_data, decode_level, p, data_filename); } @@ -1908,8 +1985,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr filter) void QPDFObjectHandle::addTokenFilter(std::shared_ptr filter) { - assertStream(); - return dynamic_cast(obj.get())->addTokenFilter(filter); + return asStreamWithAssert()->addTokenFilter(filter); } QPDFObjectHandle @@ -1946,7 +2022,6 @@ QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og) QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid"); return newNull(); } - return QPDFObjectHandle(qpdf, og, QPDF_Unresolved::create()); } @@ -2119,8 +2194,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf) QPDFObjectHandle stream_dict = newDictionary(); QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle( QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0))); - result.dereference(); - QPDF_Stream* stream = dynamic_cast(result.obj.get()); + auto stream = result.asStream(); stream->setObjGen(result.getObjGen()); return result; } @@ -2248,9 +2322,10 @@ QPDFObjectHandle::copyObject( new_obj = obj->shallowCopy(); } else if (isArray()) { std::vector items; - int n = getArrayNItems(); + auto array = asArray(); + int n = array->getNItems(); for (int i = 0; i < n; ++i) { - items.push_back(getArrayItem(i)); + items.push_back(array->getItem(i)); if ((!first_level_only) && (cross_indirect || (!items.back().isIndirect()))) { items.back().copyObject( @@ -2260,8 +2335,9 @@ QPDFObjectHandle::copyObject( new_obj = QPDF_Array::create(items); } else if (isDictionary()) { std::map items; + auto dict = asDictionary(); for (auto const& key: getKeys()) { - items[key] = getKey(key); + items[key] = dict->getKey(key); if ((!first_level_only) && (cross_indirect || (!items[key].isIndirect()))) { items[key].copyObject( @@ -2309,7 +2385,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams) void QPDFObjectHandle::assertInitialized() const { - if (!this->initialized) { + if (!initialized) { throw std::logic_error("operation attempted on uninitialized " "QPDFObjectHandle"); } @@ -2551,7 +2627,6 @@ QPDFObjectHandle::dereference() (getObjectID() && QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj))) { this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); - } return true; } diff --git a/libqpdf/QPDF_Reserved.cc b/libqpdf/QPDF_Reserved.cc index 5808a369..d5009674 100644 --- a/libqpdf/QPDF_Reserved.cc +++ b/libqpdf/QPDF_Reserved.cc @@ -17,14 +17,16 @@ QPDF_Reserved::shallowCopy() std::string QPDF_Reserved::unparse() { - throw std::logic_error("attempt to unparse QPDF_Reserved"); + throw std::logic_error( + "QPDFObjectHandle: attempting to unparse a reserved object"); return ""; } JSON QPDF_Reserved::getJSON(int json_version) { - throw std::logic_error("attempt to generate JSON from QPDF_Reserved"); + throw std::logic_error( + "QPDFObjectHandle: attempting to unparse a reserved object"); return JSON::makeNull(); } -- cgit v1.2.3-54-g00ecf From 43983109f25ba12db3fded12d0ea9a991b8a1d5c Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 21:21:20 +0100 Subject: Change QPDFObjectHandle::shallowCopyInternal to copy scalars --- libqpdf/QPDFObjectHandle.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index f60d131a..e0e0e50a 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2266,12 +2266,7 @@ QPDFObjectHandle::shallowCopyInternal( QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream"); throw std::runtime_error("attempt to make a shallow copy of a stream"); } - - if (isArray() || isDictionary()) { - new_obj = QPDFObjectHandle(obj->shallowCopy()); - } else { - new_obj = *this; - } + new_obj = QPDFObjectHandle(obj->shallowCopy()); std::set visited; new_obj.copyObject(visited, false, first_level_only, false); -- cgit v1.2.3-54-g00ecf From 431bd666c0504af0c8a016a96a73b7efbf9737c9 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 21:35:04 +0100 Subject: Split QPDFObject into QPDFObject and QPDFValue --- include/qpdf/QPDFObject.hh | 97 ++++++++++++++++++++++++++++++++-------- include/qpdf/QPDFValue.hh | 93 ++++++++++++++++++++++++++++++++++++++ libqpdf/CMakeLists.txt | 1 + libqpdf/QPDFObject.cc | 46 ------------------- libqpdf/QPDFObjectHandle.cc | 33 ++++++-------- libqpdf/QPDFValue.cc | 11 +++++ libqpdf/QPDF_Array.cc | 4 +- libqpdf/QPDF_Bool.cc | 4 +- libqpdf/QPDF_Dictionary.cc | 5 +-- libqpdf/QPDF_InlineImage.cc | 4 +- libqpdf/QPDF_Integer.cc | 4 +- libqpdf/QPDF_Name.cc | 4 +- libqpdf/QPDF_Null.cc | 4 +- libqpdf/QPDF_Operator.cc | 6 +-- libqpdf/QPDF_Real.cc | 4 +- libqpdf/QPDF_Reserved.cc | 4 +- libqpdf/QPDF_Stream.cc | 6 +-- libqpdf/QPDF_String.cc | 4 +- libqpdf/QPDF_Unresolved.cc | 6 +-- libqpdf/qpdf/QPDF_Array.hh | 6 +-- libqpdf/qpdf/QPDF_Bool.hh | 6 +-- libqpdf/qpdf/QPDF_Dictionary.hh | 6 +-- libqpdf/qpdf/QPDF_InlineImage.hh | 6 +-- libqpdf/qpdf/QPDF_Integer.hh | 6 +-- libqpdf/qpdf/QPDF_Name.hh | 6 +-- libqpdf/qpdf/QPDF_Null.hh | 6 +-- libqpdf/qpdf/QPDF_Operator.hh | 6 +-- libqpdf/qpdf/QPDF_Real.hh | 6 +-- libqpdf/qpdf/QPDF_Reserved.hh | 6 +-- libqpdf/qpdf/QPDF_Stream.hh | 6 +-- libqpdf/qpdf/QPDF_String.hh | 6 +-- libqpdf/qpdf/QPDF_Unresolved.hh | 6 +-- 32 files changed, 264 insertions(+), 154 deletions(-) create mode 100644 include/qpdf/QPDFValue.hh create mode 100644 libqpdf/QPDFValue.cc diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index 8b6f7403..db6efa4c 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -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 @@ -63,17 +64,84 @@ class QPDFObject 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 shallowCopy() = 0; - virtual std::string unparse() = 0; - virtual JSON getJSON(int json_version) = 0; + + std::shared_ptr + 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->getTypeCode(); + } // 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->getTypeName(); + } + + 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 o) + { + value = o->value; + } + void + swapWith(std::shared_ptr o) + { + auto v = value; + value = o->value; + o->value = v; + } + + template + T* + as() + { + return dynamic_cast(value.get()); + } // Accessor to give specific access to non-public methods class ObjAccessor @@ -90,29 +158,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 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 value; }; #endif // QPDFOBJECT_HH diff --git a/include/qpdf/QPDFValue.hh b/include/qpdf/QPDFValue.hh new file mode 100644 index 00000000..b957b813 --- /dev/null +++ b/include/qpdf/QPDFValue.hh @@ -0,0 +1,93 @@ +// 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 +#include +#include +#include + +#include + +class QPDF; +class QPDFObjectHandle; +class QPDFObject; + +class QPDFValue +{ + friend class QPDFObject; + + public: + virtual ~QPDFValue() = default; + + virtual std::shared_ptr shallowCopy() = 0; + virtual std::string unparse() = 0; + virtual JSON getJSON(int json_version) = 0; + virtual qpdf_object_type_e getTypeCode() const = 0; + virtual char const* getTypeName() const = 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) + { + parsed_offset = offset; + } + qpdf_offset_t + getParsedOffset() + { + return parsed_offset; + } + + protected: + QPDFValue() = default; + virtual void + releaseResolved() + { + } + static std::shared_ptr 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}; +}; + +#endif // QPDFVALUE_HH diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt index 7a4ef333..686ea04a 100644 --- a/libqpdf/CMakeLists.txt +++ b/libqpdf/CMakeLists.txt @@ -85,6 +85,7 @@ set(libqpdf_SOURCES QPDFSystemError.cc QPDFTokenizer.cc QPDFUsage.cc + QPDFValue.cc QPDFWriter.cc QPDFXRefEntry.cc QPDF_Array.cc diff --git a/libqpdf/QPDFObject.cc b/libqpdf/QPDFObject.cc index 382dd6c6..8df2b480 100644 --- a/libqpdf/QPDFObject.cc +++ b/libqpdf/QPDFObject.cc @@ -1,47 +1 @@ #include - -QPDFObject::QPDFObject() : - owning_qpdf(nullptr), - parsed_offset(-1) -{ -} - -std::shared_ptr -QPDFObject::do_create(QPDFObject* object) -{ - std::shared_ptr obj(object); - return obj; -} - -void -QPDFObject::setDescription(QPDF* qpdf, std::string const& description) -{ - this->owning_qpdf = qpdf; - this->object_description = description; -} - -bool -QPDFObject::getDescription(QPDF*& qpdf, std::string& description) -{ - qpdf = this->owning_qpdf; - description = this->object_description; - return this->owning_qpdf != nullptr; -} - -bool -QPDFObject::hasDescription() -{ - return this->owning_qpdf != nullptr; -} - -void -QPDFObject::setParsedOffset(qpdf_offset_t offset) -{ - this->parsed_offset = offset; -} - -qpdf_offset_t -QPDFObject::getParsedOffset() -{ - return this->parsed_offset; -} diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index e0e0e50a..72a35390 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -280,68 +280,67 @@ QPDFObjectHandle::getTypeName() QPDF_Array* QPDFObjectHandle::asArray() { - return isArray() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Bool* QPDFObjectHandle::asBool() { - return isBool() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Dictionary* QPDFObjectHandle::asDictionary() { - return isDictionary() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_InlineImage* QPDFObjectHandle::asInlineImage() { - return isInlineImage() ? dynamic_cast(obj.get()) - : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Integer* QPDFObjectHandle::asInteger() { - return isInteger() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Name* QPDFObjectHandle::asName() { - return isName() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Null* QPDFObjectHandle::asNull() { - return isNull() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Operator* QPDFObjectHandle::asOperator() { - return isOperator() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Real* QPDFObjectHandle::asReal() { - return isReal() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Reserved* QPDFObjectHandle::asReserved() { - return isReserved() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Stream* QPDFObjectHandle::asStream() { - return isStream() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } QPDF_Stream* @@ -355,7 +354,7 @@ QPDFObjectHandle::asStreamWithAssert() QPDF_String* QPDFObjectHandle::asString() { - return isString() ? dynamic_cast(obj.get()) : nullptr; + return dereference() ? obj->as() : nullptr; } bool @@ -1716,11 +1715,8 @@ QPDFObjectHandle::unparseResolved() if (!dereference()) { throw std::logic_error( "attempted to dereference an uninitialized QPDFObjectHandle"); - } else if (isReserved()) { - throw std::logic_error( - "QPDFObjectHandle: attempting to unparse a reserved object"); } - return this->obj->unparse(); + return obj->unparse(); } std::string @@ -1749,9 +1745,6 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) } else if (!dereference()) { throw std::logic_error( "attempted to dereference an uninitialized QPDFObjectHandle"); - } else if (isReserved()) { - throw std::logic_error( - "QPDFObjectHandle: attempting to unparse a reserved object"); } else { return obj->getJSON(json_version); } diff --git a/libqpdf/QPDFValue.cc b/libqpdf/QPDFValue.cc new file mode 100644 index 00000000..8a6222d2 --- /dev/null +++ b/libqpdf/QPDFValue.cc @@ -0,0 +1,11 @@ +#include + +#include + +std::shared_ptr +QPDFValue::do_create(QPDFValue* object) +{ + std::shared_ptr obj(new QPDFObject()); + obj->value = std::shared_ptr(object); + return obj; +} diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc index 55e4d20a..ff35e9a3 100644 --- a/libqpdf/QPDF_Array.cc +++ b/libqpdf/QPDF_Array.cc @@ -62,10 +62,10 @@ QPDF_Array::getJSON(int json_version) return j; } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Array::getTypeCode() const { - return QPDFObject::ot_array; + return ::ot_array; } char const* diff --git a/libqpdf/QPDF_Bool.cc b/libqpdf/QPDF_Bool.cc index f26325c3..e58eb62b 100644 --- a/libqpdf/QPDF_Bool.cc +++ b/libqpdf/QPDF_Bool.cc @@ -29,10 +29,10 @@ QPDF_Bool::getJSON(int json_version) return JSON::makeBool(this->val); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Bool::getTypeCode() const { - return QPDFObject::ot_boolean; + return ::ot_boolean; } char const* diff --git a/libqpdf/QPDF_Dictionary.cc b/libqpdf/QPDF_Dictionary.cc index 60b2339f..7f374f81 100644 --- a/libqpdf/QPDF_Dictionary.cc +++ b/libqpdf/QPDF_Dictionary.cc @@ -1,7 +1,6 @@ #include #include -#include QPDF_Dictionary::QPDF_Dictionary( std::map const& items) : @@ -58,10 +57,10 @@ QPDF_Dictionary::getJSON(int json_version) return j; } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Dictionary::getTypeCode() const { - return QPDFObject::ot_dictionary; + return ::ot_dictionary; } char const* diff --git a/libqpdf/QPDF_InlineImage.cc b/libqpdf/QPDF_InlineImage.cc index c3c656e0..494363f6 100644 --- a/libqpdf/QPDF_InlineImage.cc +++ b/libqpdf/QPDF_InlineImage.cc @@ -29,10 +29,10 @@ QPDF_InlineImage::getJSON(int json_version) return JSON::makeNull(); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_InlineImage::getTypeCode() const { - return QPDFObject::ot_inlineimage; + return ::ot_inlineimage; } char const* diff --git a/libqpdf/QPDF_Integer.cc b/libqpdf/QPDF_Integer.cc index e8d23e4a..68f97420 100644 --- a/libqpdf/QPDF_Integer.cc +++ b/libqpdf/QPDF_Integer.cc @@ -31,10 +31,10 @@ QPDF_Integer::getJSON(int json_version) return JSON::makeInt(this->val); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Integer::getTypeCode() const { - return QPDFObject::ot_integer; + return ::ot_integer; } char const* diff --git a/libqpdf/QPDF_Name.cc b/libqpdf/QPDF_Name.cc index 73990775..6831bcba 100644 --- a/libqpdf/QPDF_Name.cc +++ b/libqpdf/QPDF_Name.cc @@ -61,10 +61,10 @@ QPDF_Name::getJSON(int json_version) } } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Name::getTypeCode() const { - return QPDFObject::ot_name; + return ::ot_name; } char const* diff --git a/libqpdf/QPDF_Null.cc b/libqpdf/QPDF_Null.cc index b015ed8b..67b564c8 100644 --- a/libqpdf/QPDF_Null.cc +++ b/libqpdf/QPDF_Null.cc @@ -24,10 +24,10 @@ QPDF_Null::getJSON(int json_version) return JSON::makeNull(); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Null::getTypeCode() const { - return QPDFObject::ot_null; + return ::ot_null; } char const* diff --git a/libqpdf/QPDF_Operator.cc b/libqpdf/QPDF_Operator.cc index cd5009ae..84bde381 100644 --- a/libqpdf/QPDF_Operator.cc +++ b/libqpdf/QPDF_Operator.cc @@ -20,7 +20,7 @@ QPDF_Operator::shallowCopy() std::string QPDF_Operator::unparse() { - return this->val; + return val; } JSON @@ -29,10 +29,10 @@ QPDF_Operator::getJSON(int json_version) return JSON::makeNull(); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Operator::getTypeCode() const { - return QPDFObject::ot_operator; + return ::ot_operator; } char const* diff --git a/libqpdf/QPDF_Real.cc b/libqpdf/QPDF_Real.cc index 138bbb3c..1604d4ba 100644 --- a/libqpdf/QPDF_Real.cc +++ b/libqpdf/QPDF_Real.cc @@ -60,10 +60,10 @@ QPDF_Real::getJSON(int json_version) return JSON::makeNumber(result); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Real::getTypeCode() const { - return QPDFObject::ot_real; + return ::ot_real; } char const* diff --git a/libqpdf/QPDF_Reserved.cc b/libqpdf/QPDF_Reserved.cc index d5009674..14f82a62 100644 --- a/libqpdf/QPDF_Reserved.cc +++ b/libqpdf/QPDF_Reserved.cc @@ -30,10 +30,10 @@ QPDF_Reserved::getJSON(int json_version) return JSON::makeNull(); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Reserved::getTypeCode() const { - return QPDFObject::ot_reserved; + return ::ot_reserved; } char const* diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 1b7f9461..7a74512f 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -291,10 +291,10 @@ QPDF_Stream::getStreamJSON( return result; } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Stream::getTypeCode() const { - return QPDFObject::ot_stream; + return ::ot_stream; } char const* @@ -306,7 +306,7 @@ QPDF_Stream::getTypeName() const void QPDF_Stream::setDescription(QPDF* qpdf, std::string const& description) { - this->QPDFObject::setDescription(qpdf, description); + this->QPDFValue::setDescription(qpdf, description); setDictDescription(); } diff --git a/libqpdf/QPDF_String.cc b/libqpdf/QPDF_String.cc index b038366b..c8e21463 100644 --- a/libqpdf/QPDF_String.cc +++ b/libqpdf/QPDF_String.cc @@ -84,10 +84,10 @@ QPDF_String::getJSON(int json_version) return JSON::makeString(result); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_String::getTypeCode() const { - return QPDFObject::ot_string; + return ::ot_string; } char const* diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc index f348ec36..b51075f7 100644 --- a/libqpdf/QPDF_Unresolved.cc +++ b/libqpdf/QPDF_Unresolved.cc @@ -18,7 +18,7 @@ std::string QPDF_Unresolved::unparse() { throw std::logic_error( - "attempted to unparse an unresolveded QPDFObjectHandle"); + "attempted to unparse an unresolved QPDFObjectHandle"); return ""; } @@ -28,10 +28,10 @@ QPDF_Unresolved::getJSON(int json_version) return JSON::makeNull(); } -QPDFObject::object_type_e +qpdf_object_type_e QPDF_Unresolved::getTypeCode() const { - return QPDFObject::ot_unresolved; + return ::ot_unresolved; } char const* diff --git a/libqpdf/qpdf/QPDF_Array.hh b/libqpdf/qpdf/QPDF_Array.hh index 3e095637..b0207115 100644 --- a/libqpdf/qpdf/QPDF_Array.hh +++ b/libqpdf/qpdf/QPDF_Array.hh @@ -1,13 +1,13 @@ #ifndef QPDF_ARRAY_HH #define QPDF_ARRAY_HH -#include +#include #include #include #include -class QPDF_Array: public QPDFObject +class QPDF_Array: public QPDFValue { public: virtual ~QPDF_Array() = default; @@ -17,7 +17,7 @@ class QPDF_Array: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; int getNItems() const; diff --git a/libqpdf/qpdf/QPDF_Bool.hh b/libqpdf/qpdf/QPDF_Bool.hh index dbedc70a..2de585cb 100644 --- a/libqpdf/qpdf/QPDF_Bool.hh +++ b/libqpdf/qpdf/QPDF_Bool.hh @@ -1,9 +1,9 @@ #ifndef QPDF_BOOL_HH #define QPDF_BOOL_HH -#include +#include -class QPDF_Bool: public QPDFObject +class QPDF_Bool: public QPDFValue { public: virtual ~QPDF_Bool() = default; @@ -11,7 +11,7 @@ class QPDF_Bool: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; bool getVal() const; diff --git a/libqpdf/qpdf/QPDF_Dictionary.hh b/libqpdf/qpdf/QPDF_Dictionary.hh index cacc8961..5761b030 100644 --- a/libqpdf/qpdf/QPDF_Dictionary.hh +++ b/libqpdf/qpdf/QPDF_Dictionary.hh @@ -1,14 +1,14 @@ #ifndef QPDF_DICTIONARY_HH #define QPDF_DICTIONARY_HH -#include +#include #include #include #include -class QPDF_Dictionary: public QPDFObject +class QPDF_Dictionary: public QPDFValue { public: virtual ~QPDF_Dictionary() = default; @@ -17,7 +17,7 @@ class QPDF_Dictionary: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; // hasKey() and getKeys() treat keys with null values as if they diff --git a/libqpdf/qpdf/QPDF_InlineImage.hh b/libqpdf/qpdf/QPDF_InlineImage.hh index caaeaf87..31f7529a 100644 --- a/libqpdf/qpdf/QPDF_InlineImage.hh +++ b/libqpdf/qpdf/QPDF_InlineImage.hh @@ -1,9 +1,9 @@ #ifndef QPDF_INLINEIMAGE_HH #define QPDF_INLINEIMAGE_HH -#include +#include -class QPDF_InlineImage: public QPDFObject +class QPDF_InlineImage: public QPDFValue { public: virtual ~QPDF_InlineImage() = default; @@ -11,7 +11,7 @@ class QPDF_InlineImage: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; std::string getVal() const; diff --git a/libqpdf/qpdf/QPDF_Integer.hh b/libqpdf/qpdf/QPDF_Integer.hh index 2c17daf0..cf201021 100644 --- a/libqpdf/qpdf/QPDF_Integer.hh +++ b/libqpdf/qpdf/QPDF_Integer.hh @@ -1,9 +1,9 @@ #ifndef QPDF_INTEGER_HH #define QPDF_INTEGER_HH -#include +#include -class QPDF_Integer: public QPDFObject +class QPDF_Integer: public QPDFValue { public: virtual ~QPDF_Integer() = default; @@ -11,7 +11,7 @@ class QPDF_Integer: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; long long getVal() const; diff --git a/libqpdf/qpdf/QPDF_Name.hh b/libqpdf/qpdf/QPDF_Name.hh index cf653b2e..438b118e 100644 --- a/libqpdf/qpdf/QPDF_Name.hh +++ b/libqpdf/qpdf/QPDF_Name.hh @@ -1,9 +1,9 @@ #ifndef QPDF_NAME_HH #define QPDF_NAME_HH -#include +#include -class QPDF_Name: public QPDFObject +class QPDF_Name: public QPDFValue { public: virtual ~QPDF_Name() = default; @@ -11,7 +11,7 @@ class QPDF_Name: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; std::string getName() const; diff --git a/libqpdf/qpdf/QPDF_Null.hh b/libqpdf/qpdf/QPDF_Null.hh index 16833424..7f722a3a 100644 --- a/libqpdf/qpdf/QPDF_Null.hh +++ b/libqpdf/qpdf/QPDF_Null.hh @@ -1,9 +1,9 @@ #ifndef QPDF_NULL_HH #define QPDF_NULL_HH -#include +#include -class QPDF_Null: public QPDFObject +class QPDF_Null: public QPDFValue { public: virtual ~QPDF_Null() = default; @@ -11,7 +11,7 @@ class QPDF_Null: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; private: diff --git a/libqpdf/qpdf/QPDF_Operator.hh b/libqpdf/qpdf/QPDF_Operator.hh index 1da43d72..d17f1629 100644 --- a/libqpdf/qpdf/QPDF_Operator.hh +++ b/libqpdf/qpdf/QPDF_Operator.hh @@ -1,9 +1,9 @@ #ifndef QPDF_OPERATOR_HH #define QPDF_OPERATOR_HH -#include +#include -class QPDF_Operator: public QPDFObject +class QPDF_Operator: public QPDFValue { public: virtual ~QPDF_Operator() = default; @@ -11,7 +11,7 @@ class QPDF_Operator: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; std::string getVal() const; diff --git a/libqpdf/qpdf/QPDF_Real.hh b/libqpdf/qpdf/QPDF_Real.hh index f5ab4bd6..97375c73 100644 --- a/libqpdf/qpdf/QPDF_Real.hh +++ b/libqpdf/qpdf/QPDF_Real.hh @@ -1,9 +1,9 @@ #ifndef QPDF_REAL_HH #define QPDF_REAL_HH -#include +#include -class QPDF_Real: public QPDFObject +class QPDF_Real: public QPDFValue { public: virtual ~QPDF_Real() = default; @@ -13,7 +13,7 @@ class QPDF_Real: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; std::string getVal(); diff --git a/libqpdf/qpdf/QPDF_Reserved.hh b/libqpdf/qpdf/QPDF_Reserved.hh index 243a1728..e9f8313a 100644 --- a/libqpdf/qpdf/QPDF_Reserved.hh +++ b/libqpdf/qpdf/QPDF_Reserved.hh @@ -1,9 +1,9 @@ #ifndef QPDF_RESERVED_HH #define QPDF_RESERVED_HH -#include +#include -class QPDF_Reserved: public QPDFObject +class QPDF_Reserved: public QPDFValue { public: virtual ~QPDF_Reserved() = default; @@ -11,7 +11,7 @@ class QPDF_Reserved: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; private: diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh index 8980c751..639d5298 100644 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ b/libqpdf/qpdf/QPDF_Stream.hh @@ -3,9 +3,9 @@ #include -#include #include #include +#include #include #include @@ -13,7 +13,7 @@ class Pipeline; class QPDF; -class QPDF_Stream: public QPDFObject +class QPDF_Stream: public QPDFValue { public: virtual ~QPDF_Stream() = default; @@ -26,7 +26,7 @@ class QPDF_Stream: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; virtual void setDescription(QPDF*, std::string const&); QPDFObjectHandle getDict() const; diff --git a/libqpdf/qpdf/QPDF_String.hh b/libqpdf/qpdf/QPDF_String.hh index b6d77637..9b6fc95c 100644 --- a/libqpdf/qpdf/QPDF_String.hh +++ b/libqpdf/qpdf/QPDF_String.hh @@ -1,11 +1,11 @@ #ifndef QPDF_STRING_HH #define QPDF_STRING_HH -#include +#include // QPDF_Strings may included embedded null characters. -class QPDF_String: public QPDFObject +class QPDF_String: public QPDFValue { friend class QPDFWriter; @@ -16,7 +16,7 @@ class QPDF_String: public QPDFObject create_utf16(std::string const& utf8_val); virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; std::string unparse(bool force_binary); virtual JSON getJSON(int json_version); diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh index 4f1c5238..c17748b5 100644 --- a/libqpdf/qpdf/QPDF_Unresolved.hh +++ b/libqpdf/qpdf/QPDF_Unresolved.hh @@ -1,9 +1,9 @@ #ifndef QPDF_UNRESOLVED_HH #define QPDF_UNRESOLVED_HH -#include +#include -class QPDF_Unresolved: public QPDFObject +class QPDF_Unresolved: public QPDFValue { public: virtual ~QPDF_Unresolved() = default; @@ -11,7 +11,7 @@ class QPDF_Unresolved: public QPDFObject virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual QPDFObject::object_type_e getTypeCode() const; + virtual qpdf_object_type_e getTypeCode() const; virtual char const* getTypeName() const; private: -- cgit v1.2.3-54-g00ecf From 27fae2b55e835a41277df78f090d4baf6fe05c1e Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 22:57:33 +0100 Subject: Remove QPDF::ObjectChanged Also change QPDF::replaceObject and QPDF::swapObjects such that the QPDFObject assigned to an og in the obj_cache is never replaced; only QPDFObject::value is updated. --- include/qpdf/QPDF.hh | 8 -------- libqpdf/QPDF.cc | 34 +++------------------------------- libqpdf/QPDFObjectHandle.cc | 4 +--- 3 files changed, 4 insertions(+), 42 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 469bad55..701c5e55 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -851,12 +851,6 @@ class QPDF { return qpdf->resolve(og); } - static bool - objectChanged( - QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr& oph) - { - return qpdf->objectChanged(og, oph); - } }; friend class Resolver; @@ -1174,7 +1168,6 @@ class QPDF std::string const& description, QPDFObjGen const& exp_og, QPDFObjGen& og); - bool objectChanged(QPDFObjGen const& og, std::shared_ptr& oph); std::shared_ptr resolve(QPDFObjGen const& og); void resolveObjectsInStream(int obj_stream_number); void stopOnError(std::string const& message); @@ -1729,7 +1722,6 @@ class QPDF bool in_parse; bool parsed; std::set resolved_object_streams; - bool ever_replaced_objects; // Linearization data qpdf_offset_t first_xref_item_offset; // actual value from file diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 22f62a8b..000dab5d 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -223,7 +223,6 @@ QPDF::Members::Members() : immediate_copy_from(false), in_parse(false), parsed(false), - ever_replaced_objects(false), first_xref_item_offset(0), uncompressed_after_compressed(false) { @@ -1928,28 +1927,6 @@ QPDF::readObjectAtOffset( return oh; } -bool -QPDF::objectChanged(QPDFObjGen const& og, std::shared_ptr& oph) -{ - // See if the object cached at og, if any, is the one passed in. - // QPDFObjectHandle uses this to detect outdated handles to - // replaced or swapped objects. This is a somewhat expensive check - // because it happens with every dereference of a - // QPDFObjectHandle. To reduce the hit somewhat, short-circuit the - // check if we never called a function that replaces an object - // already in cache. It is important for functions that do this to - // set ever_replaced_objects = true. - - if (!this->m->ever_replaced_objects) { - return false; - } - auto c = this->m->obj_cache.find(og); - if (c == this->m->obj_cache.end()) { - return true; - } - return (c->second.object.get() != oph.get()); -} - std::shared_ptr QPDF::resolve(QPDFObjGen const& og) { @@ -2207,14 +2184,12 @@ QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh) throw std::logic_error( "QPDF::replaceObject called with indirect object handle"); } - // Force new object to appear in the cache resolve(og); // Replace the object in the object cache - this->m->ever_replaced_objects = true; - this->m->obj_cache[og] = - ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); + m->obj_cache[og].object->assign( + QPDFObjectHandle::ObjAccessor::getObject(oh)); } void @@ -2536,10 +2511,7 @@ QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2) // cache. resolve(og1); resolve(og2); - ObjCache t = this->m->obj_cache[og1]; - this->m->ever_replaced_objects = true; - this->m->obj_cache[og1] = this->m->obj_cache[og2]; - this->m->obj_cache[og2] = t; + m->obj_cache[og1].object->swapWith(m->obj_cache[og2].object); } unsigned long long diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 72a35390..32988b53 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2611,9 +2611,7 @@ QPDFObjectHandle::dereference() if (!this->initialized) { return false; } - if ((this->obj->getTypeCode() == QPDFObject::ot_unresolved) || - (getObjectID() && - QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj))) { + if (this->obj->getTypeCode() == QPDFObject::ot_unresolved) { this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); } return true; -- cgit v1.2.3-54-g00ecf From c7005e8a6d626d1c66bd780314c2520d12b0ca9a Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 2 Aug 2022 22:57:33 +0100 Subject: Remove virtual methods QPDFValue::getTypeCode and getTypeName --- include/qpdf/QPDFObject.hh | 5 ++--- include/qpdf/QPDFValue.hh | 16 +++++++++++++--- libqpdf/QPDF_Array.cc | 16 +++------------- libqpdf/QPDF_Bool.cc | 13 +------------ libqpdf/QPDF_Dictionary.cc | 13 +------------ libqpdf/QPDF_InlineImage.cc | 13 +------------ libqpdf/QPDF_Integer.cc | 13 +------------ libqpdf/QPDF_Name.cc | 13 +------------ libqpdf/QPDF_Null.cc | 17 +++++------------ libqpdf/QPDF_Operator.cc | 13 +------------ libqpdf/QPDF_Real.cc | 14 ++------------ libqpdf/QPDF_Reserved.cc | 17 +++++------------ libqpdf/QPDF_Stream.cc | 13 +------------ libqpdf/QPDF_String.cc | 13 +------------ libqpdf/QPDF_Unresolved.cc | 17 +++++------------ libqpdf/qpdf/QPDF_Array.hh | 2 -- libqpdf/qpdf/QPDF_Bool.hh | 2 -- libqpdf/qpdf/QPDF_Dictionary.hh | 2 -- libqpdf/qpdf/QPDF_InlineImage.hh | 2 -- libqpdf/qpdf/QPDF_Integer.hh | 2 -- libqpdf/qpdf/QPDF_Name.hh | 2 -- libqpdf/qpdf/QPDF_Null.hh | 4 +--- libqpdf/qpdf/QPDF_Operator.hh | 2 -- libqpdf/qpdf/QPDF_Real.hh | 2 -- libqpdf/qpdf/QPDF_Reserved.hh | 4 +--- libqpdf/qpdf/QPDF_Stream.hh | 2 -- libqpdf/qpdf/QPDF_String.hh | 2 -- libqpdf/qpdf/QPDF_Unresolved.hh | 4 +--- 28 files changed, 46 insertions(+), 192 deletions(-) diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index db6efa4c..a1930168 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -87,7 +87,7 @@ class QPDFObject object_type_e getTypeCode() const { - return value->getTypeCode(); + return value->type_code; } // Return a string literal that describes the type, useful for @@ -95,9 +95,8 @@ class QPDFObject char const* getTypeName() const { - return value->getTypeName(); + return value->type_name; } - void setDescription(QPDF* qpdf, std::string const& description) { diff --git a/include/qpdf/QPDFValue.hh b/include/qpdf/QPDFValue.hh index b957b813..33558f1b 100644 --- a/include/qpdf/QPDFValue.hh +++ b/include/qpdf/QPDFValue.hh @@ -43,8 +43,6 @@ class QPDFValue virtual std::shared_ptr shallowCopy() = 0; virtual std::string unparse() = 0; virtual JSON getJSON(int json_version) = 0; - virtual qpdf_object_type_e getTypeCode() const = 0; - virtual char const* getTypeName() const = 0; virtual void setDescription(QPDF* qpdf, std::string const& description) { @@ -75,7 +73,17 @@ class QPDFValue } protected: - QPDFValue() = default; + QPDFValue() : + type_code(::ot_uninitialized), + type_name("uninitilized") + { + } + QPDFValue(qpdf_object_type_e type_code, char const* type_name) : + type_code(type_code), + type_name(type_name) + { + } + virtual void releaseResolved() { @@ -88,6 +96,8 @@ class QPDFValue 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; }; #endif // QPDFVALUE_HH diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc index ff35e9a3..63fe98d4 100644 --- a/libqpdf/QPDF_Array.cc +++ b/libqpdf/QPDF_Array.cc @@ -4,12 +4,14 @@ #include #include -QPDF_Array::QPDF_Array(std::vector const& v) +QPDF_Array::QPDF_Array(std::vector const& v) : + QPDFValue(::ot_array, "array") { setFromVector(v); } QPDF_Array::QPDF_Array(SparseOHArray const& items) : + QPDFValue(::ot_array, "array"), elements(items) { } @@ -62,18 +64,6 @@ QPDF_Array::getJSON(int json_version) return j; } -qpdf_object_type_e -QPDF_Array::getTypeCode() const -{ - return ::ot_array; -} - -char const* -QPDF_Array::getTypeName() const -{ - return "array"; -} - int QPDF_Array::getNItems() const { diff --git a/libqpdf/QPDF_Bool.cc b/libqpdf/QPDF_Bool.cc index e58eb62b..efbfd6c9 100644 --- a/libqpdf/QPDF_Bool.cc +++ b/libqpdf/QPDF_Bool.cc @@ -1,6 +1,7 @@ #include QPDF_Bool::QPDF_Bool(bool val) : + QPDFValue(::ot_boolean, "boolean"), val(val) { } @@ -29,18 +30,6 @@ QPDF_Bool::getJSON(int json_version) return JSON::makeBool(this->val); } -qpdf_object_type_e -QPDF_Bool::getTypeCode() const -{ - return ::ot_boolean; -} - -char const* -QPDF_Bool::getTypeName() const -{ - return "boolean"; -} - bool QPDF_Bool::getVal() const { diff --git a/libqpdf/QPDF_Dictionary.cc b/libqpdf/QPDF_Dictionary.cc index 7f374f81..845bcad8 100644 --- a/libqpdf/QPDF_Dictionary.cc +++ b/libqpdf/QPDF_Dictionary.cc @@ -4,6 +4,7 @@ QPDF_Dictionary::QPDF_Dictionary( std::map const& items) : + QPDFValue(::ot_dictionary, "dictionary"), items(items) { } @@ -57,18 +58,6 @@ QPDF_Dictionary::getJSON(int json_version) return j; } -qpdf_object_type_e -QPDF_Dictionary::getTypeCode() const -{ - return ::ot_dictionary; -} - -char const* -QPDF_Dictionary::getTypeName() const -{ - return "dictionary"; -} - bool QPDF_Dictionary::hasKey(std::string const& key) { diff --git a/libqpdf/QPDF_InlineImage.cc b/libqpdf/QPDF_InlineImage.cc index 494363f6..76318196 100644 --- a/libqpdf/QPDF_InlineImage.cc +++ b/libqpdf/QPDF_InlineImage.cc @@ -1,6 +1,7 @@ #include QPDF_InlineImage::QPDF_InlineImage(std::string const& val) : + QPDFValue(::ot_inlineimage, "inline-image"), val(val) { } @@ -29,18 +30,6 @@ QPDF_InlineImage::getJSON(int json_version) return JSON::makeNull(); } -qpdf_object_type_e -QPDF_InlineImage::getTypeCode() const -{ - return ::ot_inlineimage; -} - -char const* -QPDF_InlineImage::getTypeName() const -{ - return "inline-image"; -} - std::string QPDF_InlineImage::getVal() const { diff --git a/libqpdf/QPDF_Integer.cc b/libqpdf/QPDF_Integer.cc index 68f97420..24812573 100644 --- a/libqpdf/QPDF_Integer.cc +++ b/libqpdf/QPDF_Integer.cc @@ -3,6 +3,7 @@ #include QPDF_Integer::QPDF_Integer(long long val) : + QPDFValue(::ot_integer, "integer"), val(val) { } @@ -31,18 +32,6 @@ QPDF_Integer::getJSON(int json_version) return JSON::makeInt(this->val); } -qpdf_object_type_e -QPDF_Integer::getTypeCode() const -{ - return ::ot_integer; -} - -char const* -QPDF_Integer::getTypeName() const -{ - return "integer"; -} - long long QPDF_Integer::getVal() const { diff --git a/libqpdf/QPDF_Name.cc b/libqpdf/QPDF_Name.cc index 6831bcba..c86d34b4 100644 --- a/libqpdf/QPDF_Name.cc +++ b/libqpdf/QPDF_Name.cc @@ -5,6 +5,7 @@ #include QPDF_Name::QPDF_Name(std::string const& name) : + QPDFValue(::ot_name, "name"), name(name) { } @@ -61,18 +62,6 @@ QPDF_Name::getJSON(int json_version) } } -qpdf_object_type_e -QPDF_Name::getTypeCode() const -{ - return ::ot_name; -} - -char const* -QPDF_Name::getTypeName() const -{ - return "name"; -} - std::string QPDF_Name::getName() const { diff --git a/libqpdf/QPDF_Null.cc b/libqpdf/QPDF_Null.cc index 67b564c8..f60dda1f 100644 --- a/libqpdf/QPDF_Null.cc +++ b/libqpdf/QPDF_Null.cc @@ -1,5 +1,10 @@ #include +QPDF_Null::QPDF_Null() : + QPDFValue(::ot_null, "null") +{ +} + std::shared_ptr QPDF_Null::create() { @@ -23,15 +28,3 @@ QPDF_Null::getJSON(int json_version) { return JSON::makeNull(); } - -qpdf_object_type_e -QPDF_Null::getTypeCode() const -{ - return ::ot_null; -} - -char const* -QPDF_Null::getTypeName() const -{ - return "null"; -} diff --git a/libqpdf/QPDF_Operator.cc b/libqpdf/QPDF_Operator.cc index 84bde381..547ff40a 100644 --- a/libqpdf/QPDF_Operator.cc +++ b/libqpdf/QPDF_Operator.cc @@ -1,6 +1,7 @@ #include QPDF_Operator::QPDF_Operator(std::string const& val) : + QPDFValue(::ot_operator, "operator"), val(val) { } @@ -29,18 +30,6 @@ QPDF_Operator::getJSON(int json_version) return JSON::makeNull(); } -qpdf_object_type_e -QPDF_Operator::getTypeCode() const -{ - return ::ot_operator; -} - -char const* -QPDF_Operator::getTypeName() const -{ - return "operator"; -} - std::string QPDF_Operator::getVal() const { diff --git a/libqpdf/QPDF_Real.cc b/libqpdf/QPDF_Real.cc index 1604d4ba..85c9ceeb 100644 --- a/libqpdf/QPDF_Real.cc +++ b/libqpdf/QPDF_Real.cc @@ -3,12 +3,14 @@ #include QPDF_Real::QPDF_Real(std::string const& val) : + QPDFValue(::ot_real, "real"), val(val) { } QPDF_Real::QPDF_Real( double value, int decimal_places, bool trim_trailing_zeroes) : + QPDFValue(::ot_real, "real"), val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes)) { } @@ -60,18 +62,6 @@ QPDF_Real::getJSON(int json_version) return JSON::makeNumber(result); } -qpdf_object_type_e -QPDF_Real::getTypeCode() const -{ - return ::ot_real; -} - -char const* -QPDF_Real::getTypeName() const -{ - return "real"; -} - std::string QPDF_Real::getVal() { diff --git a/libqpdf/QPDF_Reserved.cc b/libqpdf/QPDF_Reserved.cc index 14f82a62..f5af4688 100644 --- a/libqpdf/QPDF_Reserved.cc +++ b/libqpdf/QPDF_Reserved.cc @@ -2,6 +2,11 @@ #include +QPDF_Reserved::QPDF_Reserved() : + QPDFValue(::ot_reserved, "reserved") +{ +} + std::shared_ptr QPDF_Reserved::create() { @@ -29,15 +34,3 @@ QPDF_Reserved::getJSON(int json_version) "QPDFObjectHandle: attempting to unparse a reserved object"); return JSON::makeNull(); } - -qpdf_object_type_e -QPDF_Reserved::getTypeCode() const -{ - return ::ot_reserved; -} - -char const* -QPDF_Reserved::getTypeName() const -{ - return "reserved"; -} diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 7a74512f..9932c15d 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -114,6 +114,7 @@ QPDF_Stream::QPDF_Stream( QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) : + QPDFValue(::ot_stream, "stream"), qpdf(qpdf), og(og), filter_on_write(true), @@ -291,18 +292,6 @@ QPDF_Stream::getStreamJSON( return result; } -qpdf_object_type_e -QPDF_Stream::getTypeCode() const -{ - return ::ot_stream; -} - -char const* -QPDF_Stream::getTypeName() const -{ - return "stream"; -} - void QPDF_Stream::setDescription(QPDF* qpdf, std::string const& description) { diff --git a/libqpdf/QPDF_String.cc b/libqpdf/QPDF_String.cc index c8e21463..c6cb6c41 100644 --- a/libqpdf/QPDF_String.cc +++ b/libqpdf/QPDF_String.cc @@ -21,6 +21,7 @@ is_iso_latin1_printable(char ch) } QPDF_String::QPDF_String(std::string const& val) : + QPDFValue(::ot_string, "string"), val(val) { } @@ -84,18 +85,6 @@ QPDF_String::getJSON(int json_version) return JSON::makeString(result); } -qpdf_object_type_e -QPDF_String::getTypeCode() const -{ - return ::ot_string; -} - -char const* -QPDF_String::getTypeName() const -{ - return "string"; -} - bool QPDF_String::useHexString() const { diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc index b51075f7..40d4874e 100644 --- a/libqpdf/QPDF_Unresolved.cc +++ b/libqpdf/QPDF_Unresolved.cc @@ -2,6 +2,11 @@ #include +QPDF_Unresolved::QPDF_Unresolved() : + QPDFValue(::ot_unresolved, "unresolved") +{ +} + std::shared_ptr QPDF_Unresolved::create() { @@ -27,15 +32,3 @@ QPDF_Unresolved::getJSON(int json_version) { return JSON::makeNull(); } - -qpdf_object_type_e -QPDF_Unresolved::getTypeCode() const -{ - return ::ot_unresolved; -} - -char const* -QPDF_Unresolved::getTypeName() const -{ - return "unresolved"; -} diff --git a/libqpdf/qpdf/QPDF_Array.hh b/libqpdf/qpdf/QPDF_Array.hh index b0207115..426efe36 100644 --- a/libqpdf/qpdf/QPDF_Array.hh +++ b/libqpdf/qpdf/QPDF_Array.hh @@ -17,8 +17,6 @@ class QPDF_Array: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; int getNItems() const; QPDFObjectHandle getItem(int n) const; diff --git a/libqpdf/qpdf/QPDF_Bool.hh b/libqpdf/qpdf/QPDF_Bool.hh index 2de585cb..3e45cd8e 100644 --- a/libqpdf/qpdf/QPDF_Bool.hh +++ b/libqpdf/qpdf/QPDF_Bool.hh @@ -11,8 +11,6 @@ class QPDF_Bool: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; bool getVal() const; private: diff --git a/libqpdf/qpdf/QPDF_Dictionary.hh b/libqpdf/qpdf/QPDF_Dictionary.hh index 5761b030..19ab8d9b 100644 --- a/libqpdf/qpdf/QPDF_Dictionary.hh +++ b/libqpdf/qpdf/QPDF_Dictionary.hh @@ -17,8 +17,6 @@ class QPDF_Dictionary: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; // hasKey() and getKeys() treat keys with null values as if they // aren't there. getKey() returns null for the value of a diff --git a/libqpdf/qpdf/QPDF_InlineImage.hh b/libqpdf/qpdf/QPDF_InlineImage.hh index 31f7529a..b7bea9c7 100644 --- a/libqpdf/qpdf/QPDF_InlineImage.hh +++ b/libqpdf/qpdf/QPDF_InlineImage.hh @@ -11,8 +11,6 @@ class QPDF_InlineImage: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; std::string getVal() const; private: diff --git a/libqpdf/qpdf/QPDF_Integer.hh b/libqpdf/qpdf/QPDF_Integer.hh index cf201021..7e09673c 100644 --- a/libqpdf/qpdf/QPDF_Integer.hh +++ b/libqpdf/qpdf/QPDF_Integer.hh @@ -11,8 +11,6 @@ class QPDF_Integer: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; long long getVal() const; private: diff --git a/libqpdf/qpdf/QPDF_Name.hh b/libqpdf/qpdf/QPDF_Name.hh index 438b118e..74fc7e44 100644 --- a/libqpdf/qpdf/QPDF_Name.hh +++ b/libqpdf/qpdf/QPDF_Name.hh @@ -11,8 +11,6 @@ class QPDF_Name: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; std::string getName() const; // Put # into strings with characters unsuitable for name token diff --git a/libqpdf/qpdf/QPDF_Null.hh b/libqpdf/qpdf/QPDF_Null.hh index 7f722a3a..68973de9 100644 --- a/libqpdf/qpdf/QPDF_Null.hh +++ b/libqpdf/qpdf/QPDF_Null.hh @@ -11,11 +11,9 @@ class QPDF_Null: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; private: - QPDF_Null() = default; + QPDF_Null(); }; #endif // QPDF_NULL_HH diff --git a/libqpdf/qpdf/QPDF_Operator.hh b/libqpdf/qpdf/QPDF_Operator.hh index d17f1629..767c0ba0 100644 --- a/libqpdf/qpdf/QPDF_Operator.hh +++ b/libqpdf/qpdf/QPDF_Operator.hh @@ -11,8 +11,6 @@ class QPDF_Operator: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; std::string getVal() const; private: diff --git a/libqpdf/qpdf/QPDF_Real.hh b/libqpdf/qpdf/QPDF_Real.hh index 97375c73..dc0f3ff8 100644 --- a/libqpdf/qpdf/QPDF_Real.hh +++ b/libqpdf/qpdf/QPDF_Real.hh @@ -13,8 +13,6 @@ class QPDF_Real: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; std::string getVal(); private: diff --git a/libqpdf/qpdf/QPDF_Reserved.hh b/libqpdf/qpdf/QPDF_Reserved.hh index e9f8313a..f90242a9 100644 --- a/libqpdf/qpdf/QPDF_Reserved.hh +++ b/libqpdf/qpdf/QPDF_Reserved.hh @@ -11,11 +11,9 @@ class QPDF_Reserved: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; private: - QPDF_Reserved() = default; + QPDF_Reserved(); }; #endif // QPDF_RESERVED_HH diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh index 639d5298..3a16160e 100644 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ b/libqpdf/qpdf/QPDF_Stream.hh @@ -26,8 +26,6 @@ class QPDF_Stream: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; virtual void setDescription(QPDF*, std::string const&); QPDFObjectHandle getDict() const; bool isDataModified() const; diff --git a/libqpdf/qpdf/QPDF_String.hh b/libqpdf/qpdf/QPDF_String.hh index 9b6fc95c..a92427e3 100644 --- a/libqpdf/qpdf/QPDF_String.hh +++ b/libqpdf/qpdf/QPDF_String.hh @@ -16,8 +16,6 @@ class QPDF_String: public QPDFValue create_utf16(std::string const& utf8_val); virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; std::string unparse(bool force_binary); virtual JSON getJSON(int json_version); std::string getVal() const; diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh index c17748b5..c1231590 100644 --- a/libqpdf/qpdf/QPDF_Unresolved.hh +++ b/libqpdf/qpdf/QPDF_Unresolved.hh @@ -11,11 +11,9 @@ class QPDF_Unresolved: public QPDFValue virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); - virtual qpdf_object_type_e getTypeCode() const; - virtual char const* getTypeName() const; private: - QPDF_Unresolved() = default; + QPDF_Unresolved(); }; #endif // QPDF_UNRESOLVED_HH -- cgit v1.2.3-54-g00ecf From 23d50a2f14db56be4cb4efcc413b8ef44713613f Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 9 Aug 2022 21:34:34 +0100 Subject: Remove QPDFObjectHandle::initialized --- include/qpdf/QPDFObjectHandle.hh | 9 +++------ libqpdf/QPDFObjectHandle.cc | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index af454e75..1128c3ed 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1584,7 +1584,6 @@ class QPDFObjectHandle QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr const& obj) : - initialized(true), qpdf(qpdf), og(og), obj(obj) @@ -1640,8 +1639,6 @@ 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. @@ -1888,13 +1885,13 @@ QPDFObjectHandle::getGeneration() const 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 @@ -1915,7 +1912,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 (initialized) { + if (isInitialized()) { this->obj->setParsedOffset(offset); } } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 32988b53..c8611e07 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -236,13 +236,11 @@ LastChar::getLastChar() } QPDFObjectHandle::QPDFObjectHandle() : - initialized(false), qpdf(nullptr) { } QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr const& data) : - initialized(true), qpdf(nullptr), obj(data) { @@ -369,7 +367,7 @@ QPDFObjectHandle::isDirectNull() const // Don't call dereference() -- this is a const method, and we know // objid == 0, so there's nothing to resolve. return ( - initialized && (getObjectID() == 0) && + isInitialized() && (getObjectID() == 0) && (obj->getTypeCode() == QPDFObject::ot_null)); } @@ -2373,7 +2371,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams) void QPDFObjectHandle::assertInitialized() const { - if (!initialized) { + if (!isInitialized()) { throw std::logic_error("operation attempted on uninitialized " "QPDFObjectHandle"); } @@ -2608,7 +2606,7 @@ QPDFObjectHandle::assertPageObject() bool QPDFObjectHandle::dereference() { - if (!this->initialized) { + if (!isInitialized()) { return false; } if (this->obj->getTypeCode() == QPDFObject::ot_unresolved) { -- cgit v1.2.3-54-g00ecf From c0cd72a3eef996e597ba82b784de029ec6d88707 Mon Sep 17 00:00:00 2001 From: m-holger Date: Wed, 10 Aug 2022 13:16:06 +0100 Subject: Add private methods QPDF::isCached and QPDF::isUnresolved --- include/qpdf/QPDF.hh | 2 ++ include/qpdf/QPDFObject.hh | 6 +++++- libqpdf/QPDF.cc | 23 +++++++++++++++++------ libqpdf/QPDFObjectHandle.cc | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 701c5e55..ee265cec 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1175,6 +1175,8 @@ class QPDF QPDFObjectHandle reserveStream(QPDFObjGen const& og); QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr const&); + bool isCached(QPDFObjGen const& og); + bool isUnresolved(QPDFObjGen const& og); // Calls finish() on the pipeline when done but does not delete it bool pipeStreamData( diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index a1930168..198488dd 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -134,7 +134,11 @@ class QPDFObject value = o->value; o->value = v; } - + bool + isUnresolved() + { + return value->type_code == ::ot_unresolved; + } template T* as() diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 000dab5d..d877c14a 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1425,8 +1425,7 @@ QPDF::fixDanglingReferences(bool force) for (auto sub: to_check) { if (sub.isIndirect()) { if (sub.getOwningQPDF() == this) { - QPDFObjGen og(sub.getObjGen()); - if (this->m->obj_cache.count(og) == 0) { + if (!isCached(sub.getObjGen())) { QTC::TC("qpdf", "QPDF detected dangling ref"); queue.push_back(sub); } @@ -1886,7 +1885,7 @@ QPDF::readObjectAtOffset( "expected endobj"); } - if (!this->m->obj_cache.count(og)) { + if (!isCached(og)) { // Store the object in the cache here so it gets cached // whether we first know the offset or whether we first know // the object ID and generation (in which we case we would get @@ -1947,7 +1946,7 @@ QPDF::resolve(QPDFObjGen const& og) } ResolveRecorder rr(this, og); - if ((!this->m->obj_cache.count(og)) && this->m->xref_table.count(og)) { + if ((!isCached(og)) && this->m->xref_table.count(og)) { QPDFXRefEntry const& entry = this->m->xref_table[og]; try { switch (entry.getType()) { @@ -1985,7 +1984,7 @@ QPDF::resolve(QPDFObjGen const& og) ": error reading object: " + e.what())); } } - if (this->m->obj_cache.count(og) == 0) { + if (!isCached(og)) { // PDF spec says unknown objects resolve to the null object. QTC::TC("qpdf", "QPDF resolve failure to null"); QPDFObjectHandle oh = QPDFObjectHandle::newNull(); @@ -2112,6 +2111,18 @@ QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) return QPDFObjectHandle::Factory::newIndirect(this, og, obj); } +bool +QPDF::isCached(QPDFObjGen const& og) +{ + return m->obj_cache.count(og) != 0; +} + +bool +QPDF::isUnresolved(QPDFObjGen const& og) +{ + return !isCached(og) || m->obj_cache[og].object->isUnresolved(); +} + QPDFObjectHandle QPDF::makeIndirectObject(QPDFObjectHandle oh) { @@ -2129,7 +2140,7 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) QPDFObjectHandle QPDF::reserveObjectIfNotExists(QPDFObjGen const& og) { - if ((!m->obj_cache.count(og)) && (!m->xref_table.count(og))) { + if (!isCached(og) && !m->xref_table.count(og)) { resolve(og); m->obj_cache[og].object = QPDF_Reserved::create(); return newIndirect(og, m->obj_cache[og].object); diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index c8611e07..aae06529 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2609,7 +2609,7 @@ QPDFObjectHandle::dereference() if (!isInitialized()) { return false; } - if (this->obj->getTypeCode() == QPDFObject::ot_unresolved) { + if (this->obj->isUnresolved()) { this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); } return true; -- cgit v1.2.3-54-g00ecf From 556c34f0f225bfc6eaeb617693e0161fbce5f2f3 Mon Sep 17 00:00:00 2001 From: m-holger Date: Wed, 10 Aug 2022 13:16:06 +0100 Subject: Add private method QPDF::ObjCache::update Add a new obj_cache entry or update an existing entry in place. --- include/qpdf/QPDF.hh | 5 +++++ libqpdf/QPDF.cc | 20 ++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index ee265cec..c187d53f 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1177,6 +1177,11 @@ class QPDF newIndirect(QPDFObjGen const&, std::shared_ptr const&); bool isCached(QPDFObjGen const& og); bool isUnresolved(QPDFObjGen const& og); + void updateCache( + QPDFObjGen const& og, + std::shared_ptr 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( diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index d877c14a..80cc34cc 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2111,6 +2111,23 @@ QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) return QPDFObjectHandle::Factory::newIndirect(this, og, obj); } +void +QPDF::updateCache( + QPDFObjGen const& og, + std::shared_ptr const& object, + qpdf_offset_t end_before_space, + qpdf_offset_t end_after_space) +{ + if (isCached(og)) { + auto& cache = m->obj_cache[og]; + cache.object->assign(object); + cache.end_before_space = end_before_space; + cache.end_after_space = end_after_space; + } else { + m->obj_cache[og] = ObjCache(object, end_before_space, end_after_space); + } +} + bool QPDF::isCached(QPDFObjGen const& og) { @@ -2199,8 +2216,7 @@ QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh) resolve(og); // Replace the object in the object cache - m->obj_cache[og].object->assign( - QPDFObjectHandle::ObjAccessor::getObject(oh)); + updateCache(og, QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); } void -- cgit v1.2.3-54-g00ecf From c5d0428da21c9b2531fcf6b83f08a52eb7a86a4a Mon Sep 17 00:00:00 2001 From: m-holger Date: Wed, 10 Aug 2022 13:16:06 +0100 Subject: Modify QPDF::getObject to not to resolve the object --- libqpdf/QPDF.cc | 52 +++++++++++++++++++++++++++----------------- qpdf/qtest/qpdf/issue-51.out | 1 - 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 80cc34cc..39043048 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -1397,7 +1398,7 @@ QPDF::fixDanglingReferences(bool force) std::list queue; queue.push_back(this->m->trailer); for (auto const& og: to_process) { - auto obj = getObjectByObjGen(og); + auto obj = getObject(og); if (obj.isDictionary() || obj.isArray()) { queue.push_back(obj); } else if (obj.isStream()) { @@ -1424,11 +1425,10 @@ QPDF::fixDanglingReferences(bool force) } for (auto sub: to_check) { if (sub.isIndirect()) { - if (sub.getOwningQPDF() == this) { - if (!isCached(sub.getObjGen())) { - QTC::TC("qpdf", "QPDF detected dangling ref"); - queue.push_back(sub); - } + if ((sub.getOwningQPDF() == this) && + isUnresolved(sub.getObjGen())) { + QTC::TC("qpdf", "QPDF detected dangling ref"); + queue.push_back(sub); } } else { queue.push_back(sub); @@ -1885,7 +1885,7 @@ QPDF::readObjectAtOffset( "expected endobj"); } - if (!isCached(og)) { + if (isUnresolved(og)) { // Store the object in the cache here so it gets cached // whether we first know the offset or whether we first know // the object ID and generation (in which we case we would get @@ -1916,8 +1916,8 @@ QPDF::readObjectAtOffset( } } qpdf_offset_t end_after_space = this->m->file->tell(); - - this->m->obj_cache[og] = ObjCache( + updateCache( + og, QPDFObjectHandle::ObjAccessor::getObject(oh), end_before_space, end_after_space); @@ -1929,6 +1929,11 @@ QPDF::readObjectAtOffset( std::shared_ptr QPDF::resolve(QPDFObjGen const& og) { + if (isCached(og) && !isUnresolved(og)) { + // We only need to resolve unresolved objects + return m->obj_cache[og].object; + } + // Check object cache before checking xref table. This allows us // to insert things into the object cache that don't actually // exist in the file. @@ -1942,11 +1947,13 @@ QPDF::resolve(QPDFObjGen const& og) "", this->m->file->getLastOffset(), ("loop detected resolving object " + og.unparse(' '))); - return QPDF_Null::create(); + + updateCache(og, QPDF_Null::create(), -1, -1); + return m->obj_cache[og].object; } ResolveRecorder rr(this, og); - if ((!isCached(og)) && this->m->xref_table.count(og)) { + if (m->xref_table.count(og) != 0) { QPDFXRefEntry const& entry = this->m->xref_table[og]; try { switch (entry.getType()) { @@ -1984,12 +1991,11 @@ QPDF::resolve(QPDFObjGen const& og) ": error reading object: " + e.what())); } } - if (!isCached(og)) { + + if (isUnresolved(og)) { // PDF spec says unknown objects resolve to the null object. QTC::TC("qpdf", "QPDF resolve failure to null"); - QPDFObjectHandle oh = QPDFObjectHandle::newNull(); - this->m->obj_cache[og] = - ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); + updateCache(og, QPDF_Null::create(), -1, -1); } std::shared_ptr result(this->m->obj_cache[og].object); @@ -2084,15 +2090,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number) // objects appended to the file, so it is necessary to recheck the // xref table and only cache what would actually be resolved here. for (auto const& iter: offsets) { - int obj = iter.first; - QPDFObjGen og(obj, 0); + QPDFObjGen og(iter.first, 0); QPDFXRefEntry const& entry = this->m->xref_table[og]; if ((entry.getType() == 2) && (entry.getObjStreamNumber() == obj_stream_number)) { int offset = iter.second; input->seek(offset, SEEK_SET); QPDFObjectHandle oh = readObject(input, "", og, true); - this->m->obj_cache[og] = ObjCache( + updateCache( + og, QPDFObjectHandle::ObjAccessor::getObject(oh), end_before_space, end_after_space); @@ -2176,8 +2182,14 @@ QPDF::reserveStream(QPDFObjGen const& og) QPDFObjectHandle QPDF::getObject(QPDFObjGen const& og) { - auto obj = (og.getObj() != 0) ? resolve(og) : QPDF_Null::create(); - return newIndirect(og, obj); + if (!og.isIndirect()) { + return QPDFObjectHandle::newNull(); + } + // auto obj = (og.getObj() != 0) ? resolve(og) : QPDF_Null::create(); + if (!m->obj_cache.count(og)) { + m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(), -1, -1); + } + return newIndirect(og, m->obj_cache[og].object); } QPDFObjectHandle diff --git a/qpdf/qtest/qpdf/issue-51.out b/qpdf/qtest/qpdf/issue-51.out index b4bd165c..feffea44 100644 --- a/qpdf/qtest/qpdf/issue-51.out +++ b/qpdf/qtest/qpdf/issue-51.out @@ -9,7 +9,6 @@ WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj -WARNING: issue-51.pdf (object 2 0, offset 977): EOF after endobj WARNING: issue-51.pdf (object 3 0): object has offset 0 WARNING: issue-51.pdf (object 4 0): object has offset 0 WARNING: issue-51.pdf (object 5 0): object has offset 0 -- cgit v1.2.3-54-g00ecf From 356b582cec5be67cbf60ad64a1b2a7cab689dd77 Mon Sep 17 00:00:00 2001 From: m-holger Date: Wed, 10 Aug 2022 13:16:06 +0100 Subject: Remove QPDFObjectHandle::newIndirect Modify QPDFParser::parse to call QPDF::getObject instead. --- include/qpdf/QPDFObjectHandle.hh | 1 - include/qpdf/QPDFValue.hh | 4 +++- libqpdf/QPDFObjectHandle.cc | 14 -------------- libqpdf/QPDFParser.cc | 23 ++++++++++++++--------- qpdf/qpdf.testcov | 2 +- 5 files changed, 18 insertions(+), 26 deletions(-) diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 1128c3ed..0dc474cd 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1592,7 +1592,6 @@ class QPDFObjectHandle QPDFObjectHandle(std::shared_ptr const&); // Private object factory methods - static QPDFObjectHandle newIndirect(QPDF*, QPDFObjGen const& og); static QPDFObjectHandle newStream( QPDF* qpdf, QPDFObjGen const& og, diff --git a/include/qpdf/QPDFValue.hh b/include/qpdf/QPDFValue.hh index 33558f1b..4ed3a0de 100644 --- a/include/qpdf/QPDFValue.hh +++ b/include/qpdf/QPDFValue.hh @@ -64,7 +64,9 @@ class QPDFValue void setParsedOffset(qpdf_offset_t offset) { - parsed_offset = offset; + if (parsed_offset < 0) { + parsed_offset = offset; + } } qpdf_offset_t getParsedOffset() diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index aae06529..d4a75fae 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2002,20 +2002,6 @@ QPDFObjectHandle::getParsedOffset() } } -QPDFObjectHandle -QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og) -{ - if (!og.isIndirect()) { - // Special case: QPDF uses objid 0 as a sentinel for direct - // objects, and the PDF specification doesn't allow for object - // 0. Treat indirect references to object 0 as null so that we - // never create an indirect object with objid 0. - QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid"); - return newNull(); - } - return QPDFObjectHandle(qpdf, og, QPDF_Unresolved::create()); -} - QPDFObjectHandle QPDFObjectHandle::newBool(bool value) { diff --git a/libqpdf/QPDFParser.cc b/libqpdf/QPDFParser.cc index ccdd9db0..9aa1f426 100644 --- a/libqpdf/QPDFParser.cc +++ b/libqpdf/QPDFParser.cc @@ -1,8 +1,8 @@ #include #include +#include #include -#include #include #include @@ -55,6 +55,7 @@ QPDFParser::parse(bool& empty, bool content_stream) while (!done) { bool bad = false; + bool indirect_ref = false; is_null = false; auto& frame = stack.back(); auto& olist = frame.olist; @@ -185,12 +186,16 @@ QPDFParser::parse(bool& empty, bool content_stream) "QPDFObjectHandle::parse called without context" " on an object with indirect references"); } - // Try to resolve indirect objects - object = QPDFObjectHandle::newIndirect( - context, - QPDFObjGen( - olist.at(size - 2).getIntValueAsInt(), - olist.back().getIntValueAsInt())); + auto ref_og = QPDFObjGen( + olist.at(size - 2).getIntValueAsInt(), + olist.back().getIntValueAsInt()); + if (ref_og.isIndirect()) { + object = context->getObject(ref_og); + indirect_ref = true; + } else { + QTC::TC("qpdf", "QPDFParser indirect with 0 objid"); + is_null = true; + } olist.pop_back(); olist.pop_back(); } else if ((value == "endobj") && (state == st_top)) { @@ -274,8 +279,8 @@ QPDFParser::parse(bool& empty, bool content_stream) case st_dictionary: case st_array: - if (!object.isDirectNull()) { - // No need to set description for direct nulls- they will + if (!indirect_ref && !object.isDirectNull()) { + // No need to set description for direct nulls - they will // become implicit. setDescriptionFromInput(object, input->getLastOffset()); object.setParsedOffset(input->getLastOffset()); diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index f13385e4..c3ab0a07 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -254,7 +254,7 @@ QPDFWriter standard deterministic ID 1 QPDFWriter linearized deterministic ID 1 QPDFWriter deterministic with no data 0 qpdf-c called qpdf_set_deterministic_ID 0 -QPDFObjectHandle indirect with 0 objid 0 +QPDFParser indirect with 0 objid 0 QPDF object id 0 0 QPDF recursion loop in resolve 0 QPDFParser treat word as string 0 -- cgit v1.2.3-54-g00ecf From ae6e484e23e4f11878689be32bfcc6a28259b708 Mon Sep 17 00:00:00 2001 From: m-holger Date: Wed, 10 Aug 2022 13:16:06 +0100 Subject: Change return type of QPDF::resolve to void --- include/qpdf/QPDF.hh | 6 +++--- libqpdf/QPDF.cc | 10 ++++------ libqpdf/QPDFObjectHandle.cc | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index c187d53f..42097425 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -846,10 +846,10 @@ class QPDF friend class QPDFObjectHandle; private: - static std::shared_ptr + static void resolve(QPDF* qpdf, QPDFObjGen const& og) { - return qpdf->resolve(og); + qpdf->resolve(og); } }; friend class Resolver; @@ -1168,7 +1168,7 @@ class QPDF std::string const& description, QPDFObjGen const& exp_og, QPDFObjGen& og); - std::shared_ptr 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); diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 39043048..553c1a41 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1926,12 +1926,12 @@ QPDF::readObjectAtOffset( return oh; } -std::shared_ptr +void QPDF::resolve(QPDFObjGen const& og) { if (isCached(og) && !isUnresolved(og)) { // We only need to resolve unresolved objects - return m->obj_cache[og].object; + return; } // Check object cache before checking xref table. This allows us @@ -1947,9 +1947,8 @@ QPDF::resolve(QPDFObjGen const& og) "", this->m->file->getLastOffset(), ("loop detected resolving object " + og.unparse(' '))); - updateCache(og, QPDF_Null::create(), -1, -1); - return m->obj_cache[og].object; + return; } ResolveRecorder rr(this, og); @@ -1998,11 +1997,10 @@ QPDF::resolve(QPDFObjGen const& og) updateCache(og, QPDF_Null::create(), -1, -1); } - std::shared_ptr result(this->m->obj_cache[og].object); + auto result(this->m->obj_cache[og].object); if (!result->hasDescription()) { result->setDescription(this, ("object " + og.unparse(' '))); } - return result; } void diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index d4a75fae..8a38352f 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2596,7 +2596,7 @@ QPDFObjectHandle::dereference() return false; } if (this->obj->isUnresolved()) { - this->obj = QPDF::Resolver::resolve(this->qpdf, getObjGen()); + QPDF::Resolver::resolve(this->qpdf, getObjGen()); } return true; } -- cgit v1.2.3-54-g00ecf From 89061d5b33baa7e8f4e3486d0c7ccf2447500b13 Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 12 Aug 2022 15:14:11 +0100 Subject: Change QPDF_Unresolved::create method to take QPDF* and QPDFObjGen parameters --- include/qpdf/QPDFValue.hh | 29 +++++++++++++++++++++++++++-- libqpdf/QPDF.cc | 5 ++--- libqpdf/QPDF_Unresolved.cc | 12 +++++++----- libqpdf/qpdf/QPDF_Unresolved.hh | 4 ++-- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/include/qpdf/QPDFValue.hh b/include/qpdf/QPDFValue.hh index 4ed3a0de..8b4f53b5 100644 --- a/include/qpdf/QPDFValue.hh +++ b/include/qpdf/QPDFValue.hh @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -73,11 +74,21 @@ class QPDFValue { return parsed_offset; } + QPDF* + getQPDF() + { + return qpdf; + } + QPDFObjGen + getObjGen() + { + return og; + } protected: QPDFValue() : type_code(::ot_uninitialized), - type_name("uninitilized") + type_name("uninitialized") { } QPDFValue(qpdf_object_type_e type_code, char const* type_name) : @@ -85,7 +96,17 @@ class QPDFValue 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() { @@ -100,6 +121,10 @@ class QPDFValue 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/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 553c1a41..f33e2920 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2183,9 +2183,8 @@ QPDF::getObject(QPDFObjGen const& og) if (!og.isIndirect()) { return QPDFObjectHandle::newNull(); } - // auto obj = (og.getObj() != 0) ? resolve(og) : QPDF_Null::create(); - if (!m->obj_cache.count(og)) { - m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(), -1, -1); + if (!isCached(og)) { + m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1); } return newIndirect(og, m->obj_cache[og].object); } diff --git a/libqpdf/QPDF_Unresolved.cc b/libqpdf/QPDF_Unresolved.cc index 40d4874e..f824a9a6 100644 --- a/libqpdf/QPDF_Unresolved.cc +++ b/libqpdf/QPDF_Unresolved.cc @@ -2,21 +2,23 @@ #include -QPDF_Unresolved::QPDF_Unresolved() : - QPDFValue(::ot_unresolved, "unresolved") +QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) : + QPDFValue(::ot_unresolved, "unresolved", qpdf, og) { } std::shared_ptr -QPDF_Unresolved::create() +QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og) { - return do_create(new QPDF_Unresolved()); + return do_create(new QPDF_Unresolved(qpdf, og)); } std::shared_ptr QPDF_Unresolved::shallowCopy() { - return create(); + throw std::logic_error( + "attempted to shallow copy unresolved QPDFObjectHandle"); + return create(qpdf, og); } std::string diff --git a/libqpdf/qpdf/QPDF_Unresolved.hh b/libqpdf/qpdf/QPDF_Unresolved.hh index c1231590..efcf4e3d 100644 --- a/libqpdf/qpdf/QPDF_Unresolved.hh +++ b/libqpdf/qpdf/QPDF_Unresolved.hh @@ -7,13 +7,13 @@ class QPDF_Unresolved: public QPDFValue { public: virtual ~QPDF_Unresolved() = default; - static std::shared_ptr create(); + static std::shared_ptr create(QPDF* qpdf, QPDFObjGen const& og); virtual std::shared_ptr shallowCopy(); virtual std::string unparse(); virtual JSON getJSON(int json_version); private: - QPDF_Unresolved(); + QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og); }; #endif // QPDF_UNRESOLVED_HH -- cgit v1.2.3-54-g00ecf From 56e9bcabe984acd4479ff7fef9a2a0ca669abc76 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 14 Aug 2022 01:05:32 +0100 Subject: Add methods QPDFObject::setObjGen and QPDFObject::resetObjGen Also, modify QPDFObject::swapWith to update the ObjGens of the swapped objects. Modify QPDF::newIndirect and QPDF::updateCache to keep object ObjGens up to date. --- include/qpdf/QPDFObject.hh | 18 ++++++++++++++++++ libqpdf/QPDF.cc | 3 +++ 2 files changed, 21 insertions(+) diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index 198488dd..7bb7c6e1 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -133,7 +133,25 @@ class QPDFObject 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() { diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index f33e2920..1e73f794 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2109,6 +2109,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) QPDFObjectHandle QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) { + obj->setObjGen(this, og); if (!obj->hasDescription()) { obj->setDescription(this, "object " + og.unparse(' ')); } @@ -2122,8 +2123,10 @@ QPDF::updateCache( qpdf_offset_t end_before_space, qpdf_offset_t end_after_space) { + object->setObjGen(this, og); if (isCached(og)) { auto& cache = m->obj_cache[og]; + cache.object->resetObjGen(); cache.object->assign(object); cache.end_before_space = end_before_space; cache.end_after_space = end_after_space; -- cgit v1.2.3-54-g00ecf From 4a8515912c80e8d98c3c1a42eec4bdf7b6bbd8e1 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 14 Aug 2022 10:50:30 +0100 Subject: Add method QPDFObject::resolve --- include/qpdf/QPDF.hh | 2 +- include/qpdf/QPDFObject.hh | 11 ++++++++++- libqpdf/QPDFObject.cc | 9 +++++++++ libqpdf/QPDFObjectHandle.cc | 4 +--- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 42097425..bcd85cd2 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -843,7 +843,7 @@ class QPDF // it can resolve indirect references. class Resolver { - friend class QPDFObjectHandle; + friend class QPDFObject; private: static void diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index 7bb7c6e1..751a5736 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -153,10 +153,19 @@ class QPDFObject } bool - isUnresolved() + isUnresolved() const { return value->type_code == ::ot_unresolved; } + void + resolve() + { + if (isUnresolved()) { + doResolve(); + } + } + void doResolve(); + template T* as() diff --git a/libqpdf/QPDFObject.cc b/libqpdf/QPDFObject.cc index 8df2b480..8b538021 100644 --- a/libqpdf/QPDFObject.cc +++ b/libqpdf/QPDFObject.cc @@ -1 +1,10 @@ #include + +#include + +void +QPDFObject::doResolve() +{ + auto og = value->og; + QPDF::Resolver::resolve(value->qpdf, og); +} diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 8a38352f..c55506a5 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2595,9 +2595,7 @@ QPDFObjectHandle::dereference() if (!isInitialized()) { return false; } - if (this->obj->isUnresolved()) { - QPDF::Resolver::resolve(this->qpdf, getObjGen()); - } + this->obj->resolve(); return true; } -- cgit v1.2.3-54-g00ecf From 5033e3b215c36457106cc2dd0150f2322655360c Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 14 Aug 2022 11:19:00 +0100 Subject: Add method QPDFObject::getQPDF and remove QPDFObjectHandle::qpdf --- include/qpdf/QPDFObject.hh | 6 ++++++ include/qpdf/QPDFObjectHandle.hh | 13 ++++++------- libqpdf/QPDFObjectHandle.cc | 10 ++++------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index 751a5736..6801cd5b 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -97,6 +97,12 @@ class QPDFObject { return value->type_name; } + // Returns nullptr for direct objects + QPDF* + getQPDF() const + { + return value->qpdf; + } void setDescription(QPDF* qpdf, std::string const& description) { diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 0dc474cd..d23d0fd4 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -973,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, @@ -1584,7 +1584,6 @@ class QPDFObjectHandle QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr const& obj) : - qpdf(qpdf), og(og), obj(obj) { @@ -1641,7 +1640,6 @@ class QPDFObjectHandle // 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 obj; }; @@ -1896,14 +1894,15 @@ QPDFObjectHandle::isInitialized() const // 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 diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index c55506a5..2c93dcbf 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -235,13 +235,11 @@ LastChar::getLastChar() return this->last_char; } -QPDFObjectHandle::QPDFObjectHandle() : - qpdf(nullptr) +QPDFObjectHandle::QPDFObjectHandle() { } QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr const& data) : - qpdf(nullptr), obj(data) { } @@ -2284,7 +2282,6 @@ QPDFObjectHandle::copyObject( " reserved object handle direct"); } - qpdf = nullptr; og = QPDFObjGen(); std::shared_ptr new_obj; @@ -2572,8 +2569,9 @@ QPDFObjectHandle::isImage(bool exclude_imagemask) void QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const { - if ((this->qpdf != nullptr) && (item.qpdf != nullptr) && - (this->qpdf != item.qpdf)) { + auto qpdf = getOwningQPDF(); + auto item_qpdf = item.getOwningQPDF(); + if ((qpdf != nullptr) && (item_qpdf != nullptr) && (qpdf != item_qpdf)) { QTC::TC("qpdf", "QPDFObjectHandle check ownership"); throw std::logic_error( "Attempting to add an object from a different QPDF." -- cgit v1.2.3-54-g00ecf From 1bb40238e0d788e9de1ad752dcb7bfd4ff975885 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 14 Aug 2022 11:32:20 +0100 Subject: Add method QPDFObject::getObjGen and remove QPDFObjectHandle::og --- include/qpdf/QPDFObject.hh | 6 ++++++ include/qpdf/QPDFObjectHandle.hh | 8 +++----- libqpdf/QPDFObjectHandle.cc | 2 -- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/qpdf/QPDFObject.hh b/include/qpdf/QPDFObject.hh index 6801cd5b..e6d1d18b 100644 --- a/include/qpdf/QPDFObject.hh +++ b/include/qpdf/QPDFObject.hh @@ -103,6 +103,12 @@ class QPDFObject { return value->qpdf; } + QPDFObjGen + getObjGen() const + { + return value->og; + } + void setDescription(QPDF* qpdf, std::string const& description) { diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index d23d0fd4..399d1b01 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1584,7 +1584,6 @@ class QPDFObjectHandle QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr const& obj) : - og(og), obj(obj) { } @@ -1640,7 +1639,6 @@ class QPDFObjectHandle // Moving members of QPDFObjectHandle into a smart pointer incurs // a substantial performance penalty since QPDFObjectHandle // objects are copied around so frequently. - QPDFObjGen og; std::shared_ptr obj; }; @@ -1864,19 +1862,19 @@ 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 diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 2c93dcbf..7a614bbf 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2282,8 +2282,6 @@ QPDFObjectHandle::copyObject( " reserved object handle direct"); } - og = QPDFObjGen(); - std::shared_ptr new_obj; if (isBool() || isInteger() || isName() || isNull() || isReal() || -- cgit v1.2.3-54-g00ecf From 2b7e9ba2f5a247ea45ac19cdf73506f351d5afb1 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 14 Aug 2022 11:43:32 +0100 Subject: Remove methods and parameters obsoleted by the last two commits --- include/qpdf/QPDFObjectHandle.hh | 15 ++++----------- libqpdf/QPDF.cc | 2 +- libqpdf/QPDFObjectHandle.cc | 9 --------- 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index 399d1b01..16e8dc8b 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -326,7 +326,7 @@ class QPDFObjectHandle }; QPDF_DLL - QPDFObjectHandle(); + QPDFObjectHandle() = default; QPDF_DLL QPDFObjectHandle(QPDFObjectHandle const&) = default; QPDF_DLL @@ -1453,12 +1453,9 @@ class QPDFObjectHandle private: static QPDFObjectHandle - newIndirect( - QPDF* qpdf, - QPDFObjGen const& og, - std::shared_ptr const& obj) + newIndirect(std::shared_ptr const& obj) { - return QPDFObjectHandle(qpdf, og, obj); + return QPDFObjectHandle(obj); } static QPDFObjectHandle newStream( @@ -1580,14 +1577,10 @@ class QPDFObjectHandle bool isImage(bool exclude_imagemask = true); private: - QPDFObjectHandle( - QPDF* qpdf, - QPDFObjGen const& og, - std::shared_ptr const& obj) : + QPDFObjectHandle(std::shared_ptr const& obj) : obj(obj) { } - QPDFObjectHandle(std::shared_ptr const&); // Private object factory methods static QPDFObjectHandle newStream( diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 1e73f794..e41290f2 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2113,7 +2113,7 @@ QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr const& obj) if (!obj->hasDescription()) { obj->setDescription(this, "object " + og.unparse(' ')); } - return QPDFObjectHandle::Factory::newIndirect(this, og, obj); + return QPDFObjectHandle::Factory::newIndirect(obj); } void diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 7a614bbf..19a85034 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -235,15 +235,6 @@ LastChar::getLastChar() return this->last_char; } -QPDFObjectHandle::QPDFObjectHandle() -{ -} - -QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr const& data) : - obj(data) -{ -} - void QPDFObjectHandle::releaseResolved() { -- cgit v1.2.3-54-g00ecf From 805c1ad47968e33e1296af9a31492f6916ad9113 Mon Sep 17 00:00:00 2001 From: m-holger Date: Mon, 15 Aug 2022 15:13:11 +0100 Subject: Reset QPDFValue::qpdf and QPDFValue::og when the owning QPDF object gets destroyed --- libqpdf/QPDF.cc | 1 + qpdf/qtest/type-checks.test | 6 +++++- qpdf/test_driver.cc | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index e41290f2..9593c44f 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -259,6 +259,7 @@ QPDF::~QPDF() this->m->xref_table.clear(); for (auto const& iter: this->m->obj_cache) { QPDFObject::ObjAccessor::releaseResolved(iter.second.object.get()); + iter.second.object->resetObjGen(); } } diff --git a/qpdf/qtest/type-checks.test b/qpdf/qtest/type-checks.test index 03d75a6c..17b3c994 100644 --- a/qpdf/qtest/type-checks.test +++ b/qpdf/qtest/type-checks.test @@ -14,7 +14,7 @@ cleanup(); my $td = new TestDriver('type-checks'); -my $n_tests = 5; +my $n_tests = 6; # Whenever object-types.pdf is edited, object-types-os.pdf should be # regenerated. @@ -43,6 +43,10 @@ $td->runtest("compound type checks", {$td->COMMAND => "test_driver 82 object-types-os.pdf"}, {$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); +$td->runtest("indirect objects belonging to destroyed QPDF", + {$td->COMMAND => "test_driver 92 -"}, + {$td->STRING => "test 92 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); cleanup(); $td->report($n_tests); diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index aa4f9ce5..5572e824 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -3258,6 +3258,20 @@ test_91(QPDF& pdf, char const* arg2) 2, &p, qpdf_dl_none, qpdf_sj_inline, "", std::set()); } +static void +test_92(QPDF& pdf, char const* arg2) +{ + // Exercise indirect objects owned by destroyed QPDF object. + QPDF* qpdf = new QPDF(); + qpdf->emptyPDF(); + auto root = qpdf->getRoot(); + assert(root.getOwningQPDF() != nullptr); + assert(root.isIndirect()); + delete qpdf; + assert(root.getOwningQPDF() == nullptr); + assert(!root.isIndirect()); +} + void runtest(int n, char const* filename1, char const* arg2) { @@ -3265,7 +3279,7 @@ runtest(int n, char const* filename1, char const* arg2) // the test suite to see how the test is invoked to find the file // that the test is supposed to operate on. - std::set ignore_filename = {61, 81, 83, 84, 85, 86, 87}; + std::set ignore_filename = {61, 81, 83, 84, 85, 86, 87, 92}; if (n == 0) { // Throw in some random test cases that don't fit anywhere @@ -3362,7 +3376,8 @@ runtest(int n, char const* filename1, char const* arg2) {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79}, {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83}, {84, test_84}, {85, test_85}, {86, test_86}, {87, test_87}, - {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91}}; + {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91}, + {92, test_92}}; auto fn = test_functions.find(n); if (fn == test_functions.end()) { -- cgit v1.2.3-54-g00ecf