Commit 44bd9db194e87d71b4d7573a2f84c6894256427c
1 parent
c290a82f
Refactor: replace `BaseDictionary::replaceKey` method with `BaseHandle::replace`…
… for clarity and consistency across dictionary operations.
Showing
9 changed files
with
40 additions
and
30 deletions
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<PathElement>::iterator | @@ -168,7 +168,7 @@ NNTreeIterator::resetLimits(Dictionary a_node, std::list<PathElement>::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<PathElement>::iterator pare | @@ -266,7 +266,7 @@ NNTreeIterator::split(Dictionary to_split, std::list<PathElement>::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& foreig | @@ -572,7 +572,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const& 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& foreig | @@ -584,7 +584,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const& 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& aoh) | @@ -956,7 +956,7 @@ FormField::generateTextAppearance(QPDFAnnotationObjectHelper& 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& key) | @@ -63,18 +63,29 @@ BaseHandle::erase(const std::string& 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& key, QPDFObjectHandle const& val | @@ -166,11 +177,10 @@ QPDFObjectHandle::replaceKey(std::string const& key, QPDFObjectHandle const& 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 |