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,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&amp; n @@ -116,7 +113,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const&amp; 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&amp; nam @@ -132,7 +129,7 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const&amp; 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.