Commit 91ae14948fa1f3e3b6ec895e83756e51a4d70be0

Authored by m-holger
1 parent 6d5e8702

Refactor: replace `getInheritableFieldValue` with templated `inheritable_value` …

…for flexibility and consistency across FormField methods. Adjust related method implementations accordingly.
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&amp; 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&amp; 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.
... ...