Commit 91ae14948fa1f3e3b6ec895e83756e51a4d70be0
1 parent
6d5e8702
Refactor: replace `getInheritableFieldValue` with templated `inheritable_value` …
…for flexibility and consistency across FormField methods. Adjust related method implementations accordingly.
Showing
2 changed files
with
60 additions
and
29 deletions
libqpdf/QPDFFormFieldObjectHelper.cc
| ... | ... | @@ -83,28 +83,25 @@ FormField::root_field(bool* is_different) |
| 83 | 83 | QPDFObjectHandle |
| 84 | 84 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) |
| 85 | 85 | { |
| 86 | - return m->getInheritableFieldValue(name); | |
| 86 | + return Null::if_null(m->inheritable_value<QPDFObjectHandle>(name)); | |
| 87 | 87 | } |
| 88 | 88 | |
| 89 | -QPDFObjectHandle | |
| 90 | -FormField::getInheritableFieldValue(std::string const& name) | |
| 89 | +QPDFObjectHandle const& | |
| 90 | +FormField::inherited(std::string const& name, bool acroform) const | |
| 91 | 91 | { |
| 92 | - QPDFObjectHandle node = oh(); | |
| 93 | - if (!node.isDictionary()) { | |
| 94 | - return QPDFObjectHandle::newNull(); | |
| 95 | - } | |
| 96 | - QPDFObjectHandle result(node.getKey(name)); | |
| 97 | - if (result.null()) { | |
| 98 | - QPDFObjGen::set seen; | |
| 99 | - while (seen.add(node) && node.hasKey("/Parent")) { | |
| 100 | - node = node.getKey("/Parent"); | |
| 101 | - result = node.getKey(name); | |
| 102 | - if (!result.null()) { | |
| 103 | - return result; | |
| 104 | - } | |
| 92 | + if (!obj) { | |
| 93 | + return null_oh; | |
| 94 | + } | |
| 95 | + auto node = *this; | |
| 96 | + QPDFObjGen::set seen; | |
| 97 | + size_t depth = 0; // Don't bother with loop detection until depth becomes suspicious | |
| 98 | + while (node.Parent() && (++depth < 10 || seen.add(node))) { | |
| 99 | + node = node.Parent(); | |
| 100 | + if (auto const& result = node[name]) { | |
| 101 | + return {result}; | |
| 105 | 102 | } |
| 106 | 103 | } |
| 107 | - return result; | |
| 104 | + return acroform ? from_AcroForm(name) : null_oh; | |
| 108 | 105 | } |
| 109 | 106 | |
| 110 | 107 | std::string |
| ... | ... | @@ -116,7 +113,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& n |
| 116 | 113 | std::string |
| 117 | 114 | FormField::getInheritableFieldValueAsString(std::string const& name) |
| 118 | 115 | { |
| 119 | - auto fv = getInheritableFieldValue(name); | |
| 116 | + auto fv = inheritable_value<QPDFObjectHandle>(name); | |
| 120 | 117 | if (fv.isString()) { |
| 121 | 118 | return fv.getUTF8Value(); |
| 122 | 119 | } |
| ... | ... | @@ -132,7 +129,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& nam |
| 132 | 129 | std::string |
| 133 | 130 | FormField::getInheritableFieldValueAsName(std::string const& name) |
| 134 | 131 | { |
| 135 | - if (Name fv = getInheritableFieldValue(name)) { | |
| 132 | + if (auto fv = inheritable_value<Name>(name)) { | |
| 136 | 133 | return fv; |
| 137 | 134 | } |
| 138 | 135 | return {}; |
| ... | ... | @@ -227,13 +224,13 @@ FormField::getMappingName() |
| 227 | 224 | QPDFObjectHandle |
| 228 | 225 | QPDFFormFieldObjectHelper::getValue() |
| 229 | 226 | { |
| 230 | - return m->getValue(); | |
| 227 | + return Null::if_null(m->getValue()); | |
| 231 | 228 | } |
| 232 | 229 | |
| 233 | 230 | QPDFObjectHandle |
| 234 | 231 | FormField::getValue() |
| 235 | 232 | { |
| 236 | - return getInheritableFieldValue("/V"); | |
| 233 | + return inheritable_value<QPDFObjectHandle>("/V"); | |
| 237 | 234 | } |
| 238 | 235 | |
| 239 | 236 | std::string |
| ... | ... | @@ -251,13 +248,13 @@ FormField::getValueAsString() |
| 251 | 248 | QPDFObjectHandle |
| 252 | 249 | QPDFFormFieldObjectHelper::getDefaultValue() |
| 253 | 250 | { |
| 254 | - return m->getDefaultValue(); | |
| 251 | + return Null::if_null(m->getDefaultValue()); | |
| 255 | 252 | } |
| 256 | 253 | |
| 257 | 254 | QPDFObjectHandle |
| 258 | 255 | FormField::getDefaultValue() |
| 259 | 256 | { |
| 260 | - return getInheritableFieldValue("/DV"); | |
| 257 | + return inheritable_value<QPDFObjectHandle>("/DV"); | |
| 261 | 258 | } |
| 262 | 259 | |
| 263 | 260 | std::string |
| ... | ... | @@ -293,7 +290,7 @@ QPDFFormFieldObjectHelper::getDefaultAppearance() |
| 293 | 290 | std::string |
| 294 | 291 | FormField::getDefaultAppearance() |
| 295 | 292 | { |
| 296 | - auto value = getInheritableFieldValue("/DA"); | |
| 293 | + auto value = inheritable_value<QPDFObjectHandle>("/DA"); | |
| 297 | 294 | bool looked_in_acroform = false; |
| 298 | 295 | if (!value.isString()) { |
| 299 | 296 | value = from_AcroForm("/DA"); |
| ... | ... | @@ -315,7 +312,7 @@ QPDFFormFieldObjectHelper::getQuadding() |
| 315 | 312 | int |
| 316 | 313 | FormField::getQuadding() |
| 317 | 314 | { |
| 318 | - QPDFObjectHandle fv = getInheritableFieldValue("/Q"); | |
| 315 | + auto fv = inheritable_value<QPDFObjectHandle>("/Q"); | |
| 319 | 316 | bool looked_in_acroform = false; |
| 320 | 317 | if (!fv.isInteger()) { |
| 321 | 318 | fv = from_AcroForm("/Q"); |
| ... | ... | @@ -337,7 +334,7 @@ QPDFFormFieldObjectHelper::getFlags() |
| 337 | 334 | int |
| 338 | 335 | FormField::getFlags() |
| 339 | 336 | { |
| 340 | - QPDFObjectHandle f = getInheritableFieldValue("/Ff"); | |
| 337 | + auto f = inheritable_value<QPDFObjectHandle>("/Ff"); | |
| 341 | 338 | return f.isInteger() ? f.getIntValueAsInt() : 0; |
| 342 | 339 | } |
| 343 | 340 | |
| ... | ... | @@ -426,7 +423,7 @@ FormField::getChoices() |
| 426 | 423 | return {}; |
| 427 | 424 | } |
| 428 | 425 | std::vector<std::string> result; |
| 429 | - for (auto const& item: getInheritableFieldValue("/Opt").as_array()) { | |
| 426 | + for (auto const& item: inheritable_value<Array>("/Opt")) { | |
| 430 | 427 | if (item.isString()) { |
| 431 | 428 | result.emplace_back(item.getUTF8Value()); |
| 432 | 429 | } else if (item.size() == 2) { | ... | ... |
libqpdf/qpdf/FormField.hh
| ... | ... | @@ -60,8 +60,42 @@ namespace qpdf::impl |
| 60 | 60 | /// @return The top-level field in the form field hierarchy. |
| 61 | 61 | FormField root_field(bool* is_different = nullptr); |
| 62 | 62 | |
| 63 | - // Get a field value, possibly inheriting the value from an ancestor node. | |
| 64 | - QPDFObjectHandle getInheritableFieldValue(std::string const& name); | |
| 63 | + /// @brief Retrieves the inherited value of the specified attribute. | |
| 64 | + /// | |
| 65 | + /// @param name The name of the attribute to retrieve. | |
| 66 | + /// @param acroform If true, checks the document's /AcroForm dictionary for the attribute | |
| 67 | + /// if it is not found in the field hierarchy. | |
| 68 | + /// | |
| 69 | + /// @return A constant reference to the QPDFObjectHandle representing the value of the | |
| 70 | + /// specified attribute, if found. If the attribute is not found in the field | |
| 71 | + /// hierarchy or the /AcroForm dictionary (when `acroform` is true), returns a | |
| 72 | + /// reference to a static null object handle. | |
| 73 | + QPDFObjectHandle const& inherited(std::string const& name, bool acroform = false) const; | |
| 74 | + | |
| 75 | + /// @brief Retrieves the value of a specified field, accounting for inheritance through the | |
| 76 | + /// hierarchy of ancestor nodes in the form field tree. | |
| 77 | + /// | |
| 78 | + /// This function attempts to retrieve the value of the specified field. If the `inherit` | |
| 79 | + /// parameter is set to `true` and the field value is not found at the current level, the | |
| 80 | + /// method traverses up the parent hierarchy to find the value. The traversal stops when a | |
| 81 | + /// value is found, when the root node is reached, or when a loop detection mechanism | |
| 82 | + /// prevents further traversal. | |
| 83 | + /// | |
| 84 | + /// @tparam T The return type of the field value. | |
| 85 | + /// @param name The name of the field to retrieve the value for. | |
| 86 | + /// @param inherit If set to `true`, the function will attempt to retrieve the value by | |
| 87 | + /// inheritance from the parent hierarchy of the form field. Defaults to `true`. | |
| 88 | + /// @return Returns the field's value if found; otherwise, returns a default-constructed | |
| 89 | + /// value of type `T`. | |
| 90 | + template <class T> | |
| 91 | + T | |
| 92 | + inheritable_value(std::string const& name, bool inherit = true, bool acroform = false) const | |
| 93 | + { | |
| 94 | + if (auto& v = get(name)) { | |
| 95 | + return {v}; | |
| 96 | + } | |
| 97 | + return {inherit ? inherited(name, acroform) : null_oh}; | |
| 98 | + } | |
| 65 | 99 | |
| 66 | 100 | // Get an inherited field value as a string. If it is not a string, silently return the |
| 67 | 101 | // empty string. | ... | ... |