Commit b20ff9680529692d5058b0f1fcd87c2b984b4195
1 parent
91b8b0d8
Refactor `ObjCopier` and `copyForeignObject`: enhance encapsulation, streamline …
…`Copier` usage, and simplify object copying logic.
Showing
2 changed files
with
47 additions
and
30 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -471,6 +471,12 @@ QPDF::getObjectByID(int objid, int generation) |
| 471 | 471 | return getObject(QPDFObjGen(objid, generation)); |
| 472 | 472 | } |
| 473 | 473 | |
| 474 | +QPDFObjectHandle | |
| 475 | +QPDF::copyForeignObject(QPDFObjectHandle foreign) | |
| 476 | +{ | |
| 477 | + return m->obj_copier.copied(foreign); | |
| 478 | +} | |
| 479 | + | |
| 474 | 480 | QPDF::ObjCopier::Copier& |
| 475 | 481 | QPDF::ObjCopier::copier(QPDFObjectHandle const& foreign) |
| 476 | 482 | { |
| ... | ... | @@ -485,7 +491,7 @@ QPDF::ObjCopier::copier(QPDFObjectHandle const& foreign) |
| 485 | 491 | } |
| 486 | 492 | |
| 487 | 493 | QPDFObjectHandle |
| 488 | -QPDF::copyForeignObject(QPDFObjectHandle foreign) | |
| 494 | +QPDF::ObjCopier::Copier::copied(QPDFObjectHandle const& foreign) | |
| 489 | 495 | { |
| 490 | 496 | // Here's an explanation of what's going on here. |
| 491 | 497 | // |
| ... | ... | @@ -522,42 +528,36 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign) |
| 522 | 528 | // Note that we explicitly allow use of copyForeignObject on page objects. It is a documented |
| 523 | 529 | // use case to copy pages this way if the intention is to not update the pages tree. |
| 524 | 530 | |
| 525 | - auto& obj_copier = m->obj_copier.copier(foreign); | |
| 526 | - if (!obj_copier.visiting.empty()) { | |
| 527 | - throw std::logic_error( | |
| 528 | - "obj_copier.visiting is not empty at the beginning of copyForeignObject"); | |
| 529 | - } | |
| 531 | + util::assertion( | |
| 532 | + visiting.empty(), "obj_copier.visiting is not empty at the beginning of copyForeignObject"); | |
| 530 | 533 | |
| 531 | 534 | // Make sure we have an object in this file for every referenced object in the old file. |
| 532 | 535 | // obj_copier.object_map maps foreign QPDFObjGen to local objects. For everything new that we |
| 533 | 536 | // have to copy, the local object will be a reservation, unless it is a stream, in which case |
| 534 | 537 | // the local object will already be a stream. |
| 535 | - obj_copier.reserve_objects(foreign); | |
| 538 | + reserve_objects(foreign, true); | |
| 536 | 539 | |
| 537 | - if (!obj_copier.visiting.empty()) { | |
| 538 | - throw std::logic_error("obj_copier.visiting is not empty after reserving objects"); | |
| 539 | - } | |
| 540 | + util::assertion(visiting.empty(), "obj_copier.visiting is not empty after reserving objects"); | |
| 540 | 541 | |
| 541 | 542 | // Copy any new objects and replace the reservations. |
| 542 | - for (auto& to_copy: obj_copier.to_copy) { | |
| 543 | - auto copy = obj_copier.replace_indirect_object(to_copy); | |
| 544 | - if (!to_copy.isStream()) { | |
| 545 | - QPDFObjGen og(to_copy.getObjGen()); | |
| 546 | - replaceReserved(obj_copier.object_map[og], copy); | |
| 543 | + for (auto& oh: to_copy) { | |
| 544 | + auto copy = replace_indirect_object(oh, true); | |
| 545 | + if (!oh.isStream()) { | |
| 546 | + qpdf.replaceReserved(object_map[oh], copy); | |
| 547 | 547 | } |
| 548 | 548 | } |
| 549 | - obj_copier.to_copy.clear(); | |
| 549 | + to_copy.clear(); | |
| 550 | 550 | |
| 551 | 551 | auto og = foreign.getObjGen(); |
| 552 | - if (!obj_copier.object_map.contains(og)) { | |
| 553 | - warn(damagedPDF( | |
| 552 | + if (!object_map.contains(og)) { | |
| 553 | + qpdf.warn(qpdf.damagedPDF( | |
| 554 | 554 | foreign.qpdf()->getFilename() + " object " + og.unparse(' '), |
| 555 | 555 | foreign.offset(), |
| 556 | 556 | "unexpected reference to /Pages object while copying foreign object; replacing with " |
| 557 | 557 | "null")); |
| 558 | 558 | return QPDFObjectHandle::newNull(); |
| 559 | 559 | } |
| 560 | - return obj_copier.object_map[foreign.getObjGen()]; | |
| 560 | + return object_map[foreign]; | |
| 561 | 561 | } |
| 562 | 562 | |
| 563 | 563 | void |
| ... | ... | @@ -592,17 +592,17 @@ QPDF::ObjCopier::Copier::reserve_objects(QPDFObjectHandle const& foreign, bool t |
| 592 | 592 | } |
| 593 | 593 | |
| 594 | 594 | if (foreign_tc == ::ot_array) { |
| 595 | - for (auto const& item: foreign.as_array()) { | |
| 596 | - reserve_objects(item, false); | |
| 595 | + for (auto const& item: Array(foreign)) { | |
| 596 | + reserve_objects(item); | |
| 597 | 597 | } |
| 598 | 598 | } else if (foreign_tc == ::ot_dictionary) { |
| 599 | 599 | for (auto const& item: Dictionary(foreign)) { |
| 600 | 600 | if (!item.second.null()) { |
| 601 | - reserve_objects(item.second, false); | |
| 601 | + reserve_objects(item.second); | |
| 602 | 602 | } |
| 603 | 603 | } |
| 604 | 604 | } else if (foreign_tc == ::ot_stream) { |
| 605 | - reserve_objects(foreign.getDict(), false); | |
| 605 | + reserve_objects(foreign.getDict()); | |
| 606 | 606 | } |
| 607 | 607 | |
| 608 | 608 | visiting.erase(foreign); |
| ... | ... | @@ -611,7 +611,7 @@ QPDF::ObjCopier::Copier::reserve_objects(QPDFObjectHandle const& foreign, bool t |
| 611 | 611 | QPDFObjectHandle |
| 612 | 612 | QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign, bool top) |
| 613 | 613 | { |
| 614 | - auto foreign_tc = foreign.getTypeCode(); | |
| 614 | + auto foreign_tc = foreign.type_code(); | |
| 615 | 615 | |
| 616 | 616 | if (!top && foreign.indirect()) { |
| 617 | 617 | auto mapping = object_map.find(foreign.id_gen()); |
| ... | ... | @@ -628,7 +628,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign |
| 628 | 628 | std::vector<QPDFObjectHandle> result; |
| 629 | 629 | result.reserve(array.size()); |
| 630 | 630 | for (auto const& item: array) { |
| 631 | - result.emplace_back(replace_indirect_object(item, false)); | |
| 631 | + result.emplace_back(replace_indirect_object(item)); | |
| 632 | 632 | } |
| 633 | 633 | return Array(std::move(result)); |
| 634 | 634 | } |
| ... | ... | @@ -637,7 +637,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign |
| 637 | 637 | auto result = Dictionary::empty(); |
| 638 | 638 | for (auto const& [key, value]: Dictionary(foreign)) { |
| 639 | 639 | if (!value.null()) { |
| 640 | - result.replaceKey(key, replace_indirect_object(value, false)); | |
| 640 | + result.replaceKey(key, replace_indirect_object(value)); | |
| 641 | 641 | } |
| 642 | 642 | } |
| 643 | 643 | return result; |
| ... | ... | @@ -649,7 +649,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign |
| 649 | 649 | auto dict = result.getDict(); |
| 650 | 650 | for (auto const& [key, value]: stream.getDict()) { |
| 651 | 651 | if (!value.null()) { |
| 652 | - dict.replaceKey(key, replace_indirect_object(value, false)); | |
| 652 | + dict.replaceKey(key, replace_indirect_object(value)); | |
| 653 | 653 | } |
| 654 | 654 | } |
| 655 | 655 | qpdf.copyStreamData(result, foreign); | ... | ... |
libqpdf/qpdf/QPDF_private.hh
| ... | ... | @@ -46,7 +46,6 @@ class QPDF::ObjCache |
| 46 | 46 | |
| 47 | 47 | class QPDF::ObjCopier |
| 48 | 48 | { |
| 49 | - public: | |
| 50 | 49 | class Copier |
| 51 | 50 | { |
| 52 | 51 | public: |
| ... | ... | @@ -55,9 +54,11 @@ class QPDF::ObjCopier |
| 55 | 54 | { |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | - QPDFObjectHandle replace_indirect_object(QPDFObjectHandle const& foreign, bool top = true); | |
| 57 | + QPDFObjectHandle copied(QPDFObjectHandle const& foreign); | |
| 59 | 58 | |
| 60 | - void reserve_objects(QPDFObjectHandle const& foreign, bool top = true); | |
| 59 | + private: | |
| 60 | + QPDFObjectHandle replace_indirect_object(QPDFObjectHandle const& foreign, bool top = false); | |
| 61 | + void reserve_objects(QPDFObjectHandle const& foreign, bool top = false); | |
| 61 | 62 | |
| 62 | 63 | QPDF& qpdf; |
| 63 | 64 | std::map<QPDFObjGen, QPDFObjectHandle> object_map; |
| ... | ... | @@ -65,11 +66,27 @@ class QPDF::ObjCopier |
| 65 | 66 | QPDFObjGen::set visiting; |
| 66 | 67 | }; |
| 67 | 68 | |
| 69 | + public: | |
| 68 | 70 | ObjCopier(QPDF& qpdf) : |
| 69 | 71 | qpdf(qpdf) |
| 70 | 72 | { |
| 71 | 73 | } |
| 72 | 74 | |
| 75 | + ObjCopier() = delete; | |
| 76 | + ObjCopier(ObjCopier const&) = delete; | |
| 77 | + ObjCopier(ObjCopier&&) = delete; | |
| 78 | + ObjCopier& operator=(ObjCopier const&) = delete; | |
| 79 | + ObjCopier& operator=(ObjCopier&&) = delete; | |
| 80 | + ~ObjCopier() = default; | |
| 81 | + | |
| 82 | + // Return a local handle to the foreign object. Copy the foreign object if necessary. | |
| 83 | + QPDFObjectHandle | |
| 84 | + copied(QPDFObjectHandle const& foreign) | |
| 85 | + { | |
| 86 | + return copier(foreign).copied(foreign); | |
| 87 | + } | |
| 88 | + | |
| 89 | + private: | |
| 73 | 90 | Copier& copier(QPDFObjectHandle const& foreign); |
| 74 | 91 | |
| 75 | 92 | QPDF& qpdf; | ... | ... |