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 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libqpdf/QPDF.cc') 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; } -- 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(-) (limited to 'libqpdf/QPDF.cc') 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(-) (limited to 'libqpdf/QPDF.cc') 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(-) (limited to 'libqpdf/QPDF.cc') 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 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(-) (limited to 'libqpdf/QPDF.cc') 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 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(-) (limited to 'libqpdf/QPDF.cc') 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(-) (limited to 'libqpdf/QPDF.cc') 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(-) (limited to 'libqpdf/QPDF.cc') 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 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(-) (limited to 'libqpdf/QPDF.cc') 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(-) (limited to 'libqpdf/QPDF.cc') 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(+) (limited to 'libqpdf/QPDF.cc') 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 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(-) (limited to 'libqpdf/QPDF.cc') 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(-) (limited to 'libqpdf/QPDF.cc') 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