Commit 3b6b32130627e337ba58e4b6dbfde21aebbac2fc
Committed by
GitHub
Merge pull request #1586 from m-holger/ffoh
Refactor QPDFFormFieldObjectHelper
Showing
5 changed files
with
368 additions
and
191 deletions
libqpdf/QPDFFormFieldObjectHelper.cc
| @@ -18,6 +18,8 @@ using namespace qpdf; | @@ -18,6 +18,8 @@ using namespace qpdf; | ||
| 18 | 18 | ||
| 19 | using FormField = qpdf::impl::FormField; | 19 | using FormField = qpdf::impl::FormField; |
| 20 | 20 | ||
| 21 | +const QPDFObjectHandle FormField::null_oh; | ||
| 22 | + | ||
| 21 | class QPDFFormFieldObjectHelper::Members: public FormField | 23 | class QPDFFormFieldObjectHelper::Members: public FormField |
| 22 | { | 24 | { |
| 23 | public: | 25 | public: |
| @@ -48,93 +50,71 @@ QPDFFormFieldObjectHelper::isNull() | @@ -48,93 +50,71 @@ QPDFFormFieldObjectHelper::isNull() | ||
| 48 | QPDFFormFieldObjectHelper | 50 | QPDFFormFieldObjectHelper |
| 49 | QPDFFormFieldObjectHelper::getParent() | 51 | QPDFFormFieldObjectHelper::getParent() |
| 50 | { | 52 | { |
| 51 | - return {Null::if_null(m->getParent().oh())}; | ||
| 52 | -} | ||
| 53 | - | ||
| 54 | -FormField | ||
| 55 | -FormField::getParent() | ||
| 56 | -{ | ||
| 57 | - return {oh()["/Parent"]}; // maybe null | 53 | + return {Null::if_null(m->Parent().oh())}; |
| 58 | } | 54 | } |
| 59 | 55 | ||
| 60 | QPDFFormFieldObjectHelper | 56 | QPDFFormFieldObjectHelper |
| 61 | QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different) | 57 | QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different) |
| 62 | { | 58 | { |
| 63 | - return Null::if_null(m->getTopLevelField(is_different).oh()); | 59 | + return Null::if_null(m->root_field(is_different).oh()); |
| 64 | } | 60 | } |
| 65 | 61 | ||
| 66 | FormField | 62 | FormField |
| 67 | -FormField::getTopLevelField(bool* is_different) | 63 | +FormField::root_field(bool* is_different) |
| 68 | { | 64 | { |
| 65 | + if (is_different) { | ||
| 66 | + *is_different = false; | ||
| 67 | + } | ||
| 69 | if (!obj) { | 68 | if (!obj) { |
| 70 | return {}; | 69 | return {}; |
| 71 | } | 70 | } |
| 72 | - auto top_field = oh(); | 71 | + auto rf = *this; |
| 72 | + size_t depth = 0; // Don't bother with loop detection until depth becomes suspicious | ||
| 73 | QPDFObjGen::set seen; | 73 | QPDFObjGen::set seen; |
| 74 | - while (seen.add(top_field) && !top_field.getKeyIfDict("/Parent").null()) { | ||
| 75 | - top_field = top_field.getKey("/Parent"); | 74 | + while (rf.Parent() && (++depth < 10 || seen.add(rf))) { |
| 75 | + rf = rf.Parent(); | ||
| 76 | if (is_different) { | 76 | if (is_different) { |
| 77 | *is_different = true; | 77 | *is_different = true; |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | - return {top_field}; | ||
| 81 | -} | ||
| 82 | - | ||
| 83 | -QPDFObjectHandle | ||
| 84 | -FormField::getFieldFromAcroForm(std::string const& name) | ||
| 85 | -{ | ||
| 86 | - QPDFObjectHandle result = QPDFObjectHandle::newNull(); | ||
| 87 | - // Fields are supposed to be indirect, so this should work. | ||
| 88 | - QPDF* q = oh().getOwningQPDF(); | ||
| 89 | - if (!q) { | ||
| 90 | - return result; | ||
| 91 | - } | ||
| 92 | - auto acroform = q->getRoot().getKey("/AcroForm"); | ||
| 93 | - if (!acroform.isDictionary()) { | ||
| 94 | - return result; | ||
| 95 | - } | ||
| 96 | - return acroform.getKey(name); | 80 | + return rf; |
| 97 | } | 81 | } |
| 98 | 82 | ||
| 99 | QPDFObjectHandle | 83 | QPDFObjectHandle |
| 100 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) | 84 | QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name) |
| 101 | { | 85 | { |
| 102 | - return m->getInheritableFieldValue(name); | 86 | + return Null::if_null(m->inheritable_value<QPDFObjectHandle>(name)); |
| 103 | } | 87 | } |
| 104 | 88 | ||
| 105 | -QPDFObjectHandle | ||
| 106 | -FormField::getInheritableFieldValue(std::string const& name) | 89 | +QPDFObjectHandle const& |
| 90 | +FormField::inherited(std::string const& name, bool acroform) const | ||
| 107 | { | 91 | { |
| 108 | - QPDFObjectHandle node = oh(); | ||
| 109 | - if (!node.isDictionary()) { | ||
| 110 | - return QPDFObjectHandle::newNull(); | 92 | + if (!obj) { |
| 93 | + return null_oh; | ||
| 111 | } | 94 | } |
| 112 | - QPDFObjectHandle result(node.getKey(name)); | ||
| 113 | - if (result.null()) { | ||
| 114 | - QPDFObjGen::set seen; | ||
| 115 | - while (seen.add(node) && node.hasKey("/Parent")) { | ||
| 116 | - node = node.getKey("/Parent"); | ||
| 117 | - result = node.getKey(name); | ||
| 118 | - if (!result.null()) { | ||
| 119 | - return result; | ||
| 120 | - } | 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}; | ||
| 121 | } | 102 | } |
| 122 | } | 103 | } |
| 123 | - return result; | 104 | + return acroform ? from_AcroForm(name) : null_oh; |
| 124 | } | 105 | } |
| 125 | 106 | ||
| 126 | std::string | 107 | std::string |
| 127 | QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& name) | 108 | QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& name) |
| 128 | { | 109 | { |
| 129 | - return m->getInheritableFieldValueAsString(name); | 110 | + return m->inheritable_string(name); |
| 130 | } | 111 | } |
| 131 | 112 | ||
| 132 | std::string | 113 | std::string |
| 133 | -FormField::getInheritableFieldValueAsString(std::string const& name) | 114 | +FormField::inheritable_string(std::string const& name) const |
| 134 | { | 115 | { |
| 135 | - auto fv = getInheritableFieldValue(name); | ||
| 136 | - if (fv.isString()) { | ||
| 137 | - return fv.getUTF8Value(); | 116 | + if (auto fv = inheritable_value<String>(name)) { |
| 117 | + return fv.utf8_value(); | ||
| 138 | } | 118 | } |
| 139 | return {}; | 119 | return {}; |
| 140 | } | 120 | } |
| @@ -142,13 +122,7 @@ FormField::getInheritableFieldValueAsString(std::string const& name) | @@ -142,13 +122,7 @@ FormField::getInheritableFieldValueAsString(std::string const& name) | ||
| 142 | std::string | 122 | std::string |
| 143 | QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& name) | 123 | QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& name) |
| 144 | { | 124 | { |
| 145 | - return m->getInheritableFieldValueAsName(name); | ||
| 146 | -} | ||
| 147 | - | ||
| 148 | -std::string | ||
| 149 | -FormField::getInheritableFieldValueAsName(std::string const& name) | ||
| 150 | -{ | ||
| 151 | - if (Name fv = getInheritableFieldValue(name)) { | 125 | + if (auto fv = m->inheritable_value<Name>(name)) { |
| 152 | return fv; | 126 | return fv; |
| 153 | } | 127 | } |
| 154 | return {}; | 128 | return {}; |
| @@ -157,35 +131,33 @@ FormField::getInheritableFieldValueAsName(std::string const& name) | @@ -157,35 +131,33 @@ FormField::getInheritableFieldValueAsName(std::string const& name) | ||
| 157 | std::string | 131 | std::string |
| 158 | QPDFFormFieldObjectHelper::getFieldType() | 132 | QPDFFormFieldObjectHelper::getFieldType() |
| 159 | { | 133 | { |
| 160 | - return m->getFieldType(); | ||
| 161 | -} | ||
| 162 | - | ||
| 163 | -std::string | ||
| 164 | -FormField::getFieldType() | ||
| 165 | -{ | ||
| 166 | - return getInheritableFieldValueAsName("/FT"); | 134 | + if (auto ft = m->FT()) { |
| 135 | + return ft; | ||
| 136 | + } | ||
| 137 | + return {}; | ||
| 167 | } | 138 | } |
| 168 | 139 | ||
| 169 | std::string | 140 | std::string |
| 170 | QPDFFormFieldObjectHelper::getFullyQualifiedName() | 141 | QPDFFormFieldObjectHelper::getFullyQualifiedName() |
| 171 | { | 142 | { |
| 172 | - return m->getFullyQualifiedName(); | 143 | + return m->fully_qualified_name(); |
| 173 | } | 144 | } |
| 174 | 145 | ||
| 175 | std::string | 146 | std::string |
| 176 | -FormField::getFullyQualifiedName() | 147 | +FormField::fully_qualified_name() const |
| 177 | { | 148 | { |
| 178 | std::string result; | 149 | std::string result; |
| 179 | - QPDFObjectHandle node = oh(); | 150 | + auto node = *this; |
| 180 | QPDFObjGen::set seen; | 151 | QPDFObjGen::set seen; |
| 181 | - while (!node.null() && seen.add(node)) { | ||
| 182 | - if (node.getKey("/T").isString()) { | 152 | + size_t depth = 0; // Don't bother with loop detection until depth becomes suspicious |
| 153 | + while (node && (++depth < 10 || seen.add(node))) { | ||
| 154 | + if (auto T = node.T()) { | ||
| 183 | if (!result.empty()) { | 155 | if (!result.empty()) { |
| 184 | - result = "." + result; | 156 | + result.insert(0, 1, '.'); |
| 185 | } | 157 | } |
| 186 | - result = node.getKey("/T").getUTF8Value() + result; | 158 | + result.insert(0, T.utf8_value()); |
| 187 | } | 159 | } |
| 188 | - node = node.getKey("/Parent"); | 160 | + node = node.Parent(); |
| 189 | } | 161 | } |
| 190 | return result; | 162 | return result; |
| 191 | } | 163 | } |
| @@ -193,131 +165,110 @@ FormField::getFullyQualifiedName() | @@ -193,131 +165,110 @@ FormField::getFullyQualifiedName() | ||
| 193 | std::string | 165 | std::string |
| 194 | QPDFFormFieldObjectHelper::getPartialName() | 166 | QPDFFormFieldObjectHelper::getPartialName() |
| 195 | { | 167 | { |
| 196 | - return m->getPartialName(); | 168 | + return m->partial_name(); |
| 197 | } | 169 | } |
| 198 | 170 | ||
| 199 | std::string | 171 | std::string |
| 200 | -FormField::getPartialName() | 172 | +FormField::partial_name() const |
| 201 | { | 173 | { |
| 202 | - std::string result; | ||
| 203 | - if (oh().getKey("/T").isString()) { | ||
| 204 | - result = oh().getKey("/T").getUTF8Value(); | 174 | + if (auto pn = T()) { |
| 175 | + return pn.utf8_value(); | ||
| 205 | } | 176 | } |
| 206 | - return result; | 177 | + return {}; |
| 207 | } | 178 | } |
| 208 | 179 | ||
| 209 | std::string | 180 | std::string |
| 210 | QPDFFormFieldObjectHelper::getAlternativeName() | 181 | QPDFFormFieldObjectHelper::getAlternativeName() |
| 211 | { | 182 | { |
| 212 | - return m->getAlternativeName(); | 183 | + return m->alternative_name(); |
| 213 | } | 184 | } |
| 214 | 185 | ||
| 215 | std::string | 186 | std::string |
| 216 | -FormField::getAlternativeName() | 187 | +FormField::alternative_name() const |
| 217 | { | 188 | { |
| 218 | - if (oh().getKey("/TU").isString()) { | ||
| 219 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU present"); | ||
| 220 | - return oh().getKey("/TU").getUTF8Value(); | 189 | + if (auto an = TU()) { |
| 190 | + return an.utf8_value(); | ||
| 221 | } | 191 | } |
| 222 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU absent"); | ||
| 223 | - return getFullyQualifiedName(); | 192 | + return fully_qualified_name(); |
| 224 | } | 193 | } |
| 225 | 194 | ||
| 226 | std::string | 195 | std::string |
| 227 | QPDFFormFieldObjectHelper::getMappingName() | 196 | QPDFFormFieldObjectHelper::getMappingName() |
| 228 | { | 197 | { |
| 229 | - return m->getMappingName(); | 198 | + return m->mapping_name(); |
| 230 | } | 199 | } |
| 231 | 200 | ||
| 232 | std::string | 201 | std::string |
| 233 | -FormField::getMappingName() | 202 | +FormField::mapping_name() const |
| 234 | { | 203 | { |
| 235 | - if (oh().getKey("/TM").isString()) { | ||
| 236 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM present"); | ||
| 237 | - return oh().getKey("/TM").getUTF8Value(); | 204 | + if (auto mn = TM()) { |
| 205 | + return mn.utf8_value(); | ||
| 238 | } | 206 | } |
| 239 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM absent"); | ||
| 240 | - return getAlternativeName(); | 207 | + return alternative_name(); |
| 241 | } | 208 | } |
| 242 | 209 | ||
| 243 | QPDFObjectHandle | 210 | QPDFObjectHandle |
| 244 | QPDFFormFieldObjectHelper::getValue() | 211 | QPDFFormFieldObjectHelper::getValue() |
| 245 | { | 212 | { |
| 246 | - return m->getValue(); | ||
| 247 | -} | ||
| 248 | - | ||
| 249 | -QPDFObjectHandle | ||
| 250 | -FormField::getValue() | ||
| 251 | -{ | ||
| 252 | - return getInheritableFieldValue("/V"); | 213 | + return Null::if_null(m->V<QPDFObjectHandle>()); |
| 253 | } | 214 | } |
| 254 | 215 | ||
| 255 | std::string | 216 | std::string |
| 256 | QPDFFormFieldObjectHelper::getValueAsString() | 217 | QPDFFormFieldObjectHelper::getValueAsString() |
| 257 | { | 218 | { |
| 258 | - return getInheritableFieldValueAsString("/V"); | 219 | + return m->value(); |
| 259 | } | 220 | } |
| 260 | 221 | ||
| 261 | std::string | 222 | std::string |
| 262 | -FormField::getValueAsString() | 223 | +FormField::value() const |
| 263 | { | 224 | { |
| 264 | - return getInheritableFieldValueAsString("/V"); | 225 | + return inheritable_string("/V"); |
| 265 | } | 226 | } |
| 266 | 227 | ||
| 267 | QPDFObjectHandle | 228 | QPDFObjectHandle |
| 268 | QPDFFormFieldObjectHelper::getDefaultValue() | 229 | QPDFFormFieldObjectHelper::getDefaultValue() |
| 269 | { | 230 | { |
| 270 | - return m->getDefaultValue(); | ||
| 271 | -} | ||
| 272 | - | ||
| 273 | -QPDFObjectHandle | ||
| 274 | -FormField::getDefaultValue() | ||
| 275 | -{ | ||
| 276 | - return getInheritableFieldValue("/DV"); | 231 | + return Null::if_null(m->DV()); |
| 277 | } | 232 | } |
| 278 | 233 | ||
| 279 | std::string | 234 | std::string |
| 280 | QPDFFormFieldObjectHelper::getDefaultValueAsString() | 235 | QPDFFormFieldObjectHelper::getDefaultValueAsString() |
| 281 | { | 236 | { |
| 282 | - return m->getDefaultValueAsString(); | 237 | + return m->default_value(); |
| 283 | } | 238 | } |
| 284 | 239 | ||
| 285 | std::string | 240 | std::string |
| 286 | -FormField::getDefaultValueAsString() | 241 | +FormField::default_value() const |
| 287 | { | 242 | { |
| 288 | - return getInheritableFieldValueAsString("/DV"); | 243 | + return inheritable_string("/DV"); |
| 289 | } | 244 | } |
| 290 | 245 | ||
| 291 | QPDFObjectHandle | 246 | QPDFObjectHandle |
| 292 | QPDFFormFieldObjectHelper::getDefaultResources() | 247 | QPDFFormFieldObjectHelper::getDefaultResources() |
| 293 | { | 248 | { |
| 294 | - return m->getDefaultResources(); | 249 | + return Null::if_null(m->getDefaultResources()); |
| 295 | } | 250 | } |
| 296 | 251 | ||
| 297 | QPDFObjectHandle | 252 | QPDFObjectHandle |
| 298 | FormField::getDefaultResources() | 253 | FormField::getDefaultResources() |
| 299 | { | 254 | { |
| 300 | - return getFieldFromAcroForm("/DR"); | 255 | + return from_AcroForm("/DR"); |
| 301 | } | 256 | } |
| 302 | 257 | ||
| 303 | std::string | 258 | std::string |
| 304 | QPDFFormFieldObjectHelper::getDefaultAppearance() | 259 | QPDFFormFieldObjectHelper::getDefaultAppearance() |
| 305 | { | 260 | { |
| 306 | - return m->getDefaultAppearance(); | 261 | + return m->default_appearance(); |
| 307 | } | 262 | } |
| 308 | 263 | ||
| 309 | std::string | 264 | std::string |
| 310 | -FormField::getDefaultAppearance() | 265 | +FormField::default_appearance() const |
| 311 | { | 266 | { |
| 312 | - auto value = getInheritableFieldValue("/DA"); | ||
| 313 | - bool looked_in_acroform = false; | ||
| 314 | - if (!value.isString()) { | ||
| 315 | - value = getFieldFromAcroForm("/DA"); | ||
| 316 | - looked_in_acroform = true; | 267 | + if (auto DA = inheritable_value<String>("/DA")) { |
| 268 | + return DA.utf8_value(); | ||
| 317 | } | 269 | } |
| 318 | - if (value.isString()) { | ||
| 319 | - QTC::TC("qpdf", "QPDFFormFieldObjectHelper DA present", looked_in_acroform ? 0 : 1); | ||
| 320 | - return value.getUTF8Value(); | 270 | + if (String DA = from_AcroForm("/DA")) { |
| 271 | + return DA.utf8_value(); | ||
| 321 | } | 272 | } |
| 322 | return {}; | 273 | return {}; |
| 323 | } | 274 | } |
| @@ -331,10 +282,10 @@ QPDFFormFieldObjectHelper::getQuadding() | @@ -331,10 +282,10 @@ QPDFFormFieldObjectHelper::getQuadding() | ||
| 331 | int | 282 | int |
| 332 | FormField::getQuadding() | 283 | FormField::getQuadding() |
| 333 | { | 284 | { |
| 334 | - QPDFObjectHandle fv = getInheritableFieldValue("/Q"); | 285 | + auto fv = inheritable_value<QPDFObjectHandle>("/Q"); |
| 335 | bool looked_in_acroform = false; | 286 | bool looked_in_acroform = false; |
| 336 | if (!fv.isInteger()) { | 287 | if (!fv.isInteger()) { |
| 337 | - fv = getFieldFromAcroForm("/Q"); | 288 | + fv = from_AcroForm("/Q"); |
| 338 | looked_in_acroform = true; | 289 | looked_in_acroform = true; |
| 339 | } | 290 | } |
| 340 | if (fv.isInteger()) { | 291 | if (fv.isInteger()) { |
| @@ -353,7 +304,7 @@ QPDFFormFieldObjectHelper::getFlags() | @@ -353,7 +304,7 @@ QPDFFormFieldObjectHelper::getFlags() | ||
| 353 | int | 304 | int |
| 354 | FormField::getFlags() | 305 | FormField::getFlags() |
| 355 | { | 306 | { |
| 356 | - QPDFObjectHandle f = getInheritableFieldValue("/Ff"); | 307 | + auto f = inheritable_value<QPDFObjectHandle>("/Ff"); |
| 357 | return f.isInteger() ? f.getIntValueAsInt() : 0; | 308 | return f.isInteger() ? f.getIntValueAsInt() : 0; |
| 358 | } | 309 | } |
| 359 | 310 | ||
| @@ -366,7 +317,7 @@ QPDFFormFieldObjectHelper::isText() | @@ -366,7 +317,7 @@ QPDFFormFieldObjectHelper::isText() | ||
| 366 | bool | 317 | bool |
| 367 | FormField::isText() | 318 | FormField::isText() |
| 368 | { | 319 | { |
| 369 | - return getFieldType() == "/Tx"; | 320 | + return FT() == "/Tx"; |
| 370 | } | 321 | } |
| 371 | 322 | ||
| 372 | bool | 323 | bool |
| @@ -378,7 +329,7 @@ QPDFFormFieldObjectHelper::isCheckbox() | @@ -378,7 +329,7 @@ QPDFFormFieldObjectHelper::isCheckbox() | ||
| 378 | bool | 329 | bool |
| 379 | FormField::isCheckbox() | 330 | FormField::isCheckbox() |
| 380 | { | 331 | { |
| 381 | - return getFieldType() == "/Btn" && (getFlags() & (ff_btn_radio | ff_btn_pushbutton)) == 0; | 332 | + return FT() == "/Btn" && (getFlags() & (ff_btn_radio | ff_btn_pushbutton)) == 0; |
| 382 | } | 333 | } |
| 383 | 334 | ||
| 384 | bool | 335 | bool |
| @@ -390,7 +341,7 @@ QPDFFormFieldObjectHelper::isChecked() | @@ -390,7 +341,7 @@ QPDFFormFieldObjectHelper::isChecked() | ||
| 390 | bool | 341 | bool |
| 391 | FormField::isChecked() | 342 | FormField::isChecked() |
| 392 | { | 343 | { |
| 393 | - return isCheckbox() && Name(getValue()) != "/Off"; | 344 | + return isCheckbox() && V<Name>() != "/Off"; |
| 394 | } | 345 | } |
| 395 | 346 | ||
| 396 | bool | 347 | bool |
| @@ -402,7 +353,7 @@ QPDFFormFieldObjectHelper::isRadioButton() | @@ -402,7 +353,7 @@ QPDFFormFieldObjectHelper::isRadioButton() | ||
| 402 | bool | 353 | bool |
| 403 | FormField::isRadioButton() | 354 | FormField::isRadioButton() |
| 404 | { | 355 | { |
| 405 | - return getFieldType() == "/Btn" && (getFlags() & ff_btn_radio) == ff_btn_radio; | 356 | + return FT() == "/Btn" && (getFlags() & ff_btn_radio) == ff_btn_radio; |
| 406 | } | 357 | } |
| 407 | 358 | ||
| 408 | bool | 359 | bool |
| @@ -414,7 +365,7 @@ QPDFFormFieldObjectHelper::isPushbutton() | @@ -414,7 +365,7 @@ QPDFFormFieldObjectHelper::isPushbutton() | ||
| 414 | bool | 365 | bool |
| 415 | FormField::isPushbutton() | 366 | FormField::isPushbutton() |
| 416 | { | 367 | { |
| 417 | - return getFieldType() == "/Btn" && (getFlags() & ff_btn_pushbutton) == ff_btn_pushbutton; | 368 | + return FT() == "/Btn" && (getFlags() & ff_btn_pushbutton) == ff_btn_pushbutton; |
| 418 | } | 369 | } |
| 419 | 370 | ||
| 420 | bool | 371 | bool |
| @@ -426,7 +377,7 @@ QPDFFormFieldObjectHelper::isChoice() | @@ -426,7 +377,7 @@ QPDFFormFieldObjectHelper::isChoice() | ||
| 426 | bool | 377 | bool |
| 427 | FormField::isChoice() | 378 | FormField::isChoice() |
| 428 | { | 379 | { |
| 429 | - return getFieldType() == "/Ch"; | 380 | + return FT() == "/Ch"; |
| 430 | } | 381 | } |
| 431 | 382 | ||
| 432 | std::vector<std::string> | 383 | std::vector<std::string> |
| @@ -442,7 +393,7 @@ FormField::getChoices() | @@ -442,7 +393,7 @@ FormField::getChoices() | ||
| 442 | return {}; | 393 | return {}; |
| 443 | } | 394 | } |
| 444 | std::vector<std::string> result; | 395 | std::vector<std::string> result; |
| 445 | - for (auto const& item: getInheritableFieldValue("/Opt").as_array()) { | 396 | + for (auto const& item: inheritable_value<Array>("/Opt")) { |
| 446 | if (item.isString()) { | 397 | if (item.isString()) { |
| 447 | result.emplace_back(item.getUTF8Value()); | 398 | result.emplace_back(item.getUTF8Value()); |
| 448 | } else if (item.size() == 2) { | 399 | } else if (item.size() == 2) { |
| @@ -489,7 +440,7 @@ void | @@ -489,7 +440,7 @@ void | ||
| 489 | FormField::setV(QPDFObjectHandle value, bool need_appearances) | 440 | FormField::setV(QPDFObjectHandle value, bool need_appearances) |
| 490 | { | 441 | { |
| 491 | Name name = value; | 442 | Name name = value; |
| 492 | - if (getFieldType() == "/Btn") { | 443 | + if (FT() == "/Btn") { |
| 493 | if (isCheckbox()) { | 444 | if (isCheckbox()) { |
| 494 | if (!name) { | 445 | if (!name) { |
| 495 | warn("ignoring attempt to set a checkbox field to a value whose type is not name"); | 446 | warn("ignoring attempt to set a checkbox field to a value whose type is not name"); |
| @@ -652,10 +603,9 @@ QPDFFormFieldObjectHelper::generateAppearance(QPDFAnnotationObjectHelper& aoh) | @@ -652,10 +603,9 @@ QPDFFormFieldObjectHelper::generateAppearance(QPDFAnnotationObjectHelper& aoh) | ||
| 652 | void | 603 | void |
| 653 | FormField::generateAppearance(QPDFAnnotationObjectHelper& aoh) | 604 | FormField::generateAppearance(QPDFAnnotationObjectHelper& aoh) |
| 654 | { | 605 | { |
| 655 | - std::string ft = getFieldType(); | ||
| 656 | // Ignore field types we don't know how to generate appearances for. Button fields don't really | 606 | // Ignore field types we don't know how to generate appearances for. Button fields don't really |
| 657 | // need them -- see code in QPDFAcroFormDocumentHelper::generateAppearancesIfNeeded. | 607 | // need them -- see code in QPDFAcroFormDocumentHelper::generateAppearancesIfNeeded. |
| 658 | - if ((ft == "/Tx") || (ft == "/Ch")) { | 608 | + if (FT() == "/Tx" || FT() == "/Ch") { |
| 659 | generateTextAppearance(aoh); | 609 | generateTextAppearance(aoh); |
| 660 | } | 610 | } |
| 661 | } | 611 | } |
| @@ -973,8 +923,8 @@ FormField::generateTextAppearance(QPDFAnnotationObjectHelper& aoh) | @@ -973,8 +923,8 @@ FormField::generateTextAppearance(QPDFAnnotationObjectHelper& aoh) | ||
| 973 | return; | 923 | return; |
| 974 | } | 924 | } |
| 975 | QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle(); | 925 | QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle(); |
| 976 | - std::string DA = getDefaultAppearance(); | ||
| 977 | - std::string V = getValueAsString(); | 926 | + std::string DA = default_appearance(); |
| 927 | + std::string V = value(); | ||
| 978 | std::vector<std::string> opt; | 928 | std::vector<std::string> opt; |
| 979 | if (isChoice() && (getFlags() & ff_ch_combo) == 0) { | 929 | if (isChoice() && (getFlags() & ff_ch_combo) == 0) { |
| 980 | opt = getChoices(); | 930 | opt = getChoices(); |
libqpdf/qpdf/FormField.hh
| @@ -32,57 +32,264 @@ namespace qpdf::impl | @@ -32,57 +32,264 @@ namespace qpdf::impl | ||
| 32 | { | 32 | { |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | - // Return the field's parent. A form field object helper whose underlying object is null is | ||
| 36 | - // returned if there is no parent. This condition may be tested by calling isNull(). | ||
| 37 | - FormField getParent(); | ||
| 38 | - | ||
| 39 | - // Return the top-level field for this field. Typically this will be the field itself or its | ||
| 40 | - // parent. If is_different is provided, it is set to true if the top-level field is | ||
| 41 | - // different from the field itself; otherwise it is set to false. | ||
| 42 | - FormField getTopLevelField(bool* is_different = nullptr); | ||
| 43 | - | ||
| 44 | - // Get a field value, possibly inheriting the value from an ancestor node. | ||
| 45 | - QPDFObjectHandle getInheritableFieldValue(std::string const& name); | ||
| 46 | - | ||
| 47 | - // Get an inherited field value as a string. If it is not a string, silently return the | ||
| 48 | - // empty string. | ||
| 49 | - std::string getInheritableFieldValueAsString(std::string const& name); | ||
| 50 | - | ||
| 51 | - // Get an inherited field value of type name as a string representing the name. If it is not | ||
| 52 | - // a name, silently return the empty string. | ||
| 53 | - std::string getInheritableFieldValueAsName(std::string const& name); | ||
| 54 | - | ||
| 55 | - // Returns the value of /FT if present, otherwise returns the empty string. | ||
| 56 | - std::string getFieldType(); | 35 | + /// Retrieves the /Parent form field of the current field. |
| 36 | + /// | ||
| 37 | + /// This function accesses the parent field in the hierarchical structure of form fields, if | ||
| 38 | + /// it exists. The parent is determined based on the /Parent attribute in the field | ||
| 39 | + /// dictionary. | ||
| 40 | + /// | ||
| 41 | + /// @return A FormField object representing the parent field. If the current field has no | ||
| 42 | + /// parent, an empty FormField object is returned. | ||
| 43 | + FormField | ||
| 44 | + Parent() | ||
| 45 | + { | ||
| 46 | + return {get("/Parent")}; | ||
| 47 | + } | ||
| 57 | 48 | ||
| 58 | - std::string getFullyQualifiedName(); | 49 | + /// @brief Returns the top-level field associated with the current field. |
| 50 | + /// | ||
| 51 | + /// The function traverses the hierarchy of parent fields to identify the highest-level | ||
| 52 | + /// field in the tree. Typically, this will be the current field itself unless it has a | ||
| 53 | + /// parent field. Optionally, it can indicate whether the top-level field is different from | ||
| 54 | + /// the current field. | ||
| 55 | + /// | ||
| 56 | + /// @param is_different A pointer to a boolean that, if provided, will be set to true if the | ||
| 57 | + /// top-level field differs from the current field; otherwise, it will be set to | ||
| 58 | + /// false. | ||
| 59 | + /// | ||
| 60 | + /// @return The top-level field in the form field hierarchy. | ||
| 61 | + FormField root_field(bool* is_different = nullptr); | ||
| 62 | + | ||
| 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 | + } | ||
| 59 | 99 | ||
| 60 | - std::string getPartialName(); | 100 | + /// @brief Retrieves an inherited field string attribute as a string. |
| 101 | + /// | ||
| 102 | + /// @param name The name of the field for which the value is to be retrieved. | ||
| 103 | + /// @return The inherited field value as a UTF-8 encoded string, or an empty string if the | ||
| 104 | + /// value does not exist or is not of String type. | ||
| 105 | + std::string inheritable_string(std::string const& name) const; | ||
| 106 | + | ||
| 107 | + /// @brief Retrieves the field type (/FT attribute). | ||
| 108 | + /// | ||
| 109 | + /// @param inherit If set to `true`, the function will attempt to retrieve the value by | ||
| 110 | + /// inheritance from the parent hierarchy of the form field. Defaults to `true`. | ||
| 111 | + /// @return Returns the field type if found; otherwise, returns a default-constructed | ||
| 112 | + /// `Name`. | ||
| 113 | + Name | ||
| 114 | + FT(bool inherit = true) const | ||
| 115 | + { | ||
| 116 | + return inheritable_value<Name>("/FT"); | ||
| 117 | + } | ||
| 61 | 118 | ||
| 62 | - // Return the alternative field name (/TU), which is the field name intended to be presented | ||
| 63 | - // to users. If not present, fall back to the fully qualified name. | ||
| 64 | - std::string getAlternativeName(); | 119 | + /// @brief Retrieves the partial field name (/T attribute). |
| 120 | + /// | ||
| 121 | + /// @return Returns the partial field name if found; otherwise, returns a | ||
| 122 | + /// default-constructed `String`. | ||
| 123 | + String | ||
| 124 | + T() const | ||
| 125 | + { | ||
| 126 | + return {get("/T")}; | ||
| 127 | + } | ||
| 65 | 128 | ||
| 66 | - // Return the mapping field name (/TM). If not present, fall back to the alternative name, | ||
| 67 | - // then to the partial name. | ||
| 68 | - std::string getMappingName(); | 129 | + /// @brief Retrieves the alternative name (/TU attribute). |
| 130 | + /// | ||
| 131 | + /// @return Returns the alternative name if found; otherwise, returns a default-constructed | ||
| 132 | + /// `String`. | ||
| 133 | + String | ||
| 134 | + TU() const | ||
| 135 | + { | ||
| 136 | + return {get("/TU")}; | ||
| 137 | + } | ||
| 69 | 138 | ||
| 70 | - QPDFObjectHandle getValue(); | 139 | + /// @brief Retrieves the mapping name (/TM attribute). |
| 140 | + /// | ||
| 141 | + /// @return Returns the mapping name if found; otherwise, returns a default-constructed | ||
| 142 | + /// `String`. | ||
| 143 | + String | ||
| 144 | + TM() const | ||
| 145 | + { | ||
| 146 | + return {get("/TM")}; | ||
| 147 | + } | ||
| 71 | 148 | ||
| 72 | - // Return the field's value as a string. If this is called with a field whose value is not a | ||
| 73 | - std::string getValueAsString(); | 149 | + /// @brief Retrieves the fully qualified name of the form field. |
| 150 | + /// | ||
| 151 | + /// This method constructs the fully qualified name of the form field by traversing through | ||
| 152 | + /// its parent hierarchy. The fully qualified name is constructed by concatenating the /T | ||
| 153 | + /// (field name) attribute of each parent node with periods as separators, starting from the | ||
| 154 | + /// root of the hierarchy. | ||
| 155 | + /// | ||
| 156 | + /// If the field has no parent hierarchy, the result will simply be the /T attribute of the | ||
| 157 | + /// current field. In cases of potential circular references, loop detection is applied. | ||
| 158 | + /// | ||
| 159 | + /// @return A string representing the fully qualified name of the field. | ||
| 160 | + std::string fully_qualified_name() const; | ||
| 161 | + | ||
| 162 | + /// @brief Retrieves the partial name (/T attribute) of the form field. | ||
| 163 | + /// | ||
| 164 | + /// This method returns the value of the field's /T attribute, which is the partial name | ||
| 165 | + /// used to identify the field within its parent hierarchy. If the attribute is not set, an | ||
| 166 | + /// empty string is returned. | ||
| 167 | + /// | ||
| 168 | + /// @return A string representing the partial name of the field in UTF-8 encoding, or an | ||
| 169 | + /// empty string if the /T attribute is not present. | ||
| 170 | + std::string partial_name() const; | ||
| 171 | + | ||
| 172 | + /// @brief Retrieves the alternative name for the form field. | ||
| 173 | + /// | ||
| 174 | + /// This method attempts to return the alternative name (/TU) of the form field, which is | ||
| 175 | + /// the field name intended to be presented, to users as a UTF-8 string, if it exists. If | ||
| 176 | + /// the alternative name is not present, the method falls back to the fully qualified name | ||
| 177 | + /// of the form field. | ||
| 178 | + /// | ||
| 179 | + /// @return The alternative name of the form field as a string, or the | ||
| 180 | + /// fully qualified name if the alternative name is unavailable. | ||
| 181 | + std::string alternative_name() const; | ||
| 182 | + | ||
| 183 | + /// @brief Retrieves the mapping field name (/TM) for the form field. | ||
| 184 | + /// | ||
| 185 | + /// If the mapping name (/TM) is present, it is returned as a UTF-8 string. If not, it falls | ||
| 186 | + /// back to the 'alternative name', which is obtained using the `alternative_name()` method. | ||
| 187 | + /// | ||
| 188 | + /// @return The mapping field name (/TM) as a UTF-8 string or the alternative name if the | ||
| 189 | + /// mapping name is absent. | ||
| 190 | + std::string mapping_name() const; | ||
| 191 | + | ||
| 192 | + /// @brief Retrieves the field value (`/V` attribute) of a specified field, accounting for | ||
| 193 | + /// inheritance through thehierarchy of ancestor nodes in the form field tree. | ||
| 194 | + /// | ||
| 195 | + /// This function attempts to retrieve the `/V` attribute. If the `inherit` | ||
| 196 | + /// parameter is set to `true` and the `/V` is not found at the current level, the | ||
| 197 | + /// method traverses up the parent hierarchy to find the value. The traversal stops when | ||
| 198 | + /// `/V` is found, when the root node is reached, or when a loop detection mechanism | ||
| 199 | + /// prevents further traversal. | ||
| 200 | + /// | ||
| 201 | + /// @tparam T The return type. | ||
| 202 | + /// @param inherit If set to `true`, the function will attempt to retrieve `/V` by | ||
| 203 | + /// inheritance from the parent hierarchy of the form field. Defaults to `true`. | ||
| 204 | + /// @return Returns the field's value if found; otherwise, returns a default-constructed | ||
| 205 | + /// value of type `T`. | ||
| 206 | + template <class T> | ||
| 207 | + T | ||
| 208 | + V(bool inherit = true) const | ||
| 209 | + { | ||
| 210 | + return inheritable_value<T>("/V", inherit); | ||
| 211 | + } | ||
| 74 | 212 | ||
| 75 | - QPDFObjectHandle getDefaultValue(); | 213 | + /// @brief Retrieves the field value (`/V` attribute) of a specified field, accounting for |
| 214 | + /// inheritance through the hierarchy of ancestor nodes in the form field tree. | ||
| 215 | + /// | ||
| 216 | + /// This function attempts to retrieve the `/V` attribute. If the `inherit` | ||
| 217 | + /// parameter is set to `true` and the `/V` is not found at the current level, the | ||
| 218 | + /// method traverses up the parent hierarchy to find the value. The traversal stops when | ||
| 219 | + /// `/V` is found, when the root node is reached, or when a loop detection mechanism | ||
| 220 | + /// prevents further traversal. | ||
| 221 | + /// | ||
| 222 | + /// @param inherit If set to `true`, the function will attempt to retrieve `/V` by | ||
| 223 | + /// inheritance from the parent hierarchy of the form field. Defaults to `true`. | ||
| 224 | + /// @return Returns the field's value if found; otherwise, returns a default-constructed | ||
| 225 | + /// object handle. | ||
| 226 | + QPDFObjectHandle const& | ||
| 227 | + V(bool inherit = true) const | ||
| 228 | + { | ||
| 229 | + if (auto& v = get("/V")) { | ||
| 230 | + return v; | ||
| 231 | + } | ||
| 232 | + return {inherit ? inherited("/V") : null_oh}; | ||
| 233 | + } | ||
| 76 | 234 | ||
| 77 | - // Return the field's default value as a string. If this is called with a field whose value | ||
| 78 | - // is not a string, the empty string will be silently returned. | ||
| 79 | - std::string getDefaultValueAsString(); | 235 | + /// @brief Retrieves the field value `/V` attribute of the form field, considering |
| 236 | + /// inheritance, if the value is a String. | ||
| 237 | + /// | ||
| 238 | + /// This function extracts the value of the form field, accounting for potential inheritance | ||
| 239 | + /// through the form hierarchy. It returns the value if it is a String, and an empty string | ||
| 240 | + /// otherwise. | ||
| 241 | + /// | ||
| 242 | + /// @return A string containing the actual or inherited `/V` attribute of the form field, or | ||
| 243 | + /// an empty string if the value is not present or not a String. | ||
| 244 | + std::string value() const; | ||
| 245 | + | ||
| 246 | + /// @brief Retrieves the field default value (`/DV` attribute) of a specified field, | ||
| 247 | + /// accounting for inheritance through the hierarchy of ancestor nodes in the form | ||
| 248 | + /// field tree. | ||
| 249 | + /// | ||
| 250 | + /// This function attempts to retrieve the `/DV` attribute. If the `inherit` parameter is | ||
| 251 | + /// set to `true` and the `/DV` is not found at the current level, the method traverses up | ||
| 252 | + /// the parent hierarchy to find the value. The traversal stops when | ||
| 253 | + /// `/DV` is found, when the root node is reached, or when a loop detection mechanism | ||
| 254 | + /// prevents further traversal. | ||
| 255 | + /// | ||
| 256 | + /// @tparam T The return type. | ||
| 257 | + /// @param inherit If set to `true`, the function will attempt to retrieve `/DV` by | ||
| 258 | + /// inheritance from the parent hierarchy of the form field. Defaults to `true`. | ||
| 259 | + /// @return Returns the field's default value if found; otherwise, returns a | ||
| 260 | + /// default-constructed value of type `T`. | ||
| 261 | + QPDFObjectHandle const& | ||
| 262 | + DV(bool inherit = true) const | ||
| 263 | + { | ||
| 264 | + if (auto& v = get("/DV")) { | ||
| 265 | + return v; | ||
| 266 | + } | ||
| 267 | + return {inherit ? inherited("/DV") : null_oh}; | ||
| 268 | + } | ||
| 80 | 269 | ||
| 81 | - // Return the default appearance string, taking inheritance from the field tree into | ||
| 82 | - // account. Returns the empty string if the default appearance string is not available | ||
| 83 | - // (because it's erroneously absent or because this is not a variable text field). If not | ||
| 84 | - // found in the field hierarchy, look in /AcroForm. | ||
| 85 | - std::string getDefaultAppearance(); | 270 | + /// @brief Retrieves the default value `/DV` attribute of the form field, considering |
| 271 | + /// inheritance, if the default value is a String. | ||
| 272 | + /// | ||
| 273 | + /// This function extracts the default value of the form field, accounting for potential | ||
| 274 | + /// inheritance through the form hierarchy. It returns the value if it is a String, and an | ||
| 275 | + /// empty string otherwise. | ||
| 276 | + /// | ||
| 277 | + /// @return A string containing the actual or inherited `/V` attribute of the form field, or | ||
| 278 | + /// an empty string if the value is not present or not a String. | ||
| 279 | + std::string default_value() const; | ||
| 280 | + | ||
| 281 | + /// @brief Returns the default appearance string for the form field, considering inheritance | ||
| 282 | + /// from the field tree hierarchy and the document's /AcroForm dictionary. | ||
| 283 | + /// | ||
| 284 | + /// This method retrieves the field's /DA (default appearance) attribute. If the attribute | ||
| 285 | + /// is not directly available, it checks the parent fields in the hierarchy for an inherited | ||
| 286 | + /// value. If no value is found in the field hierarchy, it attempts to retrieve the /DA | ||
| 287 | + /// attribute from the document's /AcroForm dictionary. The method returns an empty string | ||
| 288 | + /// if no default appearance string is available or applicable. | ||
| 289 | + /// | ||
| 290 | + /// @return A string representing the default appearance, or an empty string if | ||
| 291 | + /// no value is found. | ||
| 292 | + std::string default_appearance() const; | ||
| 86 | 293 | ||
| 87 | // Return the default resource dictionary for the field. This comes not from the field but | 294 | // Return the default resource dictionary for the field. This comes not from the field but |
| 88 | // from the document-level /AcroForm dictionary. While several PDF generates put a /DR key | 295 | // from the document-level /AcroForm dictionary. While several PDF generates put a /DR key |
| @@ -154,12 +361,29 @@ namespace qpdf::impl | @@ -154,12 +361,29 @@ namespace qpdf::impl | ||
| 154 | void generateAppearance(QPDFAnnotationObjectHelper&); | 361 | void generateAppearance(QPDFAnnotationObjectHelper&); |
| 155 | 362 | ||
| 156 | private: | 363 | private: |
| 157 | - QPDFObjectHandle getFieldFromAcroForm(std::string const& name); | 364 | + /// @brief Retrieves an entry from the document's /AcroForm dictionary using the specified |
| 365 | + /// name. | ||
| 366 | + /// | ||
| 367 | + /// The method accesses the AcroForm dictionary within the root object of the PDF document. | ||
| 368 | + /// If the the AcroForm dictionary contains the given field name, it retrieves the | ||
| 369 | + /// corresponding entry. Otherwise, it returns a default-constructed object handle. | ||
| 370 | + /// | ||
| 371 | + /// @param name The name of the form field to retrieve. | ||
| 372 | + /// @return A object handle corresponding to the specified name within the AcroForm | ||
| 373 | + /// dictionary. | ||
| 374 | + QPDFObjectHandle const& | ||
| 375 | + from_AcroForm(std::string const& name) const | ||
| 376 | + { | ||
| 377 | + return {qpdf() ? qpdf()->getRoot()["/AcroForm"][name] : null_oh}; | ||
| 378 | + } | ||
| 379 | + | ||
| 158 | void setRadioButtonValue(QPDFObjectHandle name); | 380 | void setRadioButtonValue(QPDFObjectHandle name); |
| 159 | void setCheckBoxValue(bool value); | 381 | void setCheckBoxValue(bool value); |
| 160 | void generateTextAppearance(QPDFAnnotationObjectHelper&); | 382 | void generateTextAppearance(QPDFAnnotationObjectHelper&); |
| 161 | QPDFObjectHandle | 383 | QPDFObjectHandle |
| 162 | getFontFromResource(QPDFObjectHandle resources, std::string const& font_name); | 384 | getFontFromResource(QPDFObjectHandle resources, std::string const& font_name); |
| 385 | + | ||
| 386 | + static const QPDFObjectHandle null_oh; | ||
| 163 | }; | 387 | }; |
| 164 | } // namespace qpdf::impl | 388 | } // namespace qpdf::impl |
| 165 | 389 |
libtests/objects.cc
| @@ -90,7 +90,6 @@ test_0(QPDF& pdf, char const* arg2) | @@ -90,7 +90,6 @@ test_0(QPDF& pdf, char const* arg2) | ||
| 90 | assert_compare_numbers(UINT_MAX, t.getKey("/Q3").getUIntValueAsUInt()); | 90 | assert_compare_numbers(UINT_MAX, t.getKey("/Q3").getUIntValueAsUInt()); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | - | ||
| 94 | static void | 93 | static void |
| 95 | test_1(QPDF& pdf, char const* arg2) | 94 | test_1(QPDF& pdf, char const* arg2) |
| 96 | { | 95 | { |
| @@ -121,7 +120,7 @@ test_1(QPDF& pdf, char const* arg2) | @@ -121,7 +120,7 @@ test_1(QPDF& pdf, char const* arg2) | ||
| 121 | 120 | ||
| 122 | bool thrown = false; | 121 | bool thrown = false; |
| 123 | try { | 122 | try { |
| 124 | - i.at("/A"); | 123 | + i.at("/A"); |
| 125 | } catch (std::runtime_error const&) { | 124 | } catch (std::runtime_error const&) { |
| 126 | thrown = true; | 125 | thrown = true; |
| 127 | } | 126 | } |
| @@ -161,7 +160,9 @@ runtest(int n, char const* filename1, char const* arg2) | @@ -161,7 +160,9 @@ runtest(int n, char const* filename1, char const* arg2) | ||
| 161 | // the test suite to see how the test is invoked to find the file | 160 | // the test suite to see how the test is invoked to find the file |
| 162 | // that the test is supposed to operate on. | 161 | // that the test is supposed to operate on. |
| 163 | 162 | ||
| 164 | - std::set<int> ignore_filename = {1,}; | 163 | + std::set<int> ignore_filename = { |
| 164 | + 1, | ||
| 165 | + }; | ||
| 165 | 166 | ||
| 166 | QPDF pdf; | 167 | QPDF pdf; |
| 167 | std::shared_ptr<char> file_buf; | 168 | std::shared_ptr<char> file_buf; |
| @@ -175,7 +176,8 @@ runtest(int n, char const* filename1, char const* arg2) | @@ -175,7 +176,8 @@ runtest(int n, char const* filename1, char const* arg2) | ||
| 175 | } | 176 | } |
| 176 | 177 | ||
| 177 | std::map<int, void (*)(QPDF&, char const*)> test_functions = { | 178 | std::map<int, void (*)(QPDF&, char const*)> test_functions = { |
| 178 | - {0, test_0}, {1, test_1}, | 179 | + {0, test_0}, |
| 180 | + {1, test_1}, | ||
| 179 | }; | 181 | }; |
| 180 | 182 | ||
| 181 | auto fn = test_functions.find(n); | 183 | auto fn = test_functions.find(n); |
manual/release-notes.rst
| @@ -23,6 +23,12 @@ more detail. | @@ -23,6 +23,12 @@ more detail. | ||
| 23 | not work on some older Linux distributions. If you need support | 23 | not work on some older Linux distributions. If you need support |
| 24 | for an older distribution, please use version 12.2.0 or below. | 24 | for an older distribution, please use version 12.2.0 or below. |
| 25 | 25 | ||
| 26 | + - Bug fixes | ||
| 27 | + | ||
| 28 | + - Set `is_different` flag in `QPDFFormFieldObjectHelper::getTopLevelField` to | ||
| 29 | + false if the field is a top-level field. Previously the flag was only set | ||
| 30 | + if the field is a top-level field. | ||
| 31 | + | ||
| 26 | - Library Enhancements | 32 | - Library Enhancements |
| 27 | 33 | ||
| 28 | - Add ``QPDFNameTreeObjectHelper`` and ``QPDFNumberTreeObjectHelper`` | 34 | - Add ``QPDFNameTreeObjectHelper`` and ``QPDFNumberTreeObjectHelper`` |
qpdf/qpdf.testcov
| @@ -174,12 +174,7 @@ QPDFObjectHandle dictionary empty map for asMap 0 | @@ -174,12 +174,7 @@ QPDFObjectHandle dictionary empty map for asMap 0 | ||
| 174 | QPDFObjectHandle numeric non-numeric 0 | 174 | QPDFObjectHandle numeric non-numeric 0 |
| 175 | QPDFObjectHandle erase array bounds 0 | 175 | QPDFObjectHandle erase array bounds 0 |
| 176 | qpdf-c called qpdf_check_pdf 0 | 176 | qpdf-c called qpdf_check_pdf 0 |
| 177 | -QPDFFormFieldObjectHelper TU present 0 | ||
| 178 | -QPDFFormFieldObjectHelper TM present 0 | ||
| 179 | -QPDFFormFieldObjectHelper TU absent 0 | ||
| 180 | -QPDFFormFieldObjectHelper TM absent 0 | ||
| 181 | QPDFFormFieldObjectHelper Q present 1 | 177 | QPDFFormFieldObjectHelper Q present 1 |
| 182 | -QPDFFormFieldObjectHelper DA present 1 | ||
| 183 | QPDFAcroFormDocumentHelper field found 1 | 178 | QPDFAcroFormDocumentHelper field found 1 |
| 184 | QPDFAcroFormDocumentHelper annotation found 1 | 179 | QPDFAcroFormDocumentHelper annotation found 1 |
| 185 | QPDFJob automatically set keep files open 1 | 180 | QPDFJob automatically set keep files open 1 |