Commit 44bd9db194e87d71b4d7573a2f84c6894256427c

Authored by m-holger
1 parent c290a82f

Refactor: replace `BaseDictionary::replaceKey` method with `BaseHandle::replace`…

… for clarity and consistency across dictionary operations.
include/qpdf/ObjectHandle.hh
@@ -85,6 +85,7 @@ namespace qpdf @@ -85,6 +85,7 @@ namespace qpdf
85 85
86 bool contains(std::string const& key) const; 86 bool contains(std::string const& key) const;
87 size_t erase(std::string const& key); 87 size_t erase(std::string const& key);
  88 + bool replace(std::string const& key, QPDFObjectHandle value);
88 QPDFObjectHandle const& operator[](std::string const& key) const; 89 QPDFObjectHandle const& operator[](std::string const& key) const;
89 90
90 std::shared_ptr<QPDFObject> copy(bool shallow = false) const; 91 std::shared_ptr<QPDFObject> copy(bool shallow = false) const;
libqpdf/NNTree.cc
@@ -168,7 +168,7 @@ NNTreeIterator::resetLimits(Dictionary a_node, std::list&lt;PathElement&gt;::iterator @@ -168,7 +168,7 @@ NNTreeIterator::resetLimits(Dictionary a_node, std::list&lt;PathElement&gt;::iterator
168 } 168 }
169 } 169 }
170 if (a_node != path.begin()->node) { 170 if (a_node != path.begin()->node) {
171 - a_node.replaceKey("/Limits", Array({first, last})); 171 + a_node.replace("/Limits", Array({first, last}));
172 } 172 }
173 } 173 }
174 174
@@ -266,7 +266,7 @@ NNTreeIterator::split(Dictionary to_split, std::list&lt;PathElement&gt;::iterator pare @@ -266,7 +266,7 @@ NNTreeIterator::split(Dictionary to_split, std::list&lt;PathElement&gt;::iterator pare
266 new_kids.push_back(first_node); 266 new_kids.push_back(first_node);
267 to_split.erase("/Limits"); // already shouldn't be there for root 267 to_split.erase("/Limits"); // already shouldn't be there for root
268 to_split.erase(impl.itemsKey()); 268 to_split.erase(impl.itemsKey());
269 - to_split.replaceKey("/Kids", new_kids); 269 + to_split.replace("/Kids", new_kids);
270 if (is_leaf) { 270 if (is_leaf) {
271 node = first_node; 271 node = first_node;
272 } else { 272 } else {
@@ -446,7 +446,7 @@ NNTreeIterator::remove() @@ -446,7 +446,7 @@ NNTreeIterator::remove()
446 if (parent == path.end()) { 446 if (parent == path.end()) {
447 // We erased the very last item. Convert the root to an empty items array. 447 // We erased the very last item. Convert the root to an empty items array.
448 element->node.erase("/Kids"); 448 element->node.erase("/Kids");
449 - element->node.replaceKey(impl.itemsKey(), Array::empty()); 449 + element->node.replace(impl.itemsKey(), Array::empty());
450 path.clear(); 450 path.clear();
451 setItemNumber(impl.tree_root, -1); 451 setItemNumber(impl.tree_root, -1);
452 return; 452 return;
@@ -673,8 +673,8 @@ NNTreeImpl::repair() @@ -673,8 +673,8 @@ NNTreeImpl::repair()
673 for (auto const& [key, value]: items) { 673 for (auto const& [key, value]: items) {
674 repl.insert(key, value); 674 repl.insert(key, value);
675 } 675 }
676 - tree_root.replaceKey("/Kids", new_node["/Kids"]);  
677 - tree_root.replaceKey(itemsKey(), new_node[itemsKey()]); 676 + tree_root.replace("/Kids", new_node["/Kids"]);
  677 + tree_root.replace(itemsKey(), new_node[itemsKey()]);
678 } 678 }
679 679
680 NNTreeImpl::iterator 680 NNTreeImpl::iterator
libqpdf/QPDF.cc
@@ -572,7 +572,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig @@ -572,7 +572,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig
572 auto result = Dictionary::empty(); 572 auto result = Dictionary::empty();
573 for (auto const& [key, value]: Dictionary(foreign)) { 573 for (auto const& [key, value]: Dictionary(foreign)) {
574 if (!value.null()) { 574 if (!value.null()) {
575 - result.replaceKey(key, replace_indirect_object(value)); 575 + result.replace(key, replace_indirect_object(value));
576 } 576 }
577 } 577 }
578 return result; 578 return result;
@@ -584,7 +584,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig @@ -584,7 +584,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig
584 auto dict = result.getDict(); 584 auto dict = result.getDict();
585 for (auto const& [key, value]: stream.getDict()) { 585 for (auto const& [key, value]: stream.getDict()) {
586 if (!value.null()) { 586 if (!value.null()) {
587 - dict.replaceKey(key, replace_indirect_object(value)); 587 + dict.replace(key, replace_indirect_object(value));
588 } 588 }
589 } 589 }
590 stream.copy_data_to(result); 590 stream.copy_data_to(result);
@@ -658,7 +658,7 @@ QPDF::getRoot() @@ -658,7 +658,7 @@ QPDF::getRoot()
658 // approach to more extensive checks and warning levels. 658 // approach to more extensive checks and warning levels.
659 if (m->cf.check_mode() && Name(Root["/Type"]) != "/Catalog") { 659 if (m->cf.check_mode() && Name(Root["/Type"]) != "/Catalog") {
660 warn(m->c.damagedPDF("", -1, "catalog /Type entry missing or invalid")); 660 warn(m->c.damagedPDF("", -1, "catalog /Type entry missing or invalid"));
661 - Root.replaceKey("/Type", Name("/Catalog")); 661 + Root.replace("/Type", Name("/Catalog"));
662 } 662 }
663 return Root.oh(); 663 return Root.oh();
664 } 664 }
libqpdf/QPDFAcroFormDocumentHelper.cc
@@ -799,7 +799,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -799,7 +799,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
799 } 799 }
800 QPDFObjectHandle(dr).makeResourcesIndirect(qpdf); 800 QPDFObjectHandle(dr).makeResourcesIndirect(qpdf);
801 if (!dr.indirect()) { 801 if (!dr.indirect()) {
802 - acroform.replaceKey("/DR", qpdf.makeIndirectObject(dr)); 802 + acroform.replace("/DR", qpdf.makeIndirectObject(dr));
803 dr = acroform["/DR"]; 803 dr = acroform["/DR"];
804 } 804 }
805 // Merge the other document's /DR, creating a conflict map. mergeResources checks to 805 // Merge the other document's /DR, creating a conflict map. mergeResources checks to
@@ -839,7 +839,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -839,7 +839,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
839 if (parent.indirect()) { 839 if (parent.indirect()) {
840 auto parent_og = parent.id_gen(); 840 auto parent_og = parent.id_gen();
841 if (orig_to_copy.contains(parent_og)) { 841 if (orig_to_copy.contains(parent_og)) {
842 - obj.replaceKey("/Parent", orig_to_copy[parent_og]); 842 + obj.replace("/Parent", orig_to_copy[parent_og]);
843 } else { 843 } else {
844 parent.warn( 844 parent.warn(
845 "while traversing field " + obj.id_gen().unparse(',') + 845 "while traversing field " + obj.id_gen().unparse(',') +
@@ -869,7 +869,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -869,7 +869,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
869 // chrome, firefox, the mac Preview application, and several of the free 869 // chrome, firefox, the mac Preview application, and several of the free
870 // readers on Linux all ignore /DR at the field level. 870 // readers on Linux all ignore /DR at the field level.
871 if (obj.contains("/DR")) { 871 if (obj.contains("/DR")) {
872 - obj.replaceKey("/DR", dr); 872 + obj.replace("/DR", dr);
873 } 873 }
874 if (obj["/DA"].isString() && !dr_map.empty()) { 874 if (obj["/DA"].isString() && !dr_map.empty()) {
875 adjustDefaultAppearances(obj, dr_map); 875 adjustDefaultAppearances(obj, dr_map);
@@ -988,7 +988,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -988,7 +988,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
988 Dictionary apdict = ah.getAppearanceDictionary(); 988 Dictionary apdict = ah.getAppearanceDictionary();
989 std::vector<QPDFObjectHandle> streams; 989 std::vector<QPDFObjectHandle> streams;
990 auto replace_stream = [](auto& dict, auto& key, auto& old) { 990 auto replace_stream = [](auto& dict, auto& key, auto& old) {
991 - dict.replaceKey(key, old.copyStream()); 991 + dict.replace(key, old.copyStream());
992 return dict[key]; 992 return dict[key];
993 }; 993 };
994 994
@@ -1015,7 +1015,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -1015,7 +1015,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
1015 } 1015 }
1016 apcm.concat(cm); 1016 apcm.concat(cm);
1017 if (omatrix || apcm != QPDFMatrix()) { 1017 if (omatrix || apcm != QPDFMatrix()) {
1018 - dict.replaceKey("/Matrix", QPDFObjectHandle::newFromMatrix(apcm)); 1018 + dict.replace("/Matrix", QPDFObjectHandle::newFromMatrix(apcm));
1019 } 1019 }
1020 Dictionary resources = dict["/Resources"]; 1020 Dictionary resources = dict["/Resources"];
1021 if (!dr_map.empty() && resources) { 1021 if (!dr_map.empty() && resources) {
libqpdf/QPDFEFStreamObjectHelper.cc
@@ -31,7 +31,7 @@ void @@ -31,7 +31,7 @@ void
31 QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval) 31 QPDFEFStreamObjectHelper::setParam(std::string const& pkey, QPDFObjectHandle const& pval)
32 { 32 {
33 if (Dictionary Params = oh().getDict()["/Params"]) { 33 if (Dictionary Params = oh().getDict()["/Params"]) {
34 - Params.replaceKey(pkey, pval); 34 + Params.replace(pkey, pval);
35 return; 35 return;
36 } 36 }
37 oh().getDict().replaceKey("/Params", Dictionary({{pkey, pval}})); 37 oh().getDict().replaceKey("/Params", Dictionary({{pkey, pval}}));
libqpdf/QPDFFormFieldObjectHelper.cc
@@ -956,7 +956,7 @@ FormField::generateTextAppearance(QPDFAnnotationObjectHelper&amp; aoh) @@ -956,7 +956,7 @@ FormField::generateTextAppearance(QPDFAnnotationObjectHelper&amp; aoh)
956 aoh.getObjectHandle().replaceKey("/AP", Dictionary::empty()); 956 aoh.getObjectHandle().replaceKey("/AP", Dictionary::empty());
957 AP = aoh.getAppearanceDictionary(); 957 AP = aoh.getAppearanceDictionary();
958 } 958 }
959 - AP.replaceKey("/N", AS); 959 + AP.replace("/N", AS);
960 } 960 }
961 if (!AS.isStream()) { 961 if (!AS.isStream()) {
962 aoh.warn("unable to get normal appearance stream for update"); 962 aoh.warn("unable to get normal appearance stream for update");
libqpdf/QPDF_Dictionary.cc
@@ -63,18 +63,29 @@ BaseHandle::erase(const std::string&amp; key) @@ -63,18 +63,29 @@ BaseHandle::erase(const std::string&amp; key)
63 return 0; 63 return 0;
64 } 64 }
65 65
  66 +bool
  67 +BaseHandle::replace(std::string const& key, QPDFObjectHandle value)
  68 +{
  69 + if (auto d = as<QPDF_Dictionary>()) {
  70 + if (value.null() && !value.indirect()) {
  71 + // The PDF spec doesn't distinguish between keys with null values and missing keys.
  72 + // Allow indirect nulls which are equivalent to a dangling reference, which is permitted
  73 + // by the spec.
  74 + d->items.erase(key);
  75 + } else {
  76 + // add or replace value
  77 + d->items[key] = value;
  78 + }
  79 + return true;
  80 + }
  81 + return false;
  82 +}
  83 +
66 void 84 void
67 -BaseDictionary::replaceKey(std::string const& key, QPDFObjectHandle value)  
68 -{  
69 - auto d = dict();  
70 - if (value.null() && !value.indirect()) {  
71 - // The PDF spec doesn't distinguish between keys with null values and missing keys.  
72 - // Allow indirect nulls which are equivalent to a dangling reference, which is  
73 - // permitted by the spec.  
74 - d->items.erase(key);  
75 - } else {  
76 - // add or replace value  
77 - d->items[key] = value; 85 +BaseDictionary::replace(std::string const& key, QPDFObjectHandle value)
  86 +{
  87 + if (!BaseHandle::replace(key, value)) {
  88 + (void)dict();
78 } 89 }
79 } 90 }
80 91
@@ -166,11 +177,10 @@ QPDFObjectHandle::replaceKey(std::string const&amp; key, QPDFObjectHandle const&amp; val @@ -166,11 +177,10 @@ QPDFObjectHandle::replaceKey(std::string const&amp; key, QPDFObjectHandle const&amp; val
166 { 177 {
167 if (auto dict = as_dictionary(strict)) { 178 if (auto dict = as_dictionary(strict)) {
168 checkOwnership(value); 179 checkOwnership(value);
169 - dict.replaceKey(key, value); 180 + dict.replace(key, value);
170 return; 181 return;
171 } 182 }
172 typeWarning("dictionary", "ignoring key replacement request"); 183 typeWarning("dictionary", "ignoring key replacement request");
173 - QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");  
174 } 184 }
175 185
176 QPDFObjectHandle 186 QPDFObjectHandle
libqpdf/qpdf/QPDFObjectHandle_private.hh
@@ -127,7 +127,7 @@ namespace qpdf @@ -127,7 +127,7 @@ namespace qpdf
127 // The following methods are not part of the public API. 127 // The following methods are not part of the public API.
128 std::set<std::string> getKeys(); 128 std::set<std::string> getKeys();
129 std::map<std::string, QPDFObjectHandle> const& getAsMap() const; 129 std::map<std::string, QPDFObjectHandle> const& getAsMap() const;
130 - void replaceKey(std::string const& key, QPDFObjectHandle value); 130 + void replace(std::string const& key, QPDFObjectHandle value);
131 131
132 using iterator = std::map<std::string, QPDFObjectHandle>::iterator; 132 using iterator = std::map<std::string, QPDFObjectHandle>::iterator;
133 using const_iterator = std::map<std::string, QPDFObjectHandle>::const_iterator; 133 using const_iterator = std::map<std::string, QPDFObjectHandle>::const_iterator;
qpdf/qpdf.testcov
@@ -171,7 +171,6 @@ QPDFObjectHandle array ignoring erase item 0 @@ -171,7 +171,6 @@ QPDFObjectHandle array ignoring erase item 0
171 QPDFObjectHandle dictionary false for hasKey 0 171 QPDFObjectHandle dictionary false for hasKey 0
172 QPDFObjectHandle dictionary empty set for getKeys 0 172 QPDFObjectHandle dictionary empty set for getKeys 0
173 QPDFObjectHandle dictionary empty map for asMap 0 173 QPDFObjectHandle dictionary empty map for asMap 0
174 -QPDFObjectHandle dictionary ignoring replaceKey 0  
175 QPDFObjectHandle numeric non-numeric 0 174 QPDFObjectHandle numeric non-numeric 0
176 QPDFObjectHandle erase array bounds 0 175 QPDFObjectHandle erase array bounds 0
177 qpdf-c called qpdf_check_pdf 0 176 qpdf-c called qpdf_check_pdf 0