From f78b99939c7d56b8c92c1f0e1bf4507363e351c7 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 4 Mar 2025 16:07:42 +0000 Subject: [PATCH] Move QPDFObject::disconnect to Basehandle --- include/qpdf/ObjectHandle.hh | 5 +++++ include/qpdf/QPDFObjectHandle.hh | 14 -------------- libqpdf/QPDF.cc | 24 ++++++++++++++++++++---- libqpdf/QPDFObjectHandle.cc | 47 +++++++++++++++++++---------------------------- libqpdf/qpdf/QPDFObjectHandle_private.hh | 4 ++-- libqpdf/qpdf/QPDFObject_private.hh | 16 +++------------- 6 files changed, 49 insertions(+), 61 deletions(-) diff --git a/include/qpdf/ObjectHandle.hh b/include/qpdf/ObjectHandle.hh index 6bae99c..78bd9f8 100644 --- a/include/qpdf/ObjectHandle.hh +++ b/include/qpdf/ObjectHandle.hh @@ -47,6 +47,8 @@ namespace qpdf // QPDFObjGen and bool. class BaseHandle { + friend class QPDF; + public: explicit inline operator bool() const; inline operator QPDFObjectHandle() const; @@ -55,6 +57,9 @@ namespace qpdf // The rest of the header file is for qpdf internal use only. std::shared_ptr copy(bool shallow = false) const; + // Recursively remove association with any QPDF object. This method may only be called + // during final destruction. + void disconnect(bool only_direct = true); inline QPDFObjGen id_gen() const; inline bool indirect() const; inline bool null() const; diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index fd4b19d..e01fd46 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -1242,19 +1242,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle QPDF_DLL void warnIfPossible(std::string const& warning) const; - // Provide access to specific classes for recursive disconnected(). - class DisconnectAccess - { - friend class QPDFObject; - - private: - static void - disconnect(QPDFObjectHandle o) - { - o.disconnect(); - } - }; - // Convenience routine: Throws if the assumption is violated. Your code will be better if you // call one of the isType methods and handle the case of the type being wrong, but these can be // convenient if you have already verified the type. @@ -1354,7 +1341,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle void objectWarning(std::string const& warning) const; void assertType(char const* type_name, bool istype) const; void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); - void disconnect(); void setParsedOffset(qpdf_offset_t offset); void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks); static void parseContentStream_data( diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 7cbc656..8b7f1fd 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -212,6 +212,25 @@ QPDF::QPDF() : m->unique_id = unique_id.fetch_add(1ULL); } +// Provide access to disconnect(). Disconnect will in due course be merged into the current ObjCache +// (future Objects::Entry) to centralize all QPDF access to QPDFObject. +class Disconnect: BaseHandle +{ + public: + Disconnect(std::shared_ptr const& obj) : + BaseHandle(obj) + { + } + void + disconnect() + { + BaseHandle::disconnect(false); + if (raw_type_code() != ::ot_null) { + obj->value = QPDF_Destroyed(); + } + } +}; + QPDF::~QPDF() { // If two objects are mutually referential (through each object having an array or dictionary @@ -228,10 +247,7 @@ QPDF::~QPDF() // the xref table anyway just to prevent any possibility of resolve() succeeding. m->xref_table.clear(); for (auto const& iter: m->obj_cache) { - iter.second.object->disconnect(); - if (iter.second.object->getTypeCode() != ::ot_null) { - iter.second.object->destroy(); - } + Disconnect(iter.second.object).disconnect(); } } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 5d4a94b..4c001cd 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -580,48 +580,49 @@ BaseHandle::write_json(int json_version, JSON::Writer& p) const } void -QPDFObject::disconnect() +BaseHandle::disconnect(bool only_direct) { - // Disconnect an object from its owning QPDF. This is called by QPDF's destructor. + // QPDF::~QPDF() calls disconnect for indirect objects, so we don't do that here. + if (only_direct && indirect()) { + return; + } - switch (getTypeCode()) { + switch (raw_type_code()) { case ::ot_array: { - auto& a = std::get(value); + auto& a = std::get(obj->value); if (a.sp) { for (auto& item: a.sp->elements) { - auto& obj = item.second; - if (!obj.indirect()) { - obj.getObj()->disconnect(); - } + item.second.disconnect(); } } else { - for (auto& obj: a.elements) { - if (!obj.indirect()) { - obj.getObj()->disconnect(); - } + for (auto& oh: a.elements) { + oh.disconnect(); } } } break; case ::ot_dictionary: - for (auto& iter: std::get(value).items) { - QPDFObjectHandle::DisconnectAccess::disconnect(iter.second); + for (auto& iter: std::get(obj->value).items) { + iter.second.disconnect(); } break; case ::ot_stream: { - auto& s = std::get(value); + auto& s = std::get(obj->value); s.m->stream_provider = nullptr; - QPDFObjectHandle::DisconnectAccess::disconnect(s.m->stream_dict); + s.m->stream_dict.disconnect(); } break; + case ::ot_uninitialized: + return; default: break; } - qpdf = nullptr; - og = QPDFObjGen(); + obj->qpdf = nullptr; + obj->og = QPDFObjGen(); } + std::string QPDFObject::getStringValue() const { @@ -649,16 +650,6 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const { return this->obj == rhs.obj; } -void -QPDFObjectHandle::disconnect() -{ - // Recursively remove association with any QPDF object. This method may only be called during - // final destruction. QPDF::~QPDF() calls it for indirect objects using the object pointer - // itself, so we don't do that here. Other objects call it through this method. - if (obj && !isIndirect()) { - this->obj->disconnect(); - } -} qpdf_object_type_e QPDFObjectHandle::getTypeCode() const diff --git a/libqpdf/qpdf/QPDFObjectHandle_private.hh b/libqpdf/qpdf/QPDFObjectHandle_private.hh index 61ce62a..b940251 100644 --- a/libqpdf/qpdf/QPDFObjectHandle_private.hh +++ b/libqpdf/qpdf/QPDFObjectHandle_private.hh @@ -358,7 +358,7 @@ namespace qpdf inline bool BaseHandle::null() const { - return !obj || obj->getResolvedTypeCode() == ::ot_null; + return !obj || type_code() == ::ot_null; } inline QPDF* @@ -383,7 +383,7 @@ namespace qpdf return QPDF::Resolver::resolved(obj->qpdf, obj->og)->getTypeCode(); } if (raw_type_code() == ::ot_reference) { - return std::get(obj->value).obj->getResolvedTypeCode(); + return std::get(obj->value).obj->getTypeCode(); } return raw_type_code(); } diff --git a/libqpdf/qpdf/QPDFObject_private.hh b/libqpdf/qpdf/QPDFObject_private.hh index 2de0014..db2da1c 100644 --- a/libqpdf/qpdf/QPDFObject_private.hh +++ b/libqpdf/qpdf/QPDFObject_private.hh @@ -18,6 +18,7 @@ #include #include +class Disconnect; class QPDFObject; class QPDFObjectHandle; @@ -297,7 +298,6 @@ class QPDFObject qpdf, og, std::forward(T(std::forward(args)...))); } - void disconnect(); std::string getStringValue() const; // Return a unique type code for the resolved object @@ -308,7 +308,7 @@ class QPDFObject return QPDF::Resolver::resolved(qpdf, og)->getTypeCode(); } if (getTypeCode() == ::ot_reference) { - return std::get(value).obj->getResolvedTypeCode(); + return std::get(value).obj->getTypeCode(); } return getTypeCode(); } @@ -354,23 +354,12 @@ class QPDFObject qpdf = a_qpdf; og = a_og; } - // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects. - void - destroy() - { - value = QPDF_Destroyed(); - } bool isUnresolved() const { return getTypeCode() == ::ot_unresolved; } - const QPDFObject* - resolved_object() const - { - return isUnresolved() ? QPDF::Resolver::resolved(qpdf, og).get() : this; - } struct JSON_Descr { @@ -467,6 +456,7 @@ class QPDFObject private: friend class QPDF_Stream; friend class qpdf::BaseHandle; + friend class Disconnect; typedef std::variant< std::monostate, -- libgit2 0.21.4