Commit 3fbae967654f175ea1b0bd684947b645bfc69c69
Committed by
GitHub
Merge pull request #1515 from m-holger/base_oh
Add new private-API methods `BaseHandle::size` and `BaseHandle::empty`
Showing
21 changed files
with
337 additions
and
274 deletions
include/qpdf/ObjectHandle.hh
| ... | ... | @@ -22,7 +22,10 @@ |
| 22 | 22 | |
| 23 | 23 | #include <qpdf/Constants.h> |
| 24 | 24 | #include <qpdf/DLL.h> |
| 25 | +#include <qpdf/Types.h> | |
| 26 | + | |
| 25 | 27 | #include <qpdf/JSON.hh> |
| 28 | +#include <qpdf/QPDFExc.hh> | |
| 26 | 29 | #include <qpdf/QPDFObjGen.hh> |
| 27 | 30 | #include <qpdf/Types.h> |
| 28 | 31 | |
| ... | ... | @@ -58,6 +61,18 @@ namespace qpdf |
| 58 | 61 | |
| 59 | 62 | // The rest of the header file is for qpdf internal use only. |
| 60 | 63 | |
| 64 | + // For arrays, return the number of items in the array. | |
| 65 | + // For null-like objects, return 0. | |
| 66 | + // For all other objects, return 1. | |
| 67 | + size_t size() const; | |
| 68 | + | |
| 69 | + // Return 'true' if size() == 0. | |
| 70 | + bool | |
| 71 | + empty() const | |
| 72 | + { | |
| 73 | + return size() == 0; | |
| 74 | + } | |
| 75 | + | |
| 61 | 76 | std::shared_ptr<QPDFObject> copy(bool shallow = false) const; |
| 62 | 77 | // Recursively remove association with any QPDF object. This method may only be called |
| 63 | 78 | // during final destruction. |
| ... | ... | @@ -71,6 +86,9 @@ namespace qpdf |
| 71 | 86 | inline qpdf_object_type_e type_code() const; |
| 72 | 87 | std::string unparse() const; |
| 73 | 88 | void write_json(int json_version, JSON::Writer& p) const; |
| 89 | + static void warn(QPDF*, QPDFExc&&); | |
| 90 | + void warn(QPDFExc&&) const; | |
| 91 | + void warn(std::string const& warning) const; | |
| 74 | 92 | |
| 75 | 93 | protected: |
| 76 | 94 | BaseHandle() = default; |
| ... | ... | @@ -87,6 +105,11 @@ namespace qpdf |
| 87 | 105 | template <typename T> |
| 88 | 106 | T* as() const; |
| 89 | 107 | |
| 108 | + std::string description() const; | |
| 109 | + std::runtime_error type_error(char const* expected_type) const; | |
| 110 | + QPDFExc type_error(char const* expected_type, std::string const& message) const; | |
| 111 | + char const* type_name() const; | |
| 112 | + | |
| 90 | 113 | std::shared_ptr<QPDFObject> obj; |
| 91 | 114 | }; |
| 92 | 115 | ... | ... |
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -1357,7 +1357,6 @@ class QPDFObjectHandle: public qpdf::BaseHandle |
| 1357 | 1357 | QPDF* context); |
| 1358 | 1358 | std::vector<QPDFObjectHandle> |
| 1359 | 1359 | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); |
| 1360 | - static void warn(QPDF*, QPDFExc const&); | |
| 1361 | 1360 | void checkOwnership(QPDFObjectHandle const&) const; |
| 1362 | 1361 | }; |
| 1363 | 1362 | ... | ... |
libqpdf/QPDFAcroFormDocumentHelper.cc
| ... | ... | @@ -7,7 +7,10 @@ |
| 7 | 7 | #include <qpdf/QUtil.hh> |
| 8 | 8 | #include <qpdf/ResourceFinder.hh> |
| 9 | 9 | |
| 10 | +#include <utility> | |
| 11 | + | |
| 10 | 12 | using namespace qpdf; |
| 13 | +using namespace std::literals; | |
| 11 | 14 | |
| 12 | 15 | QPDFAcroFormDocumentHelper::QPDFAcroFormDocumentHelper(QPDF& qpdf) : |
| 13 | 16 | QPDFDocumentHelper(qpdf), |
| ... | ... | @@ -138,7 +141,7 @@ QPDFAcroFormDocumentHelper::removeFormFields(std::set<QPDFObjGen> const& to_remo |
| 138 | 141 | } |
| 139 | 142 | |
| 140 | 143 | int i = 0; |
| 141 | - while (i < fields.getArrayNItems()) { | |
| 144 | + while (std::cmp_less(i, fields.size())) { | |
| 142 | 145 | auto field = fields.getArrayItem(i); |
| 143 | 146 | if (to_remove.contains(field.getObjGen())) { |
| 144 | 147 | fields.eraseItem(i); |
| ... | ... | @@ -251,7 +254,7 @@ QPDFAcroFormDocumentHelper::analyze() |
| 251 | 254 | } |
| 252 | 255 | } else { |
| 253 | 256 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); |
| 254 | - acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring"); | |
| 257 | + acroform.warn("/Fields key of /AcroForm dictionary is not an array; ignoring"); | |
| 255 | 258 | fields = QPDFObjectHandle::newArray(); |
| 256 | 259 | } |
| 257 | 260 | |
| ... | ... | @@ -273,9 +276,9 @@ QPDFAcroFormDocumentHelper::analyze() |
| 273 | 276 | // case such as a PDF creator adding a self-contained annotation (merged with the |
| 274 | 277 | // field dictionary) to the page's /Annots array and forgetting to also put it in |
| 275 | 278 | // /AcroForm. |
| 276 | - annot.warnIfPossible( | |
| 277 | - "this widget annotation is not" | |
| 278 | - " reachable from /AcroForm in the document catalog"); | |
| 279 | + annot.warn( | |
| 280 | + "this widget annotation is not reachable from /AcroForm in the document " | |
| 281 | + "catalog"); | |
| 279 | 282 | m->annotation_to_field[og] = QPDFFormFieldObjectHelper(annot); |
| 280 | 283 | m->field_to_annotations[og].emplace_back(annot); |
| 281 | 284 | } |
| ... | ... | @@ -292,16 +295,16 @@ QPDFAcroFormDocumentHelper::traverseField( |
| 292 | 295 | // could cause stack overflow. |
| 293 | 296 | return; |
| 294 | 297 | } |
| 295 | - if (!field.isIndirect()) { | |
| 298 | + if (!field.indirect()) { | |
| 296 | 299 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper direct field"); |
| 297 | - field.warnIfPossible( | |
| 300 | + field.warn( | |
| 298 | 301 | "encountered a direct object as a field or annotation while " |
| 299 | 302 | "traversing /AcroForm; ignoring field or annotation"); |
| 300 | 303 | return; |
| 301 | 304 | } |
| 302 | 305 | if (!field.isDictionary()) { |
| 303 | 306 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper non-dictionary field"); |
| 304 | - field.warnIfPossible( | |
| 307 | + field.warn( | |
| 305 | 308 | "encountered a non-dictionary as a field or annotation while" |
| 306 | 309 | " traversing /AcroForm; ignoring field or annotation"); |
| 307 | 310 | return; |
| ... | ... | @@ -309,7 +312,7 @@ QPDFAcroFormDocumentHelper::traverseField( |
| 309 | 312 | QPDFObjGen og(field.getObjGen()); |
| 310 | 313 | if (!visited.add(og)) { |
| 311 | 314 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper loop"); |
| 312 | - field.warnIfPossible("loop detected while traversing /AcroForm"); | |
| 315 | + field.warn("loop detected while traversing /AcroForm"); | |
| 313 | 316 | return; |
| 314 | 317 | } |
| 315 | 318 | |
| ... | ... | @@ -375,7 +378,7 @@ QPDFAcroFormDocumentHelper::setNeedAppearances(bool val) |
| 375 | 378 | { |
| 376 | 379 | QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm"); |
| 377 | 380 | if (!acroform.isDictionary()) { |
| 378 | - qpdf.getRoot().warnIfPossible( | |
| 381 | + qpdf.getRoot().warn( | |
| 379 | 382 | "ignoring call to QPDFAcroFormDocumentHelper::setNeedAppearances" |
| 380 | 383 | " on a file that lacks an /AcroForm dictionary"); |
| 381 | 384 | return; |
| ... | ... | @@ -592,9 +595,7 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances( |
| 592 | 595 | } catch (std::exception& e) { |
| 593 | 596 | // No way to reproduce in test suite right now since error conditions are converted to |
| 594 | 597 | // warnings. |
| 595 | - obj.warnIfPossible( | |
| 596 | - std::string("Unable to parse /DA: ") + e.what() + | |
| 597 | - "; this form field may not update properly"); | |
| 598 | + obj.warn("Unable to parse /DA: "s + e.what() + "; this form field may not update properly"); | |
| 598 | 599 | return; |
| 599 | 600 | } |
| 600 | 601 | |
| ... | ... | @@ -677,16 +678,17 @@ QPDFAcroFormDocumentHelper::adjustAppearanceStream( |
| 677 | 678 | try { |
| 678 | 679 | auto nwarnings = qpdf.numWarnings(); |
| 679 | 680 | stream.parseAsContents(&rf); |
| 680 | - if (qpdf.numWarnings() > nwarnings) { | |
| 681 | - QTC::TC("qpdf", "QPDFAcroFormDocumentHelper AP parse error"); | |
| 682 | - } | |
| 681 | + QTC::TC( | |
| 682 | + "qpdf", | |
| 683 | + "QPDFAcroFormDocumentHelper AP parse error", | |
| 684 | + qpdf.numWarnings() > nwarnings ? 0 : 1); | |
| 683 | 685 | auto rr = new ResourceReplacer(dr_map, rf.getNamesByResourceType()); |
| 684 | 686 | auto tf = std::shared_ptr<QPDFObjectHandle::TokenFilter>(rr); |
| 685 | 687 | stream.addTokenFilter(tf); |
| 686 | 688 | } catch (std::exception& e) { |
| 687 | 689 | // No way to reproduce in test suite right now since error conditions are converted to |
| 688 | 690 | // warnings. |
| 689 | - stream.warnIfPossible(std::string("Unable to parse appearance stream: ") + e.what()); | |
| 691 | + stream.warn("Unable to parse appearance stream: "s + e.what()); | |
| 690 | 692 | } |
| 691 | 693 | } |
| 692 | 694 | |
| ... | ... | @@ -814,7 +816,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 814 | 816 | QPDFObjGen::set added_new_fields; |
| 815 | 817 | for (auto annot: old_annots.aitems()) { |
| 816 | 818 | if (annot.isStream()) { |
| 817 | - annot.warnIfPossible("ignoring annotation that's a stream"); | |
| 819 | + annot.warn("ignoring annotation that's a stream"); | |
| 818 | 820 | continue; |
| 819 | 821 | } |
| 820 | 822 | |
| ... | ... | @@ -847,10 +849,10 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 847 | 849 | bool have_field = false; |
| 848 | 850 | bool have_parent = false; |
| 849 | 851 | if (ffield_oh.isStream()) { |
| 850 | - ffield_oh.warnIfPossible("ignoring form field that's a stream"); | |
| 852 | + ffield.warn("ignoring form field that's a stream"); | |
| 851 | 853 | } else if ((!ffield_oh.isNull()) && (!ffield_oh.isIndirect())) { |
| 852 | - ffield_oh.warnIfPossible("ignoring form field not indirect"); | |
| 853 | - } else if (!ffield_oh.isNull()) { | |
| 854 | + ffield.warn("ignoring form field not indirect"); | |
| 855 | + } else if (!ffield.null()) { | |
| 854 | 856 | // A field and its associated annotation can be the same object. This matters because we |
| 855 | 857 | // don't want to clone the annotation and field separately in this case. |
| 856 | 858 | have_field = true; |
| ... | ... | @@ -888,7 +890,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 888 | 890 | if (orig_to_copy.contains(parent_og)) { |
| 889 | 891 | obj.replaceKey("/Parent", orig_to_copy[parent_og]); |
| 890 | 892 | } else { |
| 891 | - parent.warnIfPossible( | |
| 893 | + parent.warn( | |
| 892 | 894 | "while traversing field " + obj.getObjGen().unparse(',') + |
| 893 | 895 | ", found parent (" + parent_og.unparse(',') + |
| 894 | 896 | ") that had not been seen, indicating likely invalid field " |
| ... | ... | @@ -896,12 +898,13 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 896 | 898 | } |
| 897 | 899 | } |
| 898 | 900 | auto kids = obj.getKey("/Kids"); |
| 899 | - if (kids.isArray()) { | |
| 900 | - for (int i = 0; i < kids.getArrayNItems(); ++i) { | |
| 901 | + int sz = static_cast<int>(kids.size()); | |
| 902 | + if (sz != 1 || kids.isArray()) { | |
| 903 | + for (int i = 0; i < sz; ++i) { | |
| 901 | 904 | auto kid = kids.getArrayItem(i); |
| 902 | 905 | if (maybe_copy_object(kid)) { |
| 903 | 906 | kids.setArrayItem(i, kid); |
| 904 | - queue.push_back(kid); | |
| 907 | + queue.emplace_back(kid); | |
| 905 | 908 | } |
| 906 | 909 | } |
| 907 | 910 | } |
| ... | ... | @@ -1013,7 +1016,7 @@ QPDFAcroFormDocumentHelper::fixCopiedAnnotations( |
| 1013 | 1016 | std::set<QPDFObjGen>* added_fields) |
| 1014 | 1017 | { |
| 1015 | 1018 | auto old_annots = from_page.getKey("/Annots"); |
| 1016 | - if ((!old_annots.isArray()) || (old_annots.getArrayNItems() == 0)) { | |
| 1019 | + if (old_annots.empty() || !old_annots.isArray()) { | |
| 1017 | 1020 | return; |
| 1018 | 1021 | } |
| 1019 | 1022 | ... | ... |
libqpdf/QPDFEFStreamObjectHelper.cc
| ... | ... | @@ -138,7 +138,7 @@ QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream) |
| 138 | 138 | Pl_MD5 md5("EF md5", &discard); |
| 139 | 139 | Pl_Count count("EF size", &md5); |
| 140 | 140 | if (!stream.pipeStreamData(&count, nullptr, 0, qpdf_dl_all)) { |
| 141 | - stream.warnIfPossible("unable to get stream data for new embedded file stream"); | |
| 141 | + stream.warn("unable to get stream data for new embedded file stream"); | |
| 142 | 142 | } else { |
| 143 | 143 | result.setParam("/Size", QPDFObjectHandle::newInteger(count.getCount())); |
| 144 | 144 | result.setParam( | ... | ... |
libqpdf/QPDFFileSpecObjectHelper.cc
| ... | ... | @@ -4,32 +4,33 @@ |
| 4 | 4 | #include <qpdf/QTC.hh> |
| 5 | 5 | #include <qpdf/QUtil.hh> |
| 6 | 6 | |
| 7 | +#include <array> | |
| 7 | 8 | #include <string> |
| 8 | -#include <vector> | |
| 9 | + | |
| 10 | +using namespace std::literals; | |
| 9 | 11 | |
| 10 | 12 | QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) : |
| 11 | 13 | QPDFObjectHelper(oh) |
| 12 | 14 | { |
| 13 | 15 | if (!oh.isDictionary()) { |
| 14 | - oh.warnIfPossible("Embedded file object is not a dictionary"); | |
| 16 | + warn("Embedded file object is not a dictionary"); | |
| 15 | 17 | return; |
| 16 | 18 | } |
| 17 | 19 | if (!oh.isDictionaryOfType("/Filespec")) { |
| 18 | - oh.warnIfPossible("Embedded file object's type is not /Filespec"); | |
| 20 | + warn("Embedded file object's type is not /Filespec"); | |
| 19 | 21 | } |
| 20 | 22 | } |
| 21 | 23 | |
| 22 | -static std::vector<std::string> name_keys = {"/UF", "/F", "/Unix", "/DOS", "/Mac"}; | |
| 24 | +static const std::array<std::string, 5> name_keys = {"/UF"s, "/F"s, "/Unix"s, "/DOS"s, "/Mac"s}; | |
| 23 | 25 | |
| 24 | 26 | std::string |
| 25 | 27 | QPDFFileSpecObjectHelper::getDescription() |
| 26 | 28 | { |
| 27 | - std::string result; | |
| 28 | 29 | auto desc = oh().getKey("/Desc"); |
| 29 | 30 | if (desc.isString()) { |
| 30 | - result = desc.getUTF8Value(); | |
| 31 | + return desc.getUTF8Value(); | |
| 31 | 32 | } |
| 32 | - return result; | |
| 33 | + return {}; | |
| 33 | 34 | } |
| 34 | 35 | |
| 35 | 36 | std::string | ... | ... |
libqpdf/QPDFFormFieldObjectHelper.cc
| ... | ... | @@ -281,7 +281,7 @@ QPDFFormFieldObjectHelper::getChoices() |
| 281 | 281 | for (auto const& item: getInheritableFieldValue("/Opt").as_array()) { |
| 282 | 282 | if (item.isString()) { |
| 283 | 283 | result.emplace_back(item.getUTF8Value()); |
| 284 | - } else if (item.isArray() && item.getArrayNItems() == 2) { | |
| 284 | + } else if (item.size() == 2) { | |
| 285 | 285 | auto display = item.getArrayItem(1); |
| 286 | 286 | if (display.isString()) { |
| 287 | 287 | result.emplace_back(display.getUTF8Value()); |
| ... | ... | @@ -317,18 +317,17 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) |
| 317 | 317 | setCheckBoxValue((name != "/Off")); |
| 318 | 318 | } |
| 319 | 319 | if (!okay) { |
| 320 | - oh().warnIfPossible( | |
| 321 | - "ignoring attempt to set a checkbox field to a value whose type is not name"); | |
| 320 | + warn("ignoring attempt to set a checkbox field to a value whose type is not name"); | |
| 322 | 321 | } |
| 323 | 322 | } else if (isRadioButton()) { |
| 324 | 323 | if (value.isName()) { |
| 325 | 324 | setRadioButtonValue(value); |
| 326 | 325 | } else { |
| 327 | - oh().warnIfPossible( | |
| 326 | + warn( | |
| 328 | 327 | "ignoring attempt to set a radio button field to an object that is not a name"); |
| 329 | 328 | } |
| 330 | 329 | } else if (isPushbutton()) { |
| 331 | - oh().warnIfPossible("ignoring attempt set the value of a pushbutton field"); | |
| 330 | + warn("ignoring attempt set the value of a pushbutton field"); | |
| 332 | 331 | } |
| 333 | 332 | return; |
| 334 | 333 | } |
| ... | ... | @@ -375,7 +374,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) |
| 375 | 374 | |
| 376 | 375 | QPDFObjectHandle kids = oh().getKey("/Kids"); |
| 377 | 376 | if (!(isRadioButton() && parent.isNull() && kids.isArray())) { |
| 378 | - oh().warnIfPossible("don't know how to set the value of this field as a radio button"); | |
| 377 | + warn("don't know how to set the value of this field as a radio button"); | |
| 379 | 378 | return; |
| 380 | 379 | } |
| 381 | 380 | setFieldAttribute("/V", name); |
| ... | ... | @@ -397,7 +396,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) |
| 397 | 396 | } |
| 398 | 397 | if (!annot) { |
| 399 | 398 | QTC::TC("qpdf", "QPDFObjectHandle broken radio button"); |
| 400 | - oh().warnIfPossible("unable to set the value of this radio button"); | |
| 399 | + warn("unable to set the value of this radio button"); | |
| 401 | 400 | continue; |
| 402 | 401 | } |
| 403 | 402 | if (AP.isDictionary() && AP.getKey("/N").isDictionary() && |
| ... | ... | @@ -453,7 +452,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) |
| 453 | 452 | setFieldAttribute("/V", name); |
| 454 | 453 | if (!annot) { |
| 455 | 454 | QTC::TC("qpdf", "QPDFObjectHandle broken checkbox"); |
| 456 | - oh().warnIfPossible("unable to set the value of this checkbox"); | |
| 455 | + warn("unable to set the value of this checkbox"); | |
| 457 | 456 | return; |
| 458 | 457 | } |
| 459 | 458 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper set checkbox AS"); |
| ... | ... | @@ -770,18 +769,17 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& ao |
| 770 | 769 | AP.replaceKey("/N", AS); |
| 771 | 770 | } |
| 772 | 771 | if (!AS.isStream()) { |
| 773 | - aoh.getObjectHandle().warnIfPossible("unable to get normal appearance stream for update"); | |
| 772 | + aoh.warn("unable to get normal appearance stream for update"); | |
| 774 | 773 | return; |
| 775 | 774 | } |
| 776 | 775 | |
| 777 | 776 | if (AS.getObj().use_count() > 4) { |
| 778 | - aoh.getObjectHandle().warnIfPossible( | |
| 779 | - "unable to generate text appearance from shared appearance stream for update"); | |
| 777 | + aoh.warn("unable to generate text appearance from shared appearance stream for update"); | |
| 780 | 778 | return; |
| 781 | 779 | } |
| 782 | 780 | QPDFObjectHandle bbox_obj = AS.getDict().getKey("/BBox"); |
| 783 | 781 | if (!bbox_obj.isRectangle()) { |
| 784 | - aoh.getObjectHandle().warnIfPossible("unable to get appearance stream bounding box"); | |
| 782 | + aoh.warn("unable to get appearance stream bounding box"); | |
| 785 | 783 | return; |
| 786 | 784 | } |
| 787 | 785 | QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle(); | ... | ... |
libqpdf/QPDFJob.cc
| ... | ... | @@ -1082,7 +1082,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) |
| 1082 | 1082 | dp_array = decode_parms; |
| 1083 | 1083 | } else { |
| 1084 | 1084 | dp_array = QPDFObjectHandle::newArray(); |
| 1085 | - for (int i = 0; i < filters.getArrayNItems(); ++i) { | |
| 1085 | + for (size_t i = 0; i < filters.size(); ++i) { | |
| 1086 | 1086 | dp_array.appendItem(decode_parms); |
| 1087 | 1087 | } |
| 1088 | 1088 | } |
| ... | ... | @@ -2322,7 +2322,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) |
| 2322 | 2322 | }); |
| 2323 | 2323 | |
| 2324 | 2324 | std::list<QPDFObjectHandle> queue; |
| 2325 | - queue.push_back(pdf.getRoot().getKey("/Pages")); | |
| 2325 | + queue.emplace_back(pdf.getRoot().getKey("/Pages")); | |
| 2326 | 2326 | while (!queue.empty()) { |
| 2327 | 2327 | QPDFObjectHandle node = *queue.begin(); |
| 2328 | 2328 | queue.pop_front(); |
| ... | ... | @@ -2341,9 +2341,8 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) |
| 2341 | 2341 | }); |
| 2342 | 2342 | return true; |
| 2343 | 2343 | } |
| 2344 | - int n = kids.getArrayNItems(); | |
| 2345 | - for (int i = 0; i < n; ++i) { | |
| 2346 | - queue.push_back(kids.getArrayItem(i)); | |
| 2344 | + for (auto const& kid: kids.as_array()) { | |
| 2345 | + queue.emplace_back(kid); | |
| 2347 | 2346 | } |
| 2348 | 2347 | } else { |
| 2349 | 2348 | // This is a leaf node or a form XObject. |
| ... | ... | @@ -2670,12 +2669,10 @@ QPDFJob::handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_hea |
| 2670 | 2669 | new_fields.appendItem(field); |
| 2671 | 2670 | } |
| 2672 | 2671 | } |
| 2673 | - if (new_fields.getArrayNItems() > 0) { | |
| 2674 | - QTC::TC("qpdf", "QPDFJob keep some fields in pages"); | |
| 2675 | - acroform.replaceKey("/Fields", new_fields); | |
| 2676 | - } else { | |
| 2677 | - QTC::TC("qpdf", "QPDFJob no more fields in pages"); | |
| 2672 | + if (new_fields.empty()) { | |
| 2678 | 2673 | pdf.getRoot().removeKey("/AcroForm"); |
| 2674 | + } else { | |
| 2675 | + acroform.replaceKey("/Fields", new_fields); | |
| 2679 | 2676 | } |
| 2680 | 2677 | } |
| 2681 | 2678 | } | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -352,16 +352,15 @@ BaseHandle::unparse() const |
| 352 | 352 | auto const& a = std::get<QPDF_Array>(obj->value); |
| 353 | 353 | std::string result = "[ "; |
| 354 | 354 | if (a.sp) { |
| 355 | - int next = 0; | |
| 356 | - for (auto& item: a.sp->elements) { | |
| 357 | - int key = item.first; | |
| 358 | - for (int j = next; j < key; ++j) { | |
| 355 | + size_t next = 0; | |
| 356 | + for (auto& [key, value]: a.sp->elements) { | |
| 357 | + for (size_t j = next; j < key; ++j) { | |
| 359 | 358 | result += "null "; |
| 360 | 359 | } |
| 361 | - result += item.second.unparse() + " "; | |
| 362 | - next = ++key; | |
| 360 | + result += value.unparse() + " "; | |
| 361 | + next = key + 1; | |
| 363 | 362 | } |
| 364 | - for (int j = next; j < a.sp->size; ++j) { | |
| 363 | + for (size_t j = next; j < a.sp->size; ++j) { | |
| 365 | 364 | result += "null "; |
| 366 | 365 | } |
| 367 | 366 | } else { |
| ... | ... | @@ -467,22 +466,21 @@ BaseHandle::write_json(int json_version, JSON::Writer& p) const |
| 467 | 466 | auto const& a = std::get<QPDF_Array>(obj->value); |
| 468 | 467 | p.writeStart('['); |
| 469 | 468 | if (a.sp) { |
| 470 | - int next = 0; | |
| 471 | - for (auto& item: a.sp->elements) { | |
| 472 | - int key = item.first; | |
| 473 | - for (int j = next; j < key; ++j) { | |
| 469 | + size_t next = 0; | |
| 470 | + for (auto& [key, value]: a.sp->elements) { | |
| 471 | + for (size_t j = next; j < key; ++j) { | |
| 474 | 472 | p.writeNext() << "null"; |
| 475 | 473 | } |
| 476 | 474 | p.writeNext(); |
| 477 | - auto item_og = item.second.getObj()->getObjGen(); | |
| 475 | + auto item_og = value.getObj()->getObjGen(); | |
| 478 | 476 | if (item_og.isIndirect()) { |
| 479 | 477 | p << "\"" << item_og.unparse(' ') << " R\""; |
| 480 | 478 | } else { |
| 481 | - item.second.write_json(json_version, p); | |
| 479 | + value.write_json(json_version, p); | |
| 482 | 480 | } |
| 483 | - next = ++key; | |
| 481 | + next = key + 1; | |
| 484 | 482 | } |
| 485 | - for (int j = next; j < a.sp->size; ++j) { | |
| 483 | + for (size_t j = next; j < a.sp->size; ++j) { | |
| 486 | 484 | p.writeNext() << "null"; |
| 487 | 485 | } |
| 488 | 486 | } else { |
| ... | ... | @@ -611,11 +609,11 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const |
| 611 | 609 | qpdf_object_type_e |
| 612 | 610 | QPDFObjectHandle::getTypeCode() const |
| 613 | 611 | { |
| 614 | - return obj ? obj->getResolvedTypeCode() : ::ot_uninitialized; | |
| 612 | + return type_code(); | |
| 615 | 613 | } |
| 616 | 614 | |
| 617 | 615 | char const* |
| 618 | -QPDFObjectHandle::getTypeName() const | |
| 616 | +BaseHandle::type_name() const | |
| 619 | 617 | { |
| 620 | 618 | static constexpr std::array<char const*, 16> tn{ |
| 621 | 619 | "uninitialized", |
| ... | ... | @@ -634,7 +632,13 @@ QPDFObjectHandle::getTypeName() const |
| 634 | 632 | "unresolved", |
| 635 | 633 | "destroyed", |
| 636 | 634 | "reference"}; |
| 637 | - return obj ? tn[getTypeCode()] : "uninitialized"; | |
| 635 | + return tn[type_code()]; | |
| 636 | +} | |
| 637 | + | |
| 638 | +char const* | |
| 639 | +QPDFObjectHandle::getTypeName() const | |
| 640 | +{ | |
| 641 | + return type_name(); | |
| 638 | 642 | } |
| 639 | 643 | |
| 640 | 644 | bool |
| ... | ... | @@ -829,20 +833,16 @@ QPDFObjectHandle::getValueAsInt(long long& value) const |
| 829 | 833 | int |
| 830 | 834 | QPDFObjectHandle::getIntValueAsInt() const |
| 831 | 835 | { |
| 832 | - int result = 0; | |
| 833 | 836 | long long v = getIntValue(); |
| 834 | 837 | if (v < INT_MIN) { |
| 835 | - QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MIN"); | |
| 836 | - warnIfPossible("requested value of integer is too small; returning INT_MIN"); | |
| 837 | - result = INT_MIN; | |
| 838 | - } else if (v > INT_MAX) { | |
| 839 | - QTC::TC("qpdf", "QPDFObjectHandle int returning INT_MAX"); | |
| 840 | - warnIfPossible("requested value of integer is too big; returning INT_MAX"); | |
| 841 | - result = INT_MAX; | |
| 842 | - } else { | |
| 843 | - result = static_cast<int>(v); | |
| 838 | + warn("requested value of integer is too small; returning INT_MIN"); | |
| 839 | + return INT_MIN; | |
| 844 | 840 | } |
| 845 | - return result; | |
| 841 | + if (v > INT_MAX) { | |
| 842 | + warn("requested value of integer is too big; returning INT_MAX"); | |
| 843 | + return INT_MAX; | |
| 844 | + } | |
| 845 | + return static_cast<int>(v); | |
| 846 | 846 | } |
| 847 | 847 | |
| 848 | 848 | bool |
| ... | ... | @@ -860,8 +860,7 @@ QPDFObjectHandle::getUIntValue() const |
| 860 | 860 | { |
| 861 | 861 | long long v = getIntValue(); |
| 862 | 862 | if (v < 0) { |
| 863 | - QTC::TC("qpdf", "QPDFObjectHandle uint returning 0"); | |
| 864 | - warnIfPossible("unsigned value request for negative number; returning 0"); | |
| 863 | + warn("unsigned value request for negative number; returning 0"); | |
| 865 | 864 | return 0; |
| 866 | 865 | } else { |
| 867 | 866 | return static_cast<unsigned long long>(v); |
| ... | ... | @@ -883,16 +882,14 @@ QPDFObjectHandle::getUIntValueAsUInt() const |
| 883 | 882 | { |
| 884 | 883 | long long v = getIntValue(); |
| 885 | 884 | if (v < 0) { |
| 886 | - QTC::TC("qpdf", "QPDFObjectHandle uint uint returning 0"); | |
| 887 | - warnIfPossible("unsigned integer value request for negative number; returning 0"); | |
| 885 | + warn("unsigned integer value request for negative number; returning 0"); | |
| 888 | 886 | return 0; |
| 889 | - } else if (v > UINT_MAX) { | |
| 890 | - QTC::TC("qpdf", "QPDFObjectHandle uint returning UINT_MAX"); | |
| 891 | - warnIfPossible("requested value of unsigned integer is too big; returning UINT_MAX"); | |
| 887 | + } | |
| 888 | + if (v > UINT_MAX) { | |
| 889 | + warn("requested value of unsigned integer is too big; returning UINT_MAX"); | |
| 892 | 890 | return UINT_MAX; |
| 893 | - } else { | |
| 894 | - return static_cast<unsigned int>(v); | |
| 895 | 891 | } |
| 892 | + return static_cast<unsigned int>(v); | |
| 896 | 893 | } |
| 897 | 894 | |
| 898 | 895 | bool |
| ... | ... | @@ -1235,34 +1232,30 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( |
| 1235 | 1232 | all_description = description; |
| 1236 | 1233 | std::vector<QPDFObjectHandle> result; |
| 1237 | 1234 | if (auto array = as_array(strict)) { |
| 1238 | - int n_items = array.size(); | |
| 1235 | + int n_items = static_cast<int>(array.size()); | |
| 1239 | 1236 | for (int i = 0; i < n_items; ++i) { |
| 1240 | 1237 | QPDFObjectHandle item = array.at(i).second; |
| 1241 | 1238 | if (item.isStream()) { |
| 1242 | 1239 | result.emplace_back(item); |
| 1243 | 1240 | } else { |
| 1244 | 1241 | QTC::TC("qpdf", "QPDFObjectHandle non-stream in stream array"); |
| 1245 | - warn( | |
| 1246 | - item.getOwningQPDF(), | |
| 1247 | - QPDFExc( | |
| 1248 | - qpdf_e_damaged_pdf, | |
| 1249 | - "", | |
| 1250 | - description + ": item index " + std::to_string(i) + " (from 0)", | |
| 1251 | - 0, | |
| 1252 | - "ignoring non-stream in an array of streams")); | |
| 1242 | + item.warn( | |
| 1243 | + {qpdf_e_damaged_pdf, | |
| 1244 | + "", | |
| 1245 | + description + ": item index " + std::to_string(i) + " (from 0)", | |
| 1246 | + 0, | |
| 1247 | + "ignoring non-stream in an array of streams"}); | |
| 1253 | 1248 | } |
| 1254 | 1249 | } |
| 1255 | 1250 | } else if (isStream()) { |
| 1256 | 1251 | result.emplace_back(*this); |
| 1257 | - } else if (!isNull()) { | |
| 1252 | + } else if (!null()) { | |
| 1258 | 1253 | warn( |
| 1259 | - getOwningQPDF(), | |
| 1260 | - QPDFExc( | |
| 1261 | - qpdf_e_damaged_pdf, | |
| 1262 | - "", | |
| 1263 | - description, | |
| 1264 | - 0, | |
| 1265 | - " object is supposed to be a stream or an array of streams but is neither")); | |
| 1254 | + {qpdf_e_damaged_pdf, | |
| 1255 | + "", | |
| 1256 | + description, | |
| 1257 | + 0, | |
| 1258 | + " object is supposed to be a stream or an array of streams but is neither"}); | |
| 1266 | 1259 | } |
| 1267 | 1260 | |
| 1268 | 1261 | bool first = true; |
| ... | ... | @@ -1824,6 +1817,12 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) |
| 1824 | 1817 | return qpdf->newReserved(); |
| 1825 | 1818 | } |
| 1826 | 1819 | |
| 1820 | +std::string | |
| 1821 | +BaseHandle::description() const | |
| 1822 | +{ | |
| 1823 | + return obj ? obj->getDescription() : ""s; | |
| 1824 | +} | |
| 1825 | + | |
| 1827 | 1826 | void |
| 1828 | 1827 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) |
| 1829 | 1828 | { |
| ... | ... | @@ -1934,50 +1933,44 @@ QPDFObjectHandle::assertInitialized() const |
| 1934 | 1933 | } |
| 1935 | 1934 | } |
| 1936 | 1935 | |
| 1936 | +std::runtime_error | |
| 1937 | +BaseHandle::type_error(char const* expected_type) const | |
| 1938 | +{ | |
| 1939 | + return std::runtime_error( | |
| 1940 | + "operation for "s + expected_type + " attempted on object of type " + type_name()); | |
| 1941 | +} | |
| 1942 | + | |
| 1943 | +QPDFExc | |
| 1944 | +BaseHandle::type_error(char const* expected_type, std::string const& message) const | |
| 1945 | +{ | |
| 1946 | + return { | |
| 1947 | + qpdf_e_object, | |
| 1948 | + "", | |
| 1949 | + description(), | |
| 1950 | + 0, | |
| 1951 | + "operation for "s + expected_type + " attempted on object of type " + type_name() + ": " + | |
| 1952 | + message}; | |
| 1953 | +} | |
| 1954 | + | |
| 1937 | 1955 | void |
| 1938 | -QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& warning) const | |
| 1956 | +QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& message) const | |
| 1939 | 1957 | { |
| 1940 | - QPDF* context = nullptr; | |
| 1941 | - std::string description; | |
| 1942 | - // Type checks above guarantee that the object has been dereferenced. Nevertheless, dereference | |
| 1943 | - // throws exceptions in the test suite | |
| 1944 | 1958 | if (!obj) { |
| 1945 | 1959 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 1946 | 1960 | } |
| 1947 | - obj->getDescription(context, description); | |
| 1948 | - // Null context handled by warn | |
| 1949 | - warn( | |
| 1950 | - context, | |
| 1951 | - QPDFExc( | |
| 1952 | - qpdf_e_object, | |
| 1953 | - "", | |
| 1954 | - description, | |
| 1955 | - 0, | |
| 1956 | - std::string("operation for ") + expected_type + " attempted on object of type " + | |
| 1957 | - QPDFObjectHandle(*this).getTypeName() + ": " + warning)); | |
| 1961 | + warn(type_error(expected_type, message)); | |
| 1958 | 1962 | } |
| 1959 | 1963 | |
| 1960 | 1964 | void |
| 1961 | 1965 | QPDFObjectHandle::warnIfPossible(std::string const& warning) const |
| 1962 | 1966 | { |
| 1963 | - QPDF* context = nullptr; | |
| 1964 | - std::string description; | |
| 1965 | - if (obj && obj->getDescription(context, description)) { | |
| 1966 | - warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning)); | |
| 1967 | - } else { | |
| 1968 | - *QPDFLogger::defaultLogger()->getError() << warning << "\n"; | |
| 1969 | - } | |
| 1967 | + warn(warning); | |
| 1970 | 1968 | } |
| 1971 | 1969 | |
| 1972 | 1970 | void |
| 1973 | 1971 | QPDFObjectHandle::objectWarning(std::string const& warning) const |
| 1974 | 1972 | { |
| 1975 | - QPDF* context = nullptr; | |
| 1976 | - std::string description; | |
| 1977 | - // Type checks above guarantee that the object is initialized. | |
| 1978 | - obj->getDescription(context, description); | |
| 1979 | - // Null context handled by warn | |
| 1980 | - warn(context, QPDFExc(qpdf_e_object, "", description, 0, warning)); | |
| 1973 | + warn({qpdf_e_object, "", description(), 0, warning}); | |
| 1981 | 1974 | } |
| 1982 | 1975 | |
| 1983 | 1976 | void |
| ... | ... | @@ -2130,15 +2123,30 @@ QPDFObjectHandle::assertPageObject() const |
| 2130 | 2123 | } |
| 2131 | 2124 | |
| 2132 | 2125 | void |
| 2133 | -QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e) | |
| 2126 | +BaseHandle::warn(QPDF* qpdf, QPDFExc&& e) | |
| 2134 | 2127 | { |
| 2135 | - // If parsing on behalf of a QPDF object and want to give a warning, we can warn through the | |
| 2136 | - // object. If parsing for some other reason, such as an explicit creation of an object from a | |
| 2137 | - // string, then just throw the exception. | |
| 2138 | - if (qpdf) { | |
| 2139 | - qpdf->warn(e); | |
| 2128 | + if (!qpdf) { | |
| 2129 | + throw std::move(e); | |
| 2130 | + } | |
| 2131 | + qpdf->warn(std::move(e)); | |
| 2132 | +} | |
| 2133 | + | |
| 2134 | +void | |
| 2135 | +BaseHandle::warn(QPDFExc&& e) const | |
| 2136 | +{ | |
| 2137 | + if (!qpdf()) { | |
| 2138 | + throw std::move(e); | |
| 2139 | + } | |
| 2140 | + qpdf()->warn(std::move(e)); | |
| 2141 | +} | |
| 2142 | + | |
| 2143 | +void | |
| 2144 | +BaseHandle::warn(std::string const& warning) const | |
| 2145 | +{ | |
| 2146 | + if (qpdf()) { | |
| 2147 | + warn({qpdf_e_damaged_pdf, "", description(), 0, warning}); | |
| 2140 | 2148 | } else { |
| 2141 | - throw e; | |
| 2149 | + *QPDFLogger::defaultLogger()->getError() << warning << "\n"; | |
| 2142 | 2150 | } |
| 2143 | 2151 | } |
| 2144 | 2152 | ... | ... |
libqpdf/QPDFOutlineObjectHelper.cc
| ... | ... | @@ -75,7 +75,7 @@ QPDFObjectHandle |
| 75 | 75 | QPDFOutlineObjectHelper::getDestPage() |
| 76 | 76 | { |
| 77 | 77 | QPDFObjectHandle dest = getDest(); |
| 78 | - if ((dest.isArray()) && (dest.getArrayNItems() > 0)) { | |
| 78 | + if (!dest.empty() && dest.isArray()) { | |
| 79 | 79 | return dest.getArrayItem(0); |
| 80 | 80 | } |
| 81 | 81 | return QPDFObjectHandle::newNull(); | ... | ... |
libqpdf/QPDFPageDocumentHelper.cc
| ... | ... | @@ -59,7 +59,7 @@ QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_fla |
| 59 | 59 | if (afdh.getNeedAppearances()) { |
| 60 | 60 | qpdf.getRoot() |
| 61 | 61 | .getKey("/AcroForm") |
| 62 | - .warnIfPossible( | |
| 62 | + .warn( | |
| 63 | 63 | "document does not have updated appearance streams, so form fields " |
| 64 | 64 | "will not be flattened"); |
| 65 | 65 | } | ... | ... |
libqpdf/QPDFPageObjectHelper.cc
| ... | ... | @@ -12,6 +12,8 @@ |
| 12 | 12 | #include <qpdf/QUtil.hh> |
| 13 | 13 | #include <qpdf/ResourceFinder.hh> |
| 14 | 14 | |
| 15 | +using namespace std::literals; | |
| 16 | + | |
| 15 | 17 | namespace |
| 16 | 18 | { |
| 17 | 19 | class ContentProvider: public QPDFObjectHandle::StreamDataProvider |
| ... | ... | @@ -118,7 +120,7 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) |
| 118 | 120 | QTC::TC("qpdf", "QPDFPageObjectHelper colorspace lookup"); |
| 119 | 121 | value = colorspace.getKey(name); |
| 120 | 122 | } else { |
| 121 | - resources.warnIfPossible("unable to resolve colorspace " + name); | |
| 123 | + resources.warn("unable to resolve colorspace " + name); | |
| 122 | 124 | } |
| 123 | 125 | name.clear(); |
| 124 | 126 | } |
| ... | ... | @@ -414,8 +416,8 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) |
| 414 | 416 | filterContents(&iit, &b); |
| 415 | 417 | filtered = true; |
| 416 | 418 | } catch (std::exception& e) { |
| 417 | - oh().warnIfPossible( | |
| 418 | - std::string("Unable to filter content stream: ") + e.what() + | |
| 419 | + warn( | |
| 420 | + "Unable to filter content stream: "s + e.what() + | |
| 419 | 421 | "; not attempting to externalize inline images from this stream"); |
| 420 | 422 | } |
| 421 | 423 | if (filtered && iit.any_images) { |
| ... | ... | @@ -443,14 +445,9 @@ std::vector<QPDFAnnotationObjectHelper> |
| 443 | 445 | QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) |
| 444 | 446 | { |
| 445 | 447 | std::vector<QPDFAnnotationObjectHelper> result; |
| 446 | - QPDFObjectHandle annots = oh().getKey("/Annots"); | |
| 447 | - if (annots.isArray()) { | |
| 448 | - int nannots = annots.getArrayNItems(); | |
| 449 | - for (int i = 0; i < nannots; ++i) { | |
| 450 | - QPDFObjectHandle annot = annots.getArrayItem(i); | |
| 451 | - if (annot.isDictionaryOfType("", only_subtype)) { | |
| 452 | - result.emplace_back(annot); | |
| 453 | - } | |
| 448 | + for (auto const& annot: oh().getKey("/Annots").as_array()) { | |
| 449 | + if (annot.isDictionaryOfType("", only_subtype)) { | |
| 450 | + result.emplace_back(annot); | |
| 454 | 451 | } |
| 455 | 452 | } |
| 456 | 453 | return result; |
| ... | ... | @@ -555,15 +552,15 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( |
| 555 | 552 | ph.parseContents(&rf); |
| 556 | 553 | size_t after_nw = (q ? q->numWarnings() : 0); |
| 557 | 554 | if (after_nw > before_nw) { |
| 558 | - ph.oh().warnIfPossible( | |
| 555 | + ph.warn( | |
| 559 | 556 | "Bad token found while scanning content stream; " |
| 560 | 557 | "not attempting to remove unreferenced objects from this object"); |
| 561 | 558 | return false; |
| 562 | 559 | } |
| 563 | 560 | } catch (std::exception& e) { |
| 564 | 561 | QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names"); |
| 565 | - ph.oh().warnIfPossible( | |
| 566 | - std::string("Unable to parse content stream: ") + e.what() + | |
| 562 | + ph.warn( | |
| 563 | + "Unable to parse content stream: "s + e.what() + | |
| 567 | 564 | "; not attempting to remove unreferenced objects from this object"); |
| 568 | 565 | return false; |
| 569 | 566 | } |
| ... | ... | @@ -719,8 +716,7 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) |
| 719 | 716 | newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); |
| 720 | 717 | QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); |
| 721 | 718 | if (!bbox.isRectangle()) { |
| 722 | - oh().warnIfPossible( | |
| 723 | - "bounding box is invalid; form XObject created from page will not work"); | |
| 719 | + warn("bounding box is invalid; form XObject created from page will not work"); | |
| 724 | 720 | } |
| 725 | 721 | newdict.replaceKey("/BBox", bbox); |
| 726 | 722 | auto provider = | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -1396,8 +1396,8 @@ QPDFWriter::willFilterStream( |
| 1396 | 1396 | } |
| 1397 | 1397 | } catch (std::runtime_error& e) { |
| 1398 | 1398 | if (filter && first_attempt) { |
| 1399 | - stream.warnIfPossible("error while getting stream data: "s + e.what()); | |
| 1400 | - stream.warnIfPossible("qpdf will attempt to write the damaged stream unchanged"); | |
| 1399 | + stream.warn("error while getting stream data: "s + e.what()); | |
| 1400 | + stream.warn("qpdf will attempt to write the damaged stream unchanged"); | |
| 1401 | 1401 | filter = false; |
| 1402 | 1402 | stream.setFilterOnWrite(false); |
| 1403 | 1403 | continue; |
| ... | ... | @@ -1538,9 +1538,7 @@ QPDFWriter::unparseObject( |
| 1538 | 1538 | object.removeKey("/Length"); |
| 1539 | 1539 | |
| 1540 | 1540 | // If /DecodeParms is an empty list, remove it. |
| 1541 | - if (object.getKey("/DecodeParms").isArray() && | |
| 1542 | - (0 == object.getKey("/DecodeParms").getArrayNItems())) { | |
| 1543 | - QTC::TC("qpdf", "QPDFWriter remove empty DecodeParms"); | |
| 1541 | + if (object.getKey("/DecodeParms").empty()) { | |
| 1544 | 1542 | object.removeKey("/DecodeParms"); |
| 1545 | 1543 | } |
| 1546 | 1544 | |
| ... | ... | @@ -1558,22 +1556,19 @@ QPDFWriter::unparseObject( |
| 1558 | 1556 | object.removeKey("/Filter"); |
| 1559 | 1557 | object.removeKey("/DecodeParms"); |
| 1560 | 1558 | } else { |
| 1561 | - int idx = -1; | |
| 1562 | - for (int i = 0; i < filter.getArrayNItems(); ++i) { | |
| 1563 | - QPDFObjectHandle item = filter.getArrayItem(i); | |
| 1559 | + int idx = 0; | |
| 1560 | + for (auto const& item: filter.as_array()) { | |
| 1564 | 1561 | if (item.isNameAndEquals("/Crypt")) { |
| 1565 | - idx = i; | |
| 1562 | + // If filter is an array, then the code in QPDF_Stream has already | |
| 1563 | + // verified that DecodeParms and Filters are arrays of the same | |
| 1564 | + // length, but if they weren't for some reason, eraseItem does type | |
| 1565 | + // and bounds checking. Fuzzing tells us that this can actually | |
| 1566 | + // happen. | |
| 1567 | + filter.eraseItem(idx); | |
| 1568 | + decode_parms.eraseItem(idx); | |
| 1566 | 1569 | break; |
| 1567 | 1570 | } |
| 1568 | - } | |
| 1569 | - if (idx >= 0) { | |
| 1570 | - // If filter is an array, then the code in QPDF_Stream has already | |
| 1571 | - // verified that DecodeParms and Filters are arrays of the same length, | |
| 1572 | - // but if they weren't for some reason, eraseItem does type and bounds | |
| 1573 | - // checking. | |
| 1574 | - QTC::TC("qpdf", "QPDFWriter remove Crypt"); | |
| 1575 | - filter.eraseItem(idx); | |
| 1576 | - decode_parms.eraseItem(idx); | |
| 1571 | + ++idx; | |
| 1577 | 1572 | } |
| 1578 | 1573 | } |
| 1579 | 1574 | } |
| ... | ... | @@ -1742,7 +1737,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1742 | 1737 | if (obj_to_write.isStream()) { |
| 1743 | 1738 | // This condition occurred in a fuzz input. Ideally we should block it at parse |
| 1744 | 1739 | // time, but it's not clear to me how to construct a case for this. |
| 1745 | - obj_to_write.warnIfPossible("stream found inside object stream; treating as null"); | |
| 1740 | + obj_to_write.warn("stream found inside object stream; treating as null"); | |
| 1746 | 1741 | obj_to_write = QPDFObjectHandle::newNull(); |
| 1747 | 1742 | } |
| 1748 | 1743 | writeObject(obj_to_write, count); |
| ... | ... | @@ -1965,7 +1960,7 @@ QPDFWriter::initializeSpecialStreams() |
| 1965 | 1960 | QPDFObjectHandle contents = page.getKey("/Contents"); |
| 1966 | 1961 | std::vector<QPDFObjGen> contents_objects; |
| 1967 | 1962 | if (contents.isArray()) { |
| 1968 | - int n = contents.getArrayNItems(); | |
| 1963 | + int n = static_cast<int>(contents.size()); | |
| 1969 | 1964 | for (int i = 0; i < n; ++i) { |
| 1970 | 1965 | contents_objects.push_back(contents.getArrayItem(i).getObjGen()); |
| 1971 | 1966 | } | ... | ... |
libqpdf/QPDF_Array.cc
| ... | ... | @@ -2,11 +2,25 @@ |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/QTC.hh> |
| 4 | 4 | |
| 5 | +#include <utility> | |
| 6 | + | |
| 5 | 7 | using namespace std::literals; |
| 6 | 8 | using namespace qpdf; |
| 7 | 9 | |
| 8 | 10 | static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); |
| 9 | 11 | |
| 12 | +static size_t | |
| 13 | +to_s(int n) | |
| 14 | +{ | |
| 15 | + return static_cast<size_t>(n); | |
| 16 | +} | |
| 17 | + | |
| 18 | +static int | |
| 19 | +to_i(size_t n) | |
| 20 | +{ | |
| 21 | + return static_cast<int>(n); | |
| 22 | +} | |
| 23 | + | |
| 10 | 24 | inline void |
| 11 | 25 | Array::checkOwnership(QPDFObjectHandle const& item) const |
| 12 | 26 | { |
| ... | ... | @@ -142,24 +156,24 @@ Array::null() const |
| 142 | 156 | return null_oh; |
| 143 | 157 | } |
| 144 | 158 | |
| 145 | -int | |
| 159 | +size_t | |
| 146 | 160 | Array::size() const |
| 147 | 161 | { |
| 148 | 162 | auto a = array(); |
| 149 | - return a->sp ? a->sp->size : int(a->elements.size()); | |
| 163 | + return a->sp ? a->sp->size : a->elements.size(); | |
| 150 | 164 | } |
| 151 | 165 | |
| 152 | 166 | std::pair<bool, QPDFObjectHandle> |
| 153 | 167 | Array::at(int n) const |
| 154 | 168 | { |
| 155 | 169 | auto a = array(); |
| 156 | - if (n < 0 || n >= size()) { | |
| 170 | + if (n < 0 || std::cmp_greater_equal(n, size())) { | |
| 157 | 171 | return {false, {}}; |
| 158 | 172 | } |
| 159 | 173 | if (!a->sp) { |
| 160 | - return {true, a->elements[size_t(n)]}; | |
| 174 | + return {true, a->elements[to_s(n)]}; | |
| 161 | 175 | } |
| 162 | - auto const& iter = a->sp->elements.find(n); | |
| 176 | + auto const& iter = a->sp->elements.find(to_s(n)); | |
| 163 | 177 | return {true, iter == a->sp->elements.end() ? null() : iter->second}; |
| 164 | 178 | } |
| 165 | 179 | |
| ... | ... | @@ -169,12 +183,12 @@ Array::getAsVector() const |
| 169 | 183 | auto a = array(); |
| 170 | 184 | if (a->sp) { |
| 171 | 185 | std::vector<QPDFObjectHandle> v; |
| 172 | - v.reserve(size_t(size())); | |
| 186 | + v.reserve(size()); | |
| 173 | 187 | for (auto const& item: a->sp->elements) { |
| 174 | - v.resize(size_t(item.first), null_oh); | |
| 188 | + v.resize(item.first, null_oh); | |
| 175 | 189 | v.emplace_back(item.second); |
| 176 | 190 | } |
| 177 | - v.resize(size_t(size()), null_oh); | |
| 191 | + v.resize(size(), null_oh); | |
| 178 | 192 | return v; |
| 179 | 193 | } else { |
| 180 | 194 | return a->elements; |
| ... | ... | @@ -184,15 +198,15 @@ Array::getAsVector() const |
| 184 | 198 | bool |
| 185 | 199 | Array::setAt(int at, QPDFObjectHandle const& oh) |
| 186 | 200 | { |
| 187 | - if (at < 0 || at >= size()) { | |
| 201 | + if (at < 0 || std::cmp_greater_equal(at, size())) { | |
| 188 | 202 | return false; |
| 189 | 203 | } |
| 190 | 204 | auto a = array(); |
| 191 | 205 | checkOwnership(oh); |
| 192 | 206 | if (a->sp) { |
| 193 | - a->sp->elements[at] = oh; | |
| 207 | + a->sp->elements[to_s(at)] = oh; | |
| 194 | 208 | } else { |
| 195 | - a->elements[size_t(at)] = oh; | |
| 209 | + a->elements[to_s(at)] = oh; | |
| 196 | 210 | } |
| 197 | 211 | return true; |
| 198 | 212 | } |
| ... | ... | @@ -210,34 +224,39 @@ Array::setFromVector(std::vector<QPDFObjectHandle> const& v) |
| 210 | 224 | } |
| 211 | 225 | |
| 212 | 226 | bool |
| 213 | -Array::insert(int at, QPDFObjectHandle const& item) | |
| 227 | +Array::insert(int at_i, QPDFObjectHandle const& item) | |
| 214 | 228 | { |
| 215 | 229 | auto a = array(); |
| 216 | - int sz = size(); | |
| 217 | - if (at < 0 || at > sz) { | |
| 218 | - // As special case, also allow insert beyond the end | |
| 230 | + size_t sz = size(); | |
| 231 | + if (at_i < 0) { | |
| 232 | + return false; | |
| 233 | + } | |
| 234 | + size_t at = to_s(at_i); | |
| 235 | + if (at > sz) { | |
| 219 | 236 | return false; |
| 220 | - } else if (at == sz) { | |
| 237 | + } | |
| 238 | + if (at == sz) { | |
| 239 | + // As special case, also allow insert beyond the end | |
| 221 | 240 | push_back(item); |
| 222 | - } else { | |
| 223 | - checkOwnership(item); | |
| 224 | - if (a->sp) { | |
| 225 | - auto iter = a->sp->elements.crbegin(); | |
| 226 | - while (iter != a->sp->elements.crend()) { | |
| 227 | - auto key = (iter++)->first; | |
| 228 | - if (key >= at) { | |
| 229 | - auto nh = a->sp->elements.extract(key); | |
| 230 | - ++nh.key(); | |
| 231 | - a->sp->elements.insert(std::move(nh)); | |
| 232 | - } else { | |
| 233 | - break; | |
| 234 | - } | |
| 241 | + return true; | |
| 242 | + } | |
| 243 | + checkOwnership(item); | |
| 244 | + if (a->sp) { | |
| 245 | + auto iter = a->sp->elements.crbegin(); | |
| 246 | + while (iter != a->sp->elements.crend()) { | |
| 247 | + auto key = (iter++)->first; | |
| 248 | + if (key >= at) { | |
| 249 | + auto nh = a->sp->elements.extract(key); | |
| 250 | + ++nh.key(); | |
| 251 | + a->sp->elements.insert(std::move(nh)); | |
| 252 | + } else { | |
| 253 | + break; | |
| 235 | 254 | } |
| 236 | - a->sp->elements[at] = item.getObj(); | |
| 237 | - ++a->sp->size; | |
| 238 | - } else { | |
| 239 | - a->elements.insert(a->elements.cbegin() + at, item.getObj()); | |
| 240 | 255 | } |
| 256 | + a->sp->elements[at] = item.getObj(); | |
| 257 | + ++a->sp->size; | |
| 258 | + } else { | |
| 259 | + a->elements.insert(a->elements.cbegin() + at_i, item.getObj()); | |
| 241 | 260 | } |
| 242 | 261 | return true; |
| 243 | 262 | } |
| ... | ... | @@ -255,10 +274,14 @@ Array::push_back(QPDFObjectHandle const& item) |
| 255 | 274 | } |
| 256 | 275 | |
| 257 | 276 | bool |
| 258 | -Array::erase(int at) | |
| 277 | +Array::erase(int at_i) | |
| 259 | 278 | { |
| 260 | 279 | auto a = array(); |
| 261 | - if (at < 0 || at >= size()) { | |
| 280 | + if (at_i < 0) { | |
| 281 | + return false; | |
| 282 | + } | |
| 283 | + size_t at = to_s(at_i); | |
| 284 | + if (at >= size()) { | |
| 262 | 285 | return false; |
| 263 | 286 | } |
| 264 | 287 | if (a->sp) { |
| ... | ... | @@ -277,7 +300,7 @@ Array::erase(int at) |
| 277 | 300 | } |
| 278 | 301 | --(a->sp->size); |
| 279 | 302 | } else { |
| 280 | - a->elements.erase(a->elements.cbegin() + at); | |
| 303 | + a->elements.erase(a->elements.cbegin() + at_i); | |
| 281 | 304 | } |
| 282 | 305 | return true; |
| 283 | 306 | } |
| ... | ... | @@ -286,7 +309,7 @@ int |
| 286 | 309 | QPDFObjectHandle::getArrayNItems() const |
| 287 | 310 | { |
| 288 | 311 | if (auto array = as_array(strict)) { |
| 289 | - return array.size(); | |
| 312 | + return to_i(array.size()); | |
| 290 | 313 | } |
| 291 | 314 | typeWarning("array", "treating as empty"); |
| 292 | 315 | QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); |
| ... | ... | @@ -471,7 +494,37 @@ QPDFObjectHandle |
| 471 | 494 | QPDFObjectHandle::eraseItemAndGetOld(int at) |
| 472 | 495 | { |
| 473 | 496 | auto array = as_array(strict); |
| 474 | - auto result = (array && at < array.size() && at >= 0) ? array.at(at).second : newNull(); | |
| 497 | + auto result = | |
| 498 | + (array && std::cmp_less(at, array.size()) && at >= 0) ? array.at(at).second : newNull(); | |
| 475 | 499 | eraseItem(at); |
| 476 | 500 | return result; |
| 477 | 501 | } |
| 502 | + | |
| 503 | +size_t | |
| 504 | +BaseHandle::size() const | |
| 505 | +{ | |
| 506 | + switch (resolved_type_code()) { | |
| 507 | + case ::ot_array: | |
| 508 | + return as<QPDF_Array>()->size(); | |
| 509 | + case ::ot_uninitialized: | |
| 510 | + case ::ot_reserved: | |
| 511 | + case ::ot_null: | |
| 512 | + case ::ot_destroyed: | |
| 513 | + case ::ot_unresolved: | |
| 514 | + case ::ot_reference: | |
| 515 | + return 0; | |
| 516 | + case ::ot_boolean: | |
| 517 | + case ::ot_integer: | |
| 518 | + case ::ot_real: | |
| 519 | + case ::ot_string: | |
| 520 | + case ::ot_name: | |
| 521 | + case ::ot_dictionary: | |
| 522 | + case ::ot_stream: | |
| 523 | + case ::ot_inlineimage: | |
| 524 | + case ::ot_operator: | |
| 525 | + return 1; | |
| 526 | + default: | |
| 527 | + throw std::logic_error("Unexpected type code in size"); // unreachable | |
| 528 | + return 0; // unreachable | |
| 529 | + } | |
| 530 | +} | ... | ... |
libqpdf/QPDF_encryption.cc
| ... | ... | @@ -664,7 +664,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) |
| 664 | 664 | |
| 665 | 665 | std::string id1; |
| 666 | 666 | auto id_obj = trailer.getKey("/ID"); |
| 667 | - if (!id_obj.isArray() || id_obj.getArrayNItems() != 2 || !id_obj.getArrayItem(0).isString()) { | |
| 667 | + if (id_obj.size() != 2 || !id_obj.getArrayItem(0).isString()) { | |
| 668 | 668 | // Treating a missing ID as the empty string enables qpdf to decrypt some invalid encrypted |
| 669 | 669 | // files with no /ID that poppler can read but Adobe Reader can't. |
| 670 | 670 | qpdf.warn(qpdf.damagedPDF("trailer", "invalid /ID in trailer dictionary")); |
| ... | ... | @@ -961,19 +961,21 @@ QPDF::decryptStream( |
| 961 | 961 | } else if ( |
| 962 | 962 | stream_dict.getKey("/DecodeParms").isArray() && |
| 963 | 963 | stream_dict.getKey("/Filter").isArray()) { |
| 964 | - QPDFObjectHandle filter = stream_dict.getKey("/Filter"); | |
| 965 | - QPDFObjectHandle decode = stream_dict.getKey("/DecodeParms"); | |
| 966 | - if (filter.getArrayNItems() == decode.getArrayNItems()) { | |
| 967 | - for (int i = 0; i < filter.getArrayNItems(); ++i) { | |
| 968 | - if (filter.getArrayItem(i).isNameAndEquals("/Crypt")) { | |
| 969 | - QPDFObjectHandle crypt_params = decode.getArrayItem(i); | |
| 964 | + auto filter = stream_dict.getKey("/Filter"); | |
| 965 | + auto decode = stream_dict.getKey("/DecodeParms"); | |
| 966 | + if (filter.size() == decode.size()) { | |
| 967 | + int i = 0; | |
| 968 | + for (auto const& item: filter.as_array()) { | |
| 969 | + if (item.isNameAndEquals("/Crypt")) { | |
| 970 | + auto crypt_params = decode.getArrayItem(i); | |
| 970 | 971 | if (crypt_params.isDictionary() && |
| 971 | 972 | crypt_params.getKey("/Name").isName()) { |
| 972 | - QTC::TC("qpdf", "QPDF_encrypt crypt array"); | |
| 973 | 973 | method = encp->interpretCF(crypt_params.getKey("/Name")); |
| 974 | 974 | method_source = "stream's Crypt decode parameters (array)"; |
| 975 | 975 | } |
| 976 | + break; | |
| 976 | 977 | } |
| 978 | + ++i; | |
| 977 | 979 | } |
| 978 | 980 | } |
| 979 | 981 | } | ... | ... |
libqpdf/QPDF_linearization.cc
| ... | ... | @@ -174,14 +174,13 @@ QPDF::readLinearizationData() |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | 176 | // Hint table array: offset length [ offset length ] |
| 177 | - size_t n_H_items = toS(H.getArrayNItems()); | |
| 178 | - if (!((n_H_items == 2) || (n_H_items == 4))) { | |
| 177 | + size_t n_H_items = H.size(); | |
| 178 | + if (!(n_H_items == 2 || n_H_items == 4)) { | |
| 179 | 179 | throw damagedPDF("linearization dictionary", "H has the wrong number of items"); |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | 182 | std::vector<int> H_items; |
| 183 | - for (size_t i = 0; i < n_H_items; ++i) { | |
| 184 | - QPDFObjectHandle oh(H.getArrayItem(toI(i))); | |
| 183 | + for (auto const& oh: H.as_array()) { | |
| 185 | 184 | if (oh.isInteger()) { |
| 186 | 185 | H_items.push_back(oh.getIntValueAsInt()); |
| 187 | 186 | } else { | ... | ... |
libqpdf/QPDF_objects.cc
| ... | ... | @@ -782,7 +782,7 @@ std::pair<int, std::array<int, 3>> |
| 782 | 782 | QPDF::processXRefW(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged) |
| 783 | 783 | { |
| 784 | 784 | auto W_obj = dict.getKey("/W"); |
| 785 | - if (!(W_obj.isArray() && (W_obj.getArrayNItems() >= 3) && W_obj.getArrayItem(0).isInteger() && | |
| 785 | + if (!(W_obj.size() >= 3 && W_obj.getArrayItem(0).isInteger() && | |
| 786 | 786 | W_obj.getArrayItem(1).isInteger() && W_obj.getArrayItem(2).isInteger())) { |
| 787 | 787 | throw damaged("Cross-reference stream does not have a proper /W key"); |
| 788 | 788 | } | ... | ... |
libqpdf/QPDF_pages.cc
| ... | ... | @@ -57,7 +57,7 @@ QPDF::getAllPages() |
| 57 | 57 | // Files have been found in the wild where /Pages in the catalog points to the first |
| 58 | 58 | // page. Try to work around this and similar cases with this heuristic. |
| 59 | 59 | if (!warned) { |
| 60 | - root.warnIfPossible( | |
| 60 | + root.warn( | |
| 61 | 61 | "document page tree root (root -> /Pages) doesn't point" |
| 62 | 62 | " to the root of the page tree; attempting to correct"); |
| 63 | 63 | warned = true; |
| ... | ... | @@ -109,7 +109,7 @@ QPDF::getAllPagesInternal( |
| 109 | 109 | // During fuzzing files were encountered where the root object appeared in the pages tree. |
| 110 | 110 | // Unconditionally setting the /Type to /Pages could cause problems, but trying to |
| 111 | 111 | // accommodate the possibility may be excessive. |
| 112 | - cur_node.warnIfPossible("/Type key should be /Pages but is not; overriding"); | |
| 112 | + cur_node.warn("/Type key should be /Pages but is not; overriding"); | |
| 113 | 113 | cur_node.replaceKey("/Type", "/Pages"_qpdf); |
| 114 | 114 | } |
| 115 | 115 | if (!media_box) { |
| ... | ... | @@ -134,13 +134,13 @@ QPDF::getAllPagesInternal( |
| 134 | 134 | int errors = 0; |
| 135 | 135 | |
| 136 | 136 | if (!kid.isDictionary()) { |
| 137 | - kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring"); | |
| 137 | + kid.warn("Pages tree includes non-dictionary object; ignoring"); | |
| 138 | 138 | m->invalid_page_found = true; |
| 139 | 139 | continue; |
| 140 | 140 | } |
| 141 | 141 | if (!kid.isIndirect()) { |
| 142 | 142 | QTC::TC("qpdf", "QPDF handle direct page object"); |
| 143 | - cur_node.warnIfPossible( | |
| 143 | + cur_node.warn( | |
| 144 | 144 | "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); |
| 145 | 145 | kid = makeIndirectObject(kid); |
| 146 | 146 | ++errors; |
| ... | ... | @@ -150,7 +150,7 @@ QPDF::getAllPagesInternal( |
| 150 | 150 | } else { |
| 151 | 151 | if (!media_box && !kid.getKey("/MediaBox").isRectangle()) { |
| 152 | 152 | QTC::TC("qpdf", "QPDF missing mediabox"); |
| 153 | - kid.warnIfPossible( | |
| 153 | + kid.warn( | |
| 154 | 154 | "kid " + std::to_string(i) + |
| 155 | 155 | " (from 0) MediaBox is undefined; setting to letter / ANSI A"); |
| 156 | 156 | kid.replaceKey( |
| ... | ... | @@ -167,7 +167,7 @@ QPDF::getAllPagesInternal( |
| 167 | 167 | // QPDFPageObjectHelper. |
| 168 | 168 | QTC::TC("qpdf", "QPDF resolve duplicated page object"); |
| 169 | 169 | if (!m->reconstructed_xref) { |
| 170 | - cur_node.warnIfPossible( | |
| 170 | + cur_node.warn( | |
| 171 | 171 | "kid " + std::to_string(i) + |
| 172 | 172 | " (from 0) appears more than once in the pages tree;" |
| 173 | 173 | " creating a new page object as a copy"); |
| ... | ... | @@ -176,7 +176,7 @@ QPDF::getAllPagesInternal( |
| 176 | 176 | kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); |
| 177 | 177 | seen.add(kid); |
| 178 | 178 | } else { |
| 179 | - cur_node.warnIfPossible( | |
| 179 | + cur_node.warn( | |
| 180 | 180 | "kid " + std::to_string(i) + |
| 181 | 181 | " (from 0) appears more than once in the pages tree; ignoring duplicate"); |
| 182 | 182 | m->invalid_page_found = true; |
| ... | ... | @@ -189,12 +189,12 @@ QPDF::getAllPagesInternal( |
| 189 | 189 | } |
| 190 | 190 | } |
| 191 | 191 | if (!kid.isDictionaryOfType("/Page")) { |
| 192 | - kid.warnIfPossible("/Type key should be /Page but is not; overriding"); | |
| 192 | + kid.warn("/Type key should be /Page but is not; overriding"); | |
| 193 | 193 | kid.replaceKey("/Type", "/Page"_qpdf); |
| 194 | 194 | ++errors; |
| 195 | 195 | } |
| 196 | 196 | if (m->reconstructed_xref && errors > 2) { |
| 197 | - cur_node.warnIfPossible( | |
| 197 | + cur_node.warn( | |
| 198 | 198 | "kid " + std::to_string(i) + " (from 0) has too many errors; ignoring page"); |
| 199 | 199 | m->invalid_page_found = true; |
| 200 | 200 | kid = QPDFObjectHandle::newNull(); |
| ... | ... | @@ -313,7 +313,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) |
| 313 | 313 | |
| 314 | 314 | newpage.replaceKey("/Parent", pages); |
| 315 | 315 | kids.insertItem(pos, newpage); |
| 316 | - int npages = kids.getArrayNItems(); | |
| 316 | + int npages = static_cast<int>(kids.size()); | |
| 317 | 317 | pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); |
| 318 | 318 | m->all_pages.insert(m->all_pages.begin() + pos, newpage); |
| 319 | 319 | for (int i = pos + 1; i < npages; ++i) { |
| ... | ... | @@ -337,7 +337,7 @@ QPDF::removePage(QPDFObjectHandle page) |
| 337 | 337 | QPDFObjectHandle kids = pages.getKey("/Kids"); |
| 338 | 338 | |
| 339 | 339 | kids.eraseItem(pos); |
| 340 | - int npages = kids.getArrayNItems(); | |
| 340 | + int npages = static_cast<int>(kids.size()); | |
| 341 | 341 | pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); |
| 342 | 342 | m->all_pages.erase(m->all_pages.begin() + pos); |
| 343 | 343 | m->pageobj_to_pages_pos.erase(page.getObjGen()); | ... | ... |
libqpdf/qpdf/QPDFObjectHandle_private.hh
| ... | ... | @@ -38,7 +38,7 @@ namespace qpdf |
| 38 | 38 | |
| 39 | 39 | const_reverse_iterator crend(); |
| 40 | 40 | |
| 41 | - int size() const; | |
| 41 | + size_t size() const; | |
| 42 | 42 | std::pair<bool, QPDFObjectHandle> at(int n) const; |
| 43 | 43 | bool setAt(int at, QPDFObjectHandle const& oh); |
| 44 | 44 | bool insert(int at, QPDFObjectHandle const& item); | ... | ... |
libqpdf/qpdf/QPDFObject_private.hh
| ... | ... | @@ -35,8 +35,8 @@ class QPDF_Array final |
| 35 | 35 | private: |
| 36 | 36 | struct Sparse |
| 37 | 37 | { |
| 38 | - int size{0}; | |
| 39 | - std::map<int, QPDFObjectHandle> elements; | |
| 38 | + size_t size{0}; | |
| 39 | + std::map<size_t, QPDFObjectHandle> elements; | |
| 40 | 40 | }; |
| 41 | 41 | |
| 42 | 42 | public: |
| ... | ... | @@ -65,10 +65,10 @@ class QPDF_Array final |
| 65 | 65 | { |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | - int | |
| 68 | + size_t | |
| 69 | 69 | size() const |
| 70 | 70 | { |
| 71 | - return sp ? sp->size : int(elements.size()); | |
| 71 | + return sp ? sp->size : elements.size(); | |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | std::unique_ptr<Sparse> sp; |
| ... | ... | @@ -434,13 +434,6 @@ class QPDFObject |
| 434 | 434 | parsed_offset = offset; |
| 435 | 435 | } |
| 436 | 436 | } |
| 437 | - bool | |
| 438 | - getDescription(QPDF*& a_qpdf, std::string& description) | |
| 439 | - { | |
| 440 | - a_qpdf = qpdf; | |
| 441 | - description = getDescription(); | |
| 442 | - return qpdf != nullptr; | |
| 443 | - } | |
| 444 | 437 | qpdf_offset_t |
| 445 | 438 | getParsedOffset() |
| 446 | 439 | { | ... | ... |
libtests/sparse_array.cc
| ... | ... | @@ -7,6 +7,12 @@ |
| 7 | 7 | #include <iostream> |
| 8 | 8 | |
| 9 | 9 | int |
| 10 | +to_i(size_t n) | |
| 11 | +{ | |
| 12 | + return static_cast<int>(n); | |
| 13 | +} | |
| 14 | + | |
| 15 | +int | |
| 10 | 16 | main() |
| 11 | 17 | { |
| 12 | 18 | auto obj = QPDFObject::create<QPDF_Array>(std::vector<QPDFObjectHandle>(), true); |
| ... | ... | @@ -65,20 +71,20 @@ main() |
| 65 | 71 | a.setAt(4, QPDFObjectHandle::newNull()); |
| 66 | 72 | assert(a.at(4).second.isNull()); |
| 67 | 73 | |
| 68 | - a.erase(a.size() - 1); | |
| 74 | + a.erase(to_i(a.size()) - 1); | |
| 69 | 75 | assert(a.size() == 5); |
| 70 | 76 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); |
| 71 | 77 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); |
| 72 | 78 | assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); |
| 73 | 79 | assert(a.at(4).second.isNull()); |
| 74 | 80 | |
| 75 | - a.erase(a.size() - 1); | |
| 81 | + a.erase(to_i(a.size()) - 1); | |
| 76 | 82 | assert(a.size() == 4); |
| 77 | 83 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); |
| 78 | 84 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); |
| 79 | 85 | assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); |
| 80 | 86 | |
| 81 | - a.erase(a.size() - 1); | |
| 87 | + a.erase(to_i(a.size()) - 1); | |
| 82 | 88 | assert(a.size() == 3); |
| 83 | 89 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); |
| 84 | 90 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -237,9 +237,7 @@ QPDFWriter remove ADBE 0 |
| 237 | 237 | QPDFWriter remove existing Extensions 0 |
| 238 | 238 | QPDFWriter preserve ADBE 0 |
| 239 | 239 | QPDF_encryption skip 0x28 0 |
| 240 | -QPDF_encrypt crypt array 0 | |
| 241 | 240 | QPDF_encryption CFM AESV3 0 |
| 242 | -QPDFWriter remove Crypt 0 | |
| 243 | 241 | qpdf-c called qpdf_get_pdf_extension_level 0 |
| 244 | 242 | qpdf-c called qpdf_set_r5_encryption_parameters 0 |
| 245 | 243 | qpdf-c called qpdf_set_r6_encryption_parameters 0 |
| ... | ... | @@ -423,12 +421,6 @@ QPDFPageObjectHelper externalize inline image 0 |
| 423 | 421 | QPDFPageObjectHelper keep inline image 0 |
| 424 | 422 | QPDFJob image optimize colorspace 0 |
| 425 | 423 | QPDFJob image optimize bits per component 0 |
| 426 | -QPDFWriter remove empty DecodeParms 0 | |
| 427 | -QPDFObjectHandle uint returning 0 0 | |
| 428 | -QPDFObjectHandle int returning INT_MIN 0 | |
| 429 | -QPDFObjectHandle int returning INT_MAX 0 | |
| 430 | -QPDFObjectHandle uint returning UINT_MAX 0 | |
| 431 | -QPDFObjectHandle uint uint returning 0 0 | |
| 432 | 424 | QPDF xref skipped space 0 |
| 433 | 425 | QPDF eof skipping spaces before xref 1 |
| 434 | 426 | QPDF_encryption user matches owner V < 5 0 |
| ... | ... | @@ -580,9 +572,7 @@ QPDFAcroFormDocumentHelper copy annotation 3 |
| 580 | 572 | QPDFAcroFormDocumentHelper field with parent 3 |
| 581 | 573 | QPDFAcroFormDocumentHelper modify ap matrix 0 |
| 582 | 574 | QPDFJob copy form fields in split_pages 0 |
| 583 | -QPDFJob keep some fields in pages 0 | |
| 584 | 575 | QPDFJob pages keeping field from original 0 |
| 585 | -QPDFJob no more fields in pages 0 | |
| 586 | 576 | QPDFObjectHandle merge reuse 0 |
| 587 | 577 | QPDFObjectHandle merge generate 0 |
| 588 | 578 | QPDFFormFieldObjectHelper get font from /DR 0 |
| ... | ... | @@ -592,7 +582,7 @@ QPDFAcroFormDocumentHelper replaced DA token 0 |
| 592 | 582 | QPDFAcroFormDocumentHelper ap conflict 0 |
| 593 | 583 | QPDFAcroFormDocumentHelper ap rename 0 |
| 594 | 584 | QPDFAcroFormDocumentHelper /DA parse error 0 |
| 595 | -QPDFAcroFormDocumentHelper AP parse error 0 | |
| 585 | +QPDFAcroFormDocumentHelper AP parse error 1 | |
| 596 | 586 | QPDFJob copy fields not this file 0 |
| 597 | 587 | QPDFJob copy fields non-first from orig 0 |
| 598 | 588 | QPDF resolve duplicated page in insert 0 | ... | ... |