Commit f78b99939c7d56b8c92c1f0e1bf4507363e351c7
1 parent
586865f9
Move QPDFObject::disconnect to Basehandle
Showing
6 changed files
with
49 additions
and
61 deletions
include/qpdf/ObjectHandle.hh
| @@ -47,6 +47,8 @@ namespace qpdf | @@ -47,6 +47,8 @@ namespace qpdf | ||
| 47 | // QPDFObjGen and bool. | 47 | // QPDFObjGen and bool. |
| 48 | class BaseHandle | 48 | class BaseHandle |
| 49 | { | 49 | { |
| 50 | + friend class QPDF; | ||
| 51 | + | ||
| 50 | public: | 52 | public: |
| 51 | explicit inline operator bool() const; | 53 | explicit inline operator bool() const; |
| 52 | inline operator QPDFObjectHandle() const; | 54 | inline operator QPDFObjectHandle() const; |
| @@ -55,6 +57,9 @@ namespace qpdf | @@ -55,6 +57,9 @@ namespace qpdf | ||
| 55 | // The rest of the header file is for qpdf internal use only. | 57 | // The rest of the header file is for qpdf internal use only. |
| 56 | 58 | ||
| 57 | std::shared_ptr<QPDFObject> copy(bool shallow = false) const; | 59 | std::shared_ptr<QPDFObject> copy(bool shallow = false) const; |
| 60 | + // Recursively remove association with any QPDF object. This method may only be called | ||
| 61 | + // during final destruction. | ||
| 62 | + void disconnect(bool only_direct = true); | ||
| 58 | inline QPDFObjGen id_gen() const; | 63 | inline QPDFObjGen id_gen() const; |
| 59 | inline bool indirect() const; | 64 | inline bool indirect() const; |
| 60 | inline bool null() const; | 65 | inline bool null() const; |
include/qpdf/QPDFObjectHandle.hh
| @@ -1242,19 +1242,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle | @@ -1242,19 +1242,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle | ||
| 1242 | QPDF_DLL | 1242 | QPDF_DLL |
| 1243 | void warnIfPossible(std::string const& warning) const; | 1243 | void warnIfPossible(std::string const& warning) const; |
| 1244 | 1244 | ||
| 1245 | - // Provide access to specific classes for recursive disconnected(). | ||
| 1246 | - class DisconnectAccess | ||
| 1247 | - { | ||
| 1248 | - friend class QPDFObject; | ||
| 1249 | - | ||
| 1250 | - private: | ||
| 1251 | - static void | ||
| 1252 | - disconnect(QPDFObjectHandle o) | ||
| 1253 | - { | ||
| 1254 | - o.disconnect(); | ||
| 1255 | - } | ||
| 1256 | - }; | ||
| 1257 | - | ||
| 1258 | // Convenience routine: Throws if the assumption is violated. Your code will be better if you | 1245 | // Convenience routine: Throws if the assumption is violated. Your code will be better if you |
| 1259 | // call one of the isType methods and handle the case of the type being wrong, but these can be | 1246 | // call one of the isType methods and handle the case of the type being wrong, but these can be |
| 1260 | // convenient if you have already verified the type. | 1247 | // convenient if you have already verified the type. |
| @@ -1354,7 +1341,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle | @@ -1354,7 +1341,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle | ||
| 1354 | void objectWarning(std::string const& warning) const; | 1341 | void objectWarning(std::string const& warning) const; |
| 1355 | void assertType(char const* type_name, bool istype) const; | 1342 | void assertType(char const* type_name, bool istype) const; |
| 1356 | void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); | 1343 | void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); |
| 1357 | - void disconnect(); | ||
| 1358 | void setParsedOffset(qpdf_offset_t offset); | 1344 | void setParsedOffset(qpdf_offset_t offset); |
| 1359 | void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks); | 1345 | void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks); |
| 1360 | static void parseContentStream_data( | 1346 | static void parseContentStream_data( |
libqpdf/QPDF.cc
| @@ -212,6 +212,25 @@ QPDF::QPDF() : | @@ -212,6 +212,25 @@ QPDF::QPDF() : | ||
| 212 | m->unique_id = unique_id.fetch_add(1ULL); | 212 | m->unique_id = unique_id.fetch_add(1ULL); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | +// Provide access to disconnect(). Disconnect will in due course be merged into the current ObjCache | ||
| 216 | +// (future Objects::Entry) to centralize all QPDF access to QPDFObject. | ||
| 217 | +class Disconnect: BaseHandle | ||
| 218 | +{ | ||
| 219 | + public: | ||
| 220 | + Disconnect(std::shared_ptr<QPDFObject> const& obj) : | ||
| 221 | + BaseHandle(obj) | ||
| 222 | + { | ||
| 223 | + } | ||
| 224 | + void | ||
| 225 | + disconnect() | ||
| 226 | + { | ||
| 227 | + BaseHandle::disconnect(false); | ||
| 228 | + if (raw_type_code() != ::ot_null) { | ||
| 229 | + obj->value = QPDF_Destroyed(); | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | +}; | ||
| 233 | + | ||
| 215 | QPDF::~QPDF() | 234 | QPDF::~QPDF() |
| 216 | { | 235 | { |
| 217 | // If two objects are mutually referential (through each object having an array or dictionary | 236 | // If two objects are mutually referential (through each object having an array or dictionary |
| @@ -228,10 +247,7 @@ QPDF::~QPDF() | @@ -228,10 +247,7 @@ QPDF::~QPDF() | ||
| 228 | // the xref table anyway just to prevent any possibility of resolve() succeeding. | 247 | // the xref table anyway just to prevent any possibility of resolve() succeeding. |
| 229 | m->xref_table.clear(); | 248 | m->xref_table.clear(); |
| 230 | for (auto const& iter: m->obj_cache) { | 249 | for (auto const& iter: m->obj_cache) { |
| 231 | - iter.second.object->disconnect(); | ||
| 232 | - if (iter.second.object->getTypeCode() != ::ot_null) { | ||
| 233 | - iter.second.object->destroy(); | ||
| 234 | - } | 250 | + Disconnect(iter.second.object).disconnect(); |
| 235 | } | 251 | } |
| 236 | } | 252 | } |
| 237 | 253 |
libqpdf/QPDFObjectHandle.cc
| @@ -580,48 +580,49 @@ BaseHandle::write_json(int json_version, JSON::Writer& p) const | @@ -580,48 +580,49 @@ BaseHandle::write_json(int json_version, JSON::Writer& p) const | ||
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | void | 582 | void |
| 583 | -QPDFObject::disconnect() | 583 | +BaseHandle::disconnect(bool only_direct) |
| 584 | { | 584 | { |
| 585 | - // Disconnect an object from its owning QPDF. This is called by QPDF's destructor. | 585 | + // QPDF::~QPDF() calls disconnect for indirect objects, so we don't do that here. |
| 586 | + if (only_direct && indirect()) { | ||
| 587 | + return; | ||
| 588 | + } | ||
| 586 | 589 | ||
| 587 | - switch (getTypeCode()) { | 590 | + switch (raw_type_code()) { |
| 588 | case ::ot_array: | 591 | case ::ot_array: |
| 589 | { | 592 | { |
| 590 | - auto& a = std::get<QPDF_Array>(value); | 593 | + auto& a = std::get<QPDF_Array>(obj->value); |
| 591 | if (a.sp) { | 594 | if (a.sp) { |
| 592 | for (auto& item: a.sp->elements) { | 595 | for (auto& item: a.sp->elements) { |
| 593 | - auto& obj = item.second; | ||
| 594 | - if (!obj.indirect()) { | ||
| 595 | - obj.getObj()->disconnect(); | ||
| 596 | - } | 596 | + item.second.disconnect(); |
| 597 | } | 597 | } |
| 598 | } else { | 598 | } else { |
| 599 | - for (auto& obj: a.elements) { | ||
| 600 | - if (!obj.indirect()) { | ||
| 601 | - obj.getObj()->disconnect(); | ||
| 602 | - } | 599 | + for (auto& oh: a.elements) { |
| 600 | + oh.disconnect(); | ||
| 603 | } | 601 | } |
| 604 | } | 602 | } |
| 605 | } | 603 | } |
| 606 | break; | 604 | break; |
| 607 | case ::ot_dictionary: | 605 | case ::ot_dictionary: |
| 608 | - for (auto& iter: std::get<QPDF_Dictionary>(value).items) { | ||
| 609 | - QPDFObjectHandle::DisconnectAccess::disconnect(iter.second); | 606 | + for (auto& iter: std::get<QPDF_Dictionary>(obj->value).items) { |
| 607 | + iter.second.disconnect(); | ||
| 610 | } | 608 | } |
| 611 | break; | 609 | break; |
| 612 | case ::ot_stream: | 610 | case ::ot_stream: |
| 613 | { | 611 | { |
| 614 | - auto& s = std::get<QPDF_Stream>(value); | 612 | + auto& s = std::get<QPDF_Stream>(obj->value); |
| 615 | s.m->stream_provider = nullptr; | 613 | s.m->stream_provider = nullptr; |
| 616 | - QPDFObjectHandle::DisconnectAccess::disconnect(s.m->stream_dict); | 614 | + s.m->stream_dict.disconnect(); |
| 617 | } | 615 | } |
| 618 | break; | 616 | break; |
| 617 | + case ::ot_uninitialized: | ||
| 618 | + return; | ||
| 619 | default: | 619 | default: |
| 620 | break; | 620 | break; |
| 621 | } | 621 | } |
| 622 | - qpdf = nullptr; | ||
| 623 | - og = QPDFObjGen(); | 622 | + obj->qpdf = nullptr; |
| 623 | + obj->og = QPDFObjGen(); | ||
| 624 | } | 624 | } |
| 625 | + | ||
| 625 | std::string | 626 | std::string |
| 626 | QPDFObject::getStringValue() const | 627 | QPDFObject::getStringValue() const |
| 627 | { | 628 | { |
| @@ -649,16 +650,6 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const | @@ -649,16 +650,6 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const | ||
| 649 | { | 650 | { |
| 650 | return this->obj == rhs.obj; | 651 | return this->obj == rhs.obj; |
| 651 | } | 652 | } |
| 652 | -void | ||
| 653 | -QPDFObjectHandle::disconnect() | ||
| 654 | -{ | ||
| 655 | - // Recursively remove association with any QPDF object. This method may only be called during | ||
| 656 | - // final destruction. QPDF::~QPDF() calls it for indirect objects using the object pointer | ||
| 657 | - // itself, so we don't do that here. Other objects call it through this method. | ||
| 658 | - if (obj && !isIndirect()) { | ||
| 659 | - this->obj->disconnect(); | ||
| 660 | - } | ||
| 661 | -} | ||
| 662 | 653 | ||
| 663 | qpdf_object_type_e | 654 | qpdf_object_type_e |
| 664 | QPDFObjectHandle::getTypeCode() const | 655 | QPDFObjectHandle::getTypeCode() const |
libqpdf/qpdf/QPDFObjectHandle_private.hh
| @@ -358,7 +358,7 @@ namespace qpdf | @@ -358,7 +358,7 @@ namespace qpdf | ||
| 358 | inline bool | 358 | inline bool |
| 359 | BaseHandle::null() const | 359 | BaseHandle::null() const |
| 360 | { | 360 | { |
| 361 | - return !obj || obj->getResolvedTypeCode() == ::ot_null; | 361 | + return !obj || type_code() == ::ot_null; |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | inline QPDF* | 364 | inline QPDF* |
| @@ -383,7 +383,7 @@ namespace qpdf | @@ -383,7 +383,7 @@ namespace qpdf | ||
| 383 | return QPDF::Resolver::resolved(obj->qpdf, obj->og)->getTypeCode(); | 383 | return QPDF::Resolver::resolved(obj->qpdf, obj->og)->getTypeCode(); |
| 384 | } | 384 | } |
| 385 | if (raw_type_code() == ::ot_reference) { | 385 | if (raw_type_code() == ::ot_reference) { |
| 386 | - return std::get<QPDF_Reference>(obj->value).obj->getResolvedTypeCode(); | 386 | + return std::get<QPDF_Reference>(obj->value).obj->getTypeCode(); |
| 387 | } | 387 | } |
| 388 | return raw_type_code(); | 388 | return raw_type_code(); |
| 389 | } | 389 | } |
libqpdf/qpdf/QPDFObject_private.hh
| @@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
| 18 | #include <variant> | 18 | #include <variant> |
| 19 | #include <vector> | 19 | #include <vector> |
| 20 | 20 | ||
| 21 | +class Disconnect; | ||
| 21 | class QPDFObject; | 22 | class QPDFObject; |
| 22 | class QPDFObjectHandle; | 23 | class QPDFObjectHandle; |
| 23 | 24 | ||
| @@ -297,7 +298,6 @@ class QPDFObject | @@ -297,7 +298,6 @@ class QPDFObject | ||
| 297 | qpdf, og, std::forward<T>(T(std::forward<Args>(args)...))); | 298 | qpdf, og, std::forward<T>(T(std::forward<Args>(args)...))); |
| 298 | } | 299 | } |
| 299 | 300 | ||
| 300 | - void disconnect(); | ||
| 301 | std::string getStringValue() const; | 301 | std::string getStringValue() const; |
| 302 | 302 | ||
| 303 | // Return a unique type code for the resolved object | 303 | // Return a unique type code for the resolved object |
| @@ -308,7 +308,7 @@ class QPDFObject | @@ -308,7 +308,7 @@ class QPDFObject | ||
| 308 | return QPDF::Resolver::resolved(qpdf, og)->getTypeCode(); | 308 | return QPDF::Resolver::resolved(qpdf, og)->getTypeCode(); |
| 309 | } | 309 | } |
| 310 | if (getTypeCode() == ::ot_reference) { | 310 | if (getTypeCode() == ::ot_reference) { |
| 311 | - return std::get<QPDF_Reference>(value).obj->getResolvedTypeCode(); | 311 | + return std::get<QPDF_Reference>(value).obj->getTypeCode(); |
| 312 | } | 312 | } |
| 313 | return getTypeCode(); | 313 | return getTypeCode(); |
| 314 | } | 314 | } |
| @@ -354,23 +354,12 @@ class QPDFObject | @@ -354,23 +354,12 @@ class QPDFObject | ||
| 354 | qpdf = a_qpdf; | 354 | qpdf = a_qpdf; |
| 355 | og = a_og; | 355 | og = a_og; |
| 356 | } | 356 | } |
| 357 | - // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects. | ||
| 358 | - void | ||
| 359 | - destroy() | ||
| 360 | - { | ||
| 361 | - value = QPDF_Destroyed(); | ||
| 362 | - } | ||
| 363 | 357 | ||
| 364 | bool | 358 | bool |
| 365 | isUnresolved() const | 359 | isUnresolved() const |
| 366 | { | 360 | { |
| 367 | return getTypeCode() == ::ot_unresolved; | 361 | return getTypeCode() == ::ot_unresolved; |
| 368 | } | 362 | } |
| 369 | - const QPDFObject* | ||
| 370 | - resolved_object() const | ||
| 371 | - { | ||
| 372 | - return isUnresolved() ? QPDF::Resolver::resolved(qpdf, og).get() : this; | ||
| 373 | - } | ||
| 374 | 363 | ||
| 375 | struct JSON_Descr | 364 | struct JSON_Descr |
| 376 | { | 365 | { |
| @@ -467,6 +456,7 @@ class QPDFObject | @@ -467,6 +456,7 @@ class QPDFObject | ||
| 467 | private: | 456 | private: |
| 468 | friend class QPDF_Stream; | 457 | friend class QPDF_Stream; |
| 469 | friend class qpdf::BaseHandle; | 458 | friend class qpdf::BaseHandle; |
| 459 | + friend class Disconnect; | ||
| 470 | 460 | ||
| 471 | typedef std::variant< | 461 | typedef std::variant< |
| 472 | std::monostate, | 462 | std::monostate, |