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,28 +83,25 @@ FormField::root_field(bool* is_different) | ||
| 83 | QPDFObjectHandle | 83 | QPDFObjectHandle |
| 84 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) | 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 | std::string | 107 | std::string |
| @@ -116,7 +113,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& n | @@ -116,7 +113,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& n | ||
| 116 | std::string | 113 | std::string |
| 117 | FormField::getInheritableFieldValueAsString(std::string const& name) | 114 | FormField::getInheritableFieldValueAsString(std::string const& name) |
| 118 | { | 115 | { |
| 119 | - auto fv = getInheritableFieldValue(name); | 116 | + auto fv = inheritable_value<QPDFObjectHandle>(name); |
| 120 | if (fv.isString()) { | 117 | if (fv.isString()) { |
| 121 | return fv.getUTF8Value(); | 118 | return fv.getUTF8Value(); |
| 122 | } | 119 | } |
| @@ -132,7 +129,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& nam | @@ -132,7 +129,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& nam | ||
| 132 | std::string | 129 | std::string |
| 133 | FormField::getInheritableFieldValueAsName(std::string const& name) | 130 | FormField::getInheritableFieldValueAsName(std::string const& name) |
| 134 | { | 131 | { |
| 135 | - if (Name fv = getInheritableFieldValue(name)) { | 132 | + if (auto fv = inheritable_value<Name>(name)) { |
| 136 | return fv; | 133 | return fv; |
| 137 | } | 134 | } |
| 138 | return {}; | 135 | return {}; |
| @@ -227,13 +224,13 @@ FormField::getMappingName() | @@ -227,13 +224,13 @@ FormField::getMappingName() | ||
| 227 | QPDFObjectHandle | 224 | QPDFObjectHandle |
| 228 | QPDFFormFieldObjectHelper::getValue() | 225 | QPDFFormFieldObjectHelper::getValue() |
| 229 | { | 226 | { |
| 230 | - return m->getValue(); | 227 | + return Null::if_null(m->getValue()); |
| 231 | } | 228 | } |
| 232 | 229 | ||
| 233 | QPDFObjectHandle | 230 | QPDFObjectHandle |
| 234 | FormField::getValue() | 231 | FormField::getValue() |
| 235 | { | 232 | { |
| 236 | - return getInheritableFieldValue("/V"); | 233 | + return inheritable_value<QPDFObjectHandle>("/V"); |
| 237 | } | 234 | } |
| 238 | 235 | ||
| 239 | std::string | 236 | std::string |
| @@ -251,13 +248,13 @@ FormField::getValueAsString() | @@ -251,13 +248,13 @@ FormField::getValueAsString() | ||
| 251 | QPDFObjectHandle | 248 | QPDFObjectHandle |
| 252 | QPDFFormFieldObjectHelper::getDefaultValue() | 249 | QPDFFormFieldObjectHelper::getDefaultValue() |
| 253 | { | 250 | { |
| 254 | - return m->getDefaultValue(); | 251 | + return Null::if_null(m->getDefaultValue()); |
| 255 | } | 252 | } |
| 256 | 253 | ||
| 257 | QPDFObjectHandle | 254 | QPDFObjectHandle |
| 258 | FormField::getDefaultValue() | 255 | FormField::getDefaultValue() |
| 259 | { | 256 | { |
| 260 | - return getInheritableFieldValue("/DV"); | 257 | + return inheritable_value<QPDFObjectHandle>("/DV"); |
| 261 | } | 258 | } |
| 262 | 259 | ||
| 263 | std::string | 260 | std::string |
| @@ -293,7 +290,7 @@ QPDFFormFieldObjectHelper::getDefaultAppearance() | @@ -293,7 +290,7 @@ QPDFFormFieldObjectHelper::getDefaultAppearance() | ||
| 293 | std::string | 290 | std::string |
| 294 | FormField::getDefaultAppearance() | 291 | FormField::getDefaultAppearance() |
| 295 | { | 292 | { |
| 296 | - auto value = getInheritableFieldValue("/DA"); | 293 | + auto value = inheritable_value<QPDFObjectHandle>("/DA"); |
| 297 | bool looked_in_acroform = false; | 294 | bool looked_in_acroform = false; |
| 298 | if (!value.isString()) { | 295 | if (!value.isString()) { |
| 299 | value = from_AcroForm("/DA"); | 296 | value = from_AcroForm("/DA"); |
| @@ -315,7 +312,7 @@ QPDFFormFieldObjectHelper::getQuadding() | @@ -315,7 +312,7 @@ QPDFFormFieldObjectHelper::getQuadding() | ||
| 315 | int | 312 | int |
| 316 | FormField::getQuadding() | 313 | FormField::getQuadding() |
| 317 | { | 314 | { |
| 318 | - QPDFObjectHandle fv = getInheritableFieldValue("/Q"); | 315 | + auto fv = inheritable_value<QPDFObjectHandle>("/Q"); |
| 319 | bool looked_in_acroform = false; | 316 | bool looked_in_acroform = false; |
| 320 | if (!fv.isInteger()) { | 317 | if (!fv.isInteger()) { |
| 321 | fv = from_AcroForm("/Q"); | 318 | fv = from_AcroForm("/Q"); |
| @@ -337,7 +334,7 @@ QPDFFormFieldObjectHelper::getFlags() | @@ -337,7 +334,7 @@ QPDFFormFieldObjectHelper::getFlags() | ||
| 337 | int | 334 | int |
| 338 | FormField::getFlags() | 335 | FormField::getFlags() |
| 339 | { | 336 | { |
| 340 | - QPDFObjectHandle f = getInheritableFieldValue("/Ff"); | 337 | + auto f = inheritable_value<QPDFObjectHandle>("/Ff"); |
| 341 | return f.isInteger() ? f.getIntValueAsInt() : 0; | 338 | return f.isInteger() ? f.getIntValueAsInt() : 0; |
| 342 | } | 339 | } |
| 343 | 340 | ||
| @@ -426,7 +423,7 @@ FormField::getChoices() | @@ -426,7 +423,7 @@ FormField::getChoices() | ||
| 426 | return {}; | 423 | return {}; |
| 427 | } | 424 | } |
| 428 | std::vector<std::string> result; | 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 | if (item.isString()) { | 427 | if (item.isString()) { |
| 431 | result.emplace_back(item.getUTF8Value()); | 428 | result.emplace_back(item.getUTF8Value()); |
| 432 | } else if (item.size() == 2) { | 429 | } else if (item.size() == 2) { |
libqpdf/qpdf/FormField.hh
| @@ -60,8 +60,42 @@ namespace qpdf::impl | @@ -60,8 +60,42 @@ namespace qpdf::impl | ||
| 60 | /// @return The top-level field in the form field hierarchy. | 60 | /// @return The top-level field in the form field hierarchy. |
| 61 | FormField root_field(bool* is_different = nullptr); | 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 | // Get an inherited field value as a string. If it is not a string, silently return the | 100 | // Get an inherited field value as a string. If it is not a string, silently return the |
| 67 | // empty string. | 101 | // empty string. |