Commit b20ff9680529692d5058b0f1fcd87c2b984b4195

Authored by m-holger
1 parent 91b8b0d8

Refactor `ObjCopier` and `copyForeignObject`: enhance encapsulation, streamline …

…`Copier` usage, and simplify object copying logic.
libqpdf/QPDF.cc
@@ -471,6 +471,12 @@ QPDF::getObjectByID(int objid, int generation) @@ -471,6 +471,12 @@ QPDF::getObjectByID(int objid, int generation)
471 return getObject(QPDFObjGen(objid, generation)); 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 QPDF::ObjCopier::Copier& 480 QPDF::ObjCopier::Copier&
475 QPDF::ObjCopier::copier(QPDFObjectHandle const& foreign) 481 QPDF::ObjCopier::copier(QPDFObjectHandle const& foreign)
476 { 482 {
@@ -485,7 +491,7 @@ QPDF::ObjCopier::copier(QPDFObjectHandle const& foreign) @@ -485,7 +491,7 @@ QPDF::ObjCopier::copier(QPDFObjectHandle const& foreign)
485 } 491 }
486 492
487 QPDFObjectHandle 493 QPDFObjectHandle
488 -QPDF::copyForeignObject(QPDFObjectHandle foreign) 494 +QPDF::ObjCopier::Copier::copied(QPDFObjectHandle const& foreign)
489 { 495 {
490 // Here's an explanation of what's going on here. 496 // Here's an explanation of what's going on here.
491 // 497 //
@@ -522,42 +528,36 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign) @@ -522,42 +528,36 @@ QPDF::copyForeignObject(QPDFObjectHandle foreign)
522 // Note that we explicitly allow use of copyForeignObject on page objects. It is a documented 528 // Note that we explicitly allow use of copyForeignObject on page objects. It is a documented
523 // use case to copy pages this way if the intention is to not update the pages tree. 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 // Make sure we have an object in this file for every referenced object in the old file. 534 // Make sure we have an object in this file for every referenced object in the old file.
532 // obj_copier.object_map maps foreign QPDFObjGen to local objects. For everything new that we 535 // obj_copier.object_map maps foreign QPDFObjGen to local objects. For everything new that we
533 // have to copy, the local object will be a reservation, unless it is a stream, in which case 536 // have to copy, the local object will be a reservation, unless it is a stream, in which case
534 // the local object will already be a stream. 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 // Copy any new objects and replace the reservations. 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 auto og = foreign.getObjGen(); 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 foreign.qpdf()->getFilename() + " object " + og.unparse(' '), 554 foreign.qpdf()->getFilename() + " object " + og.unparse(' '),
555 foreign.offset(), 555 foreign.offset(),
556 "unexpected reference to /Pages object while copying foreign object; replacing with " 556 "unexpected reference to /Pages object while copying foreign object; replacing with "
557 "null")); 557 "null"));
558 return QPDFObjectHandle::newNull(); 558 return QPDFObjectHandle::newNull();
559 } 559 }
560 - return obj_copier.object_map[foreign.getObjGen()]; 560 + return object_map[foreign];
561 } 561 }
562 562
563 void 563 void
@@ -592,17 +592,17 @@ QPDF::ObjCopier::Copier::reserve_objects(QPDFObjectHandle const& foreign, bool t @@ -592,17 +592,17 @@ QPDF::ObjCopier::Copier::reserve_objects(QPDFObjectHandle const& foreign, bool t
592 } 592 }
593 593
594 if (foreign_tc == ::ot_array) { 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 } else if (foreign_tc == ::ot_dictionary) { 598 } else if (foreign_tc == ::ot_dictionary) {
599 for (auto const& item: Dictionary(foreign)) { 599 for (auto const& item: Dictionary(foreign)) {
600 if (!item.second.null()) { 600 if (!item.second.null()) {
601 - reserve_objects(item.second, false); 601 + reserve_objects(item.second);
602 } 602 }
603 } 603 }
604 } else if (foreign_tc == ::ot_stream) { 604 } else if (foreign_tc == ::ot_stream) {
605 - reserve_objects(foreign.getDict(), false); 605 + reserve_objects(foreign.getDict());
606 } 606 }
607 607
608 visiting.erase(foreign); 608 visiting.erase(foreign);
@@ -611,7 +611,7 @@ QPDF::ObjCopier::Copier::reserve_objects(QPDFObjectHandle const& foreign, bool t @@ -611,7 +611,7 @@ QPDF::ObjCopier::Copier::reserve_objects(QPDFObjectHandle const& foreign, bool t
611 QPDFObjectHandle 611 QPDFObjectHandle
612 QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign, bool top) 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 if (!top && foreign.indirect()) { 616 if (!top && foreign.indirect()) {
617 auto mapping = object_map.find(foreign.id_gen()); 617 auto mapping = object_map.find(foreign.id_gen());
@@ -628,7 +628,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign @@ -628,7 +628,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const& foreign
628 std::vector<QPDFObjectHandle> result; 628 std::vector<QPDFObjectHandle> result;
629 result.reserve(array.size()); 629 result.reserve(array.size());
630 for (auto const& item: array) { 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 return Array(std::move(result)); 633 return Array(std::move(result));
634 } 634 }
@@ -637,7 +637,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreign @@ -637,7 +637,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreign
637 auto result = Dictionary::empty(); 637 auto result = Dictionary::empty();
638 for (auto const& [key, value]: Dictionary(foreign)) { 638 for (auto const& [key, value]: Dictionary(foreign)) {
639 if (!value.null()) { 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 return result; 643 return result;
@@ -649,7 +649,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreign @@ -649,7 +649,7 @@ QPDF::ObjCopier::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreign
649 auto dict = result.getDict(); 649 auto dict = result.getDict();
650 for (auto const& [key, value]: stream.getDict()) { 650 for (auto const& [key, value]: stream.getDict()) {
651 if (!value.null()) { 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 qpdf.copyStreamData(result, foreign); 655 qpdf.copyStreamData(result, foreign);
libqpdf/qpdf/QPDF_private.hh
@@ -46,7 +46,6 @@ class QPDF::ObjCache @@ -46,7 +46,6 @@ class QPDF::ObjCache
46 46
47 class QPDF::ObjCopier 47 class QPDF::ObjCopier
48 { 48 {
49 - public:  
50 class Copier 49 class Copier
51 { 50 {
52 public: 51 public:
@@ -55,9 +54,11 @@ class QPDF::ObjCopier @@ -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 QPDF& qpdf; 63 QPDF& qpdf;
63 std::map<QPDFObjGen, QPDFObjectHandle> object_map; 64 std::map<QPDFObjGen, QPDFObjectHandle> object_map;
@@ -65,11 +66,27 @@ class QPDF::ObjCopier @@ -65,11 +66,27 @@ class QPDF::ObjCopier
65 QPDFObjGen::set visiting; 66 QPDFObjGen::set visiting;
66 }; 67 };
67 68
  69 + public:
68 ObjCopier(QPDF& qpdf) : 70 ObjCopier(QPDF& qpdf) :
69 qpdf(qpdf) 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 Copier& copier(QPDFObjectHandle const& foreign); 90 Copier& copier(QPDFObjectHandle const& foreign);
74 91
75 QPDF& qpdf; 92 QPDF& qpdf;