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,7 +22,10 @@ | ||
| 22 | 22 | ||
| 23 | #include <qpdf/Constants.h> | 23 | #include <qpdf/Constants.h> |
| 24 | #include <qpdf/DLL.h> | 24 | #include <qpdf/DLL.h> |
| 25 | +#include <qpdf/Types.h> | ||
| 26 | + | ||
| 25 | #include <qpdf/JSON.hh> | 27 | #include <qpdf/JSON.hh> |
| 28 | +#include <qpdf/QPDFExc.hh> | ||
| 26 | #include <qpdf/QPDFObjGen.hh> | 29 | #include <qpdf/QPDFObjGen.hh> |
| 27 | #include <qpdf/Types.h> | 30 | #include <qpdf/Types.h> |
| 28 | 31 | ||
| @@ -58,6 +61,18 @@ namespace qpdf | @@ -58,6 +61,18 @@ namespace qpdf | ||
| 58 | 61 | ||
| 59 | // The rest of the header file is for qpdf internal use only. | 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 | std::shared_ptr<QPDFObject> copy(bool shallow = false) const; | 76 | std::shared_ptr<QPDFObject> copy(bool shallow = false) const; |
| 62 | // Recursively remove association with any QPDF object. This method may only be called | 77 | // Recursively remove association with any QPDF object. This method may only be called |
| 63 | // during final destruction. | 78 | // during final destruction. |
| @@ -71,6 +86,9 @@ namespace qpdf | @@ -71,6 +86,9 @@ namespace qpdf | ||
| 71 | inline qpdf_object_type_e type_code() const; | 86 | inline qpdf_object_type_e type_code() const; |
| 72 | std::string unparse() const; | 87 | std::string unparse() const; |
| 73 | void write_json(int json_version, JSON::Writer& p) const; | 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 | protected: | 93 | protected: |
| 76 | BaseHandle() = default; | 94 | BaseHandle() = default; |
| @@ -87,6 +105,11 @@ namespace qpdf | @@ -87,6 +105,11 @@ namespace qpdf | ||
| 87 | template <typename T> | 105 | template <typename T> |
| 88 | T* as() const; | 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 | std::shared_ptr<QPDFObject> obj; | 113 | std::shared_ptr<QPDFObject> obj; |
| 91 | }; | 114 | }; |
| 92 | 115 |
include/qpdf/QPDFObjectHandle.hh
| @@ -1357,7 +1357,6 @@ class QPDFObjectHandle: public qpdf::BaseHandle | @@ -1357,7 +1357,6 @@ class QPDFObjectHandle: public qpdf::BaseHandle | ||
| 1357 | QPDF* context); | 1357 | QPDF* context); |
| 1358 | std::vector<QPDFObjectHandle> | 1358 | std::vector<QPDFObjectHandle> |
| 1359 | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); | 1359 | arrayOrStreamToStreamArray(std::string const& description, std::string& all_description); |
| 1360 | - static void warn(QPDF*, QPDFExc const&); | ||
| 1361 | void checkOwnership(QPDFObjectHandle const&) const; | 1360 | void checkOwnership(QPDFObjectHandle const&) const; |
| 1362 | }; | 1361 | }; |
| 1363 | 1362 |
libqpdf/QPDFAcroFormDocumentHelper.cc
| @@ -7,7 +7,10 @@ | @@ -7,7 +7,10 @@ | ||
| 7 | #include <qpdf/QUtil.hh> | 7 | #include <qpdf/QUtil.hh> |
| 8 | #include <qpdf/ResourceFinder.hh> | 8 | #include <qpdf/ResourceFinder.hh> |
| 9 | 9 | ||
| 10 | +#include <utility> | ||
| 11 | + | ||
| 10 | using namespace qpdf; | 12 | using namespace qpdf; |
| 13 | +using namespace std::literals; | ||
| 11 | 14 | ||
| 12 | QPDFAcroFormDocumentHelper::QPDFAcroFormDocumentHelper(QPDF& qpdf) : | 15 | QPDFAcroFormDocumentHelper::QPDFAcroFormDocumentHelper(QPDF& qpdf) : |
| 13 | QPDFDocumentHelper(qpdf), | 16 | QPDFDocumentHelper(qpdf), |
| @@ -138,7 +141,7 @@ QPDFAcroFormDocumentHelper::removeFormFields(std::set<QPDFObjGen> const& to_remo | @@ -138,7 +141,7 @@ QPDFAcroFormDocumentHelper::removeFormFields(std::set<QPDFObjGen> const& to_remo | ||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | int i = 0; | 143 | int i = 0; |
| 141 | - while (i < fields.getArrayNItems()) { | 144 | + while (std::cmp_less(i, fields.size())) { |
| 142 | auto field = fields.getArrayItem(i); | 145 | auto field = fields.getArrayItem(i); |
| 143 | if (to_remove.contains(field.getObjGen())) { | 146 | if (to_remove.contains(field.getObjGen())) { |
| 144 | fields.eraseItem(i); | 147 | fields.eraseItem(i); |
| @@ -251,7 +254,7 @@ QPDFAcroFormDocumentHelper::analyze() | @@ -251,7 +254,7 @@ QPDFAcroFormDocumentHelper::analyze() | ||
| 251 | } | 254 | } |
| 252 | } else { | 255 | } else { |
| 253 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); | 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 | fields = QPDFObjectHandle::newArray(); | 258 | fields = QPDFObjectHandle::newArray(); |
| 256 | } | 259 | } |
| 257 | 260 | ||
| @@ -273,9 +276,9 @@ QPDFAcroFormDocumentHelper::analyze() | @@ -273,9 +276,9 @@ QPDFAcroFormDocumentHelper::analyze() | ||
| 273 | // case such as a PDF creator adding a self-contained annotation (merged with the | 276 | // case such as a PDF creator adding a self-contained annotation (merged with the |
| 274 | // field dictionary) to the page's /Annots array and forgetting to also put it in | 277 | // field dictionary) to the page's /Annots array and forgetting to also put it in |
| 275 | // /AcroForm. | 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 | m->annotation_to_field[og] = QPDFFormFieldObjectHelper(annot); | 282 | m->annotation_to_field[og] = QPDFFormFieldObjectHelper(annot); |
| 280 | m->field_to_annotations[og].emplace_back(annot); | 283 | m->field_to_annotations[og].emplace_back(annot); |
| 281 | } | 284 | } |
| @@ -292,16 +295,16 @@ QPDFAcroFormDocumentHelper::traverseField( | @@ -292,16 +295,16 @@ QPDFAcroFormDocumentHelper::traverseField( | ||
| 292 | // could cause stack overflow. | 295 | // could cause stack overflow. |
| 293 | return; | 296 | return; |
| 294 | } | 297 | } |
| 295 | - if (!field.isIndirect()) { | 298 | + if (!field.indirect()) { |
| 296 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper direct field"); | 299 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper direct field"); |
| 297 | - field.warnIfPossible( | 300 | + field.warn( |
| 298 | "encountered a direct object as a field or annotation while " | 301 | "encountered a direct object as a field or annotation while " |
| 299 | "traversing /AcroForm; ignoring field or annotation"); | 302 | "traversing /AcroForm; ignoring field or annotation"); |
| 300 | return; | 303 | return; |
| 301 | } | 304 | } |
| 302 | if (!field.isDictionary()) { | 305 | if (!field.isDictionary()) { |
| 303 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper non-dictionary field"); | 306 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper non-dictionary field"); |
| 304 | - field.warnIfPossible( | 307 | + field.warn( |
| 305 | "encountered a non-dictionary as a field or annotation while" | 308 | "encountered a non-dictionary as a field or annotation while" |
| 306 | " traversing /AcroForm; ignoring field or annotation"); | 309 | " traversing /AcroForm; ignoring field or annotation"); |
| 307 | return; | 310 | return; |
| @@ -309,7 +312,7 @@ QPDFAcroFormDocumentHelper::traverseField( | @@ -309,7 +312,7 @@ QPDFAcroFormDocumentHelper::traverseField( | ||
| 309 | QPDFObjGen og(field.getObjGen()); | 312 | QPDFObjGen og(field.getObjGen()); |
| 310 | if (!visited.add(og)) { | 313 | if (!visited.add(og)) { |
| 311 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper loop"); | 314 | QTC::TC("qpdf", "QPDFAcroFormDocumentHelper loop"); |
| 312 | - field.warnIfPossible("loop detected while traversing /AcroForm"); | 315 | + field.warn("loop detected while traversing /AcroForm"); |
| 313 | return; | 316 | return; |
| 314 | } | 317 | } |
| 315 | 318 | ||
| @@ -375,7 +378,7 @@ QPDFAcroFormDocumentHelper::setNeedAppearances(bool val) | @@ -375,7 +378,7 @@ QPDFAcroFormDocumentHelper::setNeedAppearances(bool val) | ||
| 375 | { | 378 | { |
| 376 | QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm"); | 379 | QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm"); |
| 377 | if (!acroform.isDictionary()) { | 380 | if (!acroform.isDictionary()) { |
| 378 | - qpdf.getRoot().warnIfPossible( | 381 | + qpdf.getRoot().warn( |
| 379 | "ignoring call to QPDFAcroFormDocumentHelper::setNeedAppearances" | 382 | "ignoring call to QPDFAcroFormDocumentHelper::setNeedAppearances" |
| 380 | " on a file that lacks an /AcroForm dictionary"); | 383 | " on a file that lacks an /AcroForm dictionary"); |
| 381 | return; | 384 | return; |
| @@ -592,9 +595,7 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances( | @@ -592,9 +595,7 @@ QPDFAcroFormDocumentHelper::adjustDefaultAppearances( | ||
| 592 | } catch (std::exception& e) { | 595 | } catch (std::exception& e) { |
| 593 | // No way to reproduce in test suite right now since error conditions are converted to | 596 | // No way to reproduce in test suite right now since error conditions are converted to |
| 594 | // warnings. | 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 | return; | 599 | return; |
| 599 | } | 600 | } |
| 600 | 601 | ||
| @@ -677,16 +678,17 @@ QPDFAcroFormDocumentHelper::adjustAppearanceStream( | @@ -677,16 +678,17 @@ QPDFAcroFormDocumentHelper::adjustAppearanceStream( | ||
| 677 | try { | 678 | try { |
| 678 | auto nwarnings = qpdf.numWarnings(); | 679 | auto nwarnings = qpdf.numWarnings(); |
| 679 | stream.parseAsContents(&rf); | 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 | auto rr = new ResourceReplacer(dr_map, rf.getNamesByResourceType()); | 685 | auto rr = new ResourceReplacer(dr_map, rf.getNamesByResourceType()); |
| 684 | auto tf = std::shared_ptr<QPDFObjectHandle::TokenFilter>(rr); | 686 | auto tf = std::shared_ptr<QPDFObjectHandle::TokenFilter>(rr); |
| 685 | stream.addTokenFilter(tf); | 687 | stream.addTokenFilter(tf); |
| 686 | } catch (std::exception& e) { | 688 | } catch (std::exception& e) { |
| 687 | // No way to reproduce in test suite right now since error conditions are converted to | 689 | // No way to reproduce in test suite right now since error conditions are converted to |
| 688 | // warnings. | 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,7 +816,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | ||
| 814 | QPDFObjGen::set added_new_fields; | 816 | QPDFObjGen::set added_new_fields; |
| 815 | for (auto annot: old_annots.aitems()) { | 817 | for (auto annot: old_annots.aitems()) { |
| 816 | if (annot.isStream()) { | 818 | if (annot.isStream()) { |
| 817 | - annot.warnIfPossible("ignoring annotation that's a stream"); | 819 | + annot.warn("ignoring annotation that's a stream"); |
| 818 | continue; | 820 | continue; |
| 819 | } | 821 | } |
| 820 | 822 | ||
| @@ -847,10 +849,10 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | @@ -847,10 +849,10 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | ||
| 847 | bool have_field = false; | 849 | bool have_field = false; |
| 848 | bool have_parent = false; | 850 | bool have_parent = false; |
| 849 | if (ffield_oh.isStream()) { | 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 | } else if ((!ffield_oh.isNull()) && (!ffield_oh.isIndirect())) { | 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 | // A field and its associated annotation can be the same object. This matters because we | 856 | // A field and its associated annotation can be the same object. This matters because we |
| 855 | // don't want to clone the annotation and field separately in this case. | 857 | // don't want to clone the annotation and field separately in this case. |
| 856 | have_field = true; | 858 | have_field = true; |
| @@ -888,7 +890,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | @@ -888,7 +890,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | ||
| 888 | if (orig_to_copy.contains(parent_og)) { | 890 | if (orig_to_copy.contains(parent_og)) { |
| 889 | obj.replaceKey("/Parent", orig_to_copy[parent_og]); | 891 | obj.replaceKey("/Parent", orig_to_copy[parent_og]); |
| 890 | } else { | 892 | } else { |
| 891 | - parent.warnIfPossible( | 893 | + parent.warn( |
| 892 | "while traversing field " + obj.getObjGen().unparse(',') + | 894 | "while traversing field " + obj.getObjGen().unparse(',') + |
| 893 | ", found parent (" + parent_og.unparse(',') + | 895 | ", found parent (" + parent_og.unparse(',') + |
| 894 | ") that had not been seen, indicating likely invalid field " | 896 | ") that had not been seen, indicating likely invalid field " |
| @@ -896,12 +898,13 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | @@ -896,12 +898,13 @@ QPDFAcroFormDocumentHelper::transformAnnotations( | ||
| 896 | } | 898 | } |
| 897 | } | 899 | } |
| 898 | auto kids = obj.getKey("/Kids"); | 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 | auto kid = kids.getArrayItem(i); | 904 | auto kid = kids.getArrayItem(i); |
| 902 | if (maybe_copy_object(kid)) { | 905 | if (maybe_copy_object(kid)) { |
| 903 | kids.setArrayItem(i, kid); | 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,7 +1016,7 @@ QPDFAcroFormDocumentHelper::fixCopiedAnnotations( | ||
| 1013 | std::set<QPDFObjGen>* added_fields) | 1016 | std::set<QPDFObjGen>* added_fields) |
| 1014 | { | 1017 | { |
| 1015 | auto old_annots = from_page.getKey("/Annots"); | 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 | return; | 1020 | return; |
| 1018 | } | 1021 | } |
| 1019 | 1022 |
libqpdf/QPDFEFStreamObjectHelper.cc
| @@ -138,7 +138,7 @@ QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream) | @@ -138,7 +138,7 @@ QPDFEFStreamObjectHelper::newFromStream(QPDFObjectHandle stream) | ||
| 138 | Pl_MD5 md5("EF md5", &discard); | 138 | Pl_MD5 md5("EF md5", &discard); |
| 139 | Pl_Count count("EF size", &md5); | 139 | Pl_Count count("EF size", &md5); |
| 140 | if (!stream.pipeStreamData(&count, nullptr, 0, qpdf_dl_all)) { | 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 | } else { | 142 | } else { |
| 143 | result.setParam("/Size", QPDFObjectHandle::newInteger(count.getCount())); | 143 | result.setParam("/Size", QPDFObjectHandle::newInteger(count.getCount())); |
| 144 | result.setParam( | 144 | result.setParam( |
libqpdf/QPDFFileSpecObjectHelper.cc
| @@ -4,32 +4,33 @@ | @@ -4,32 +4,33 @@ | ||
| 4 | #include <qpdf/QTC.hh> | 4 | #include <qpdf/QTC.hh> |
| 5 | #include <qpdf/QUtil.hh> | 5 | #include <qpdf/QUtil.hh> |
| 6 | 6 | ||
| 7 | +#include <array> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | -#include <vector> | 9 | + |
| 10 | +using namespace std::literals; | ||
| 9 | 11 | ||
| 10 | QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) : | 12 | QPDFFileSpecObjectHelper::QPDFFileSpecObjectHelper(QPDFObjectHandle oh) : |
| 11 | QPDFObjectHelper(oh) | 13 | QPDFObjectHelper(oh) |
| 12 | { | 14 | { |
| 13 | if (!oh.isDictionary()) { | 15 | if (!oh.isDictionary()) { |
| 14 | - oh.warnIfPossible("Embedded file object is not a dictionary"); | 16 | + warn("Embedded file object is not a dictionary"); |
| 15 | return; | 17 | return; |
| 16 | } | 18 | } |
| 17 | if (!oh.isDictionaryOfType("/Filespec")) { | 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 | std::string | 26 | std::string |
| 25 | QPDFFileSpecObjectHelper::getDescription() | 27 | QPDFFileSpecObjectHelper::getDescription() |
| 26 | { | 28 | { |
| 27 | - std::string result; | ||
| 28 | auto desc = oh().getKey("/Desc"); | 29 | auto desc = oh().getKey("/Desc"); |
| 29 | if (desc.isString()) { | 30 | if (desc.isString()) { |
| 30 | - result = desc.getUTF8Value(); | 31 | + return desc.getUTF8Value(); |
| 31 | } | 32 | } |
| 32 | - return result; | 33 | + return {}; |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | std::string | 36 | std::string |
libqpdf/QPDFFormFieldObjectHelper.cc
| @@ -281,7 +281,7 @@ QPDFFormFieldObjectHelper::getChoices() | @@ -281,7 +281,7 @@ QPDFFormFieldObjectHelper::getChoices() | ||
| 281 | for (auto const& item: getInheritableFieldValue("/Opt").as_array()) { | 281 | for (auto const& item: getInheritableFieldValue("/Opt").as_array()) { |
| 282 | if (item.isString()) { | 282 | if (item.isString()) { |
| 283 | result.emplace_back(item.getUTF8Value()); | 283 | result.emplace_back(item.getUTF8Value()); |
| 284 | - } else if (item.isArray() && item.getArrayNItems() == 2) { | 284 | + } else if (item.size() == 2) { |
| 285 | auto display = item.getArrayItem(1); | 285 | auto display = item.getArrayItem(1); |
| 286 | if (display.isString()) { | 286 | if (display.isString()) { |
| 287 | result.emplace_back(display.getUTF8Value()); | 287 | result.emplace_back(display.getUTF8Value()); |
| @@ -317,18 +317,17 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | @@ -317,18 +317,17 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) | ||
| 317 | setCheckBoxValue((name != "/Off")); | 317 | setCheckBoxValue((name != "/Off")); |
| 318 | } | 318 | } |
| 319 | if (!okay) { | 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 | } else if (isRadioButton()) { | 322 | } else if (isRadioButton()) { |
| 324 | if (value.isName()) { | 323 | if (value.isName()) { |
| 325 | setRadioButtonValue(value); | 324 | setRadioButtonValue(value); |
| 326 | } else { | 325 | } else { |
| 327 | - oh().warnIfPossible( | 326 | + warn( |
| 328 | "ignoring attempt to set a radio button field to an object that is not a name"); | 327 | "ignoring attempt to set a radio button field to an object that is not a name"); |
| 329 | } | 328 | } |
| 330 | } else if (isPushbutton()) { | 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 | return; | 332 | return; |
| 334 | } | 333 | } |
| @@ -375,7 +374,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | @@ -375,7 +374,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | ||
| 375 | 374 | ||
| 376 | QPDFObjectHandle kids = oh().getKey("/Kids"); | 375 | QPDFObjectHandle kids = oh().getKey("/Kids"); |
| 377 | if (!(isRadioButton() && parent.isNull() && kids.isArray())) { | 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 | return; | 378 | return; |
| 380 | } | 379 | } |
| 381 | setFieldAttribute("/V", name); | 380 | setFieldAttribute("/V", name); |
| @@ -397,7 +396,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | @@ -397,7 +396,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) | ||
| 397 | } | 396 | } |
| 398 | if (!annot) { | 397 | if (!annot) { |
| 399 | QTC::TC("qpdf", "QPDFObjectHandle broken radio button"); | 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 | continue; | 400 | continue; |
| 402 | } | 401 | } |
| 403 | if (AP.isDictionary() && AP.getKey("/N").isDictionary() && | 402 | if (AP.isDictionary() && AP.getKey("/N").isDictionary() && |
| @@ -453,7 +452,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) | @@ -453,7 +452,7 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) | ||
| 453 | setFieldAttribute("/V", name); | 452 | setFieldAttribute("/V", name); |
| 454 | if (!annot) { | 453 | if (!annot) { |
| 455 | QTC::TC("qpdf", "QPDFObjectHandle broken checkbox"); | 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 | return; | 456 | return; |
| 458 | } | 457 | } |
| 459 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper set checkbox AS"); | 458 | QTC::TC("qpdf", "QPDFFormFieldObjectHelper set checkbox AS"); |
| @@ -770,18 +769,17 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& ao | @@ -770,18 +769,17 @@ QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& ao | ||
| 770 | AP.replaceKey("/N", AS); | 769 | AP.replaceKey("/N", AS); |
| 771 | } | 770 | } |
| 772 | if (!AS.isStream()) { | 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 | return; | 773 | return; |
| 775 | } | 774 | } |
| 776 | 775 | ||
| 777 | if (AS.getObj().use_count() > 4) { | 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 | return; | 778 | return; |
| 781 | } | 779 | } |
| 782 | QPDFObjectHandle bbox_obj = AS.getDict().getKey("/BBox"); | 780 | QPDFObjectHandle bbox_obj = AS.getDict().getKey("/BBox"); |
| 783 | if (!bbox_obj.isRectangle()) { | 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 | return; | 783 | return; |
| 786 | } | 784 | } |
| 787 | QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle(); | 785 | QPDFObjectHandle::Rectangle bbox = bbox_obj.getArrayAsRectangle(); |
libqpdf/QPDFJob.cc
| @@ -1082,7 +1082,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | @@ -1082,7 +1082,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1082 | dp_array = decode_parms; | 1082 | dp_array = decode_parms; |
| 1083 | } else { | 1083 | } else { |
| 1084 | dp_array = QPDFObjectHandle::newArray(); | 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 | dp_array.appendItem(decode_parms); | 1086 | dp_array.appendItem(decode_parms); |
| 1087 | } | 1087 | } |
| 1088 | } | 1088 | } |
| @@ -2322,7 +2322,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) | @@ -2322,7 +2322,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) | ||
| 2322 | }); | 2322 | }); |
| 2323 | 2323 | ||
| 2324 | std::list<QPDFObjectHandle> queue; | 2324 | std::list<QPDFObjectHandle> queue; |
| 2325 | - queue.push_back(pdf.getRoot().getKey("/Pages")); | 2325 | + queue.emplace_back(pdf.getRoot().getKey("/Pages")); |
| 2326 | while (!queue.empty()) { | 2326 | while (!queue.empty()) { |
| 2327 | QPDFObjectHandle node = *queue.begin(); | 2327 | QPDFObjectHandle node = *queue.begin(); |
| 2328 | queue.pop_front(); | 2328 | queue.pop_front(); |
| @@ -2341,9 +2341,8 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) | @@ -2341,9 +2341,8 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF& pdf) | ||
| 2341 | }); | 2341 | }); |
| 2342 | return true; | 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 | } else { | 2347 | } else { |
| 2349 | // This is a leaf node or a form XObject. | 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,12 +2669,10 @@ QPDFJob::handlePageSpecs(QPDF& pdf, std::vector<std::unique_ptr<QPDF>>& page_hea | ||
| 2670 | new_fields.appendItem(field); | 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 | pdf.getRoot().removeKey("/AcroForm"); | 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,16 +352,15 @@ BaseHandle::unparse() const | ||
| 352 | auto const& a = std::get<QPDF_Array>(obj->value); | 352 | auto const& a = std::get<QPDF_Array>(obj->value); |
| 353 | std::string result = "[ "; | 353 | std::string result = "[ "; |
| 354 | if (a.sp) { | 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 | result += "null "; | 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 | result += "null "; | 364 | result += "null "; |
| 366 | } | 365 | } |
| 367 | } else { | 366 | } else { |
| @@ -467,22 +466,21 @@ BaseHandle::write_json(int json_version, JSON::Writer& p) const | @@ -467,22 +466,21 @@ BaseHandle::write_json(int json_version, JSON::Writer& p) const | ||
| 467 | auto const& a = std::get<QPDF_Array>(obj->value); | 466 | auto const& a = std::get<QPDF_Array>(obj->value); |
| 468 | p.writeStart('['); | 467 | p.writeStart('['); |
| 469 | if (a.sp) { | 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 | p.writeNext() << "null"; | 472 | p.writeNext() << "null"; |
| 475 | } | 473 | } |
| 476 | p.writeNext(); | 474 | p.writeNext(); |
| 477 | - auto item_og = item.second.getObj()->getObjGen(); | 475 | + auto item_og = value.getObj()->getObjGen(); |
| 478 | if (item_og.isIndirect()) { | 476 | if (item_og.isIndirect()) { |
| 479 | p << "\"" << item_og.unparse(' ') << " R\""; | 477 | p << "\"" << item_og.unparse(' ') << " R\""; |
| 480 | } else { | 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 | p.writeNext() << "null"; | 484 | p.writeNext() << "null"; |
| 487 | } | 485 | } |
| 488 | } else { | 486 | } else { |
| @@ -611,11 +609,11 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const | @@ -611,11 +609,11 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const | ||
| 611 | qpdf_object_type_e | 609 | qpdf_object_type_e |
| 612 | QPDFObjectHandle::getTypeCode() const | 610 | QPDFObjectHandle::getTypeCode() const |
| 613 | { | 611 | { |
| 614 | - return obj ? obj->getResolvedTypeCode() : ::ot_uninitialized; | 612 | + return type_code(); |
| 615 | } | 613 | } |
| 616 | 614 | ||
| 617 | char const* | 615 | char const* |
| 618 | -QPDFObjectHandle::getTypeName() const | 616 | +BaseHandle::type_name() const |
| 619 | { | 617 | { |
| 620 | static constexpr std::array<char const*, 16> tn{ | 618 | static constexpr std::array<char const*, 16> tn{ |
| 621 | "uninitialized", | 619 | "uninitialized", |
| @@ -634,7 +632,13 @@ QPDFObjectHandle::getTypeName() const | @@ -634,7 +632,13 @@ QPDFObjectHandle::getTypeName() const | ||
| 634 | "unresolved", | 632 | "unresolved", |
| 635 | "destroyed", | 633 | "destroyed", |
| 636 | "reference"}; | 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 | bool | 644 | bool |
| @@ -829,20 +833,16 @@ QPDFObjectHandle::getValueAsInt(long long& value) const | @@ -829,20 +833,16 @@ QPDFObjectHandle::getValueAsInt(long long& value) const | ||
| 829 | int | 833 | int |
| 830 | QPDFObjectHandle::getIntValueAsInt() const | 834 | QPDFObjectHandle::getIntValueAsInt() const |
| 831 | { | 835 | { |
| 832 | - int result = 0; | ||
| 833 | long long v = getIntValue(); | 836 | long long v = getIntValue(); |
| 834 | if (v < INT_MIN) { | 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 | bool | 848 | bool |
| @@ -860,8 +860,7 @@ QPDFObjectHandle::getUIntValue() const | @@ -860,8 +860,7 @@ QPDFObjectHandle::getUIntValue() const | ||
| 860 | { | 860 | { |
| 861 | long long v = getIntValue(); | 861 | long long v = getIntValue(); |
| 862 | if (v < 0) { | 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 | return 0; | 864 | return 0; |
| 866 | } else { | 865 | } else { |
| 867 | return static_cast<unsigned long long>(v); | 866 | return static_cast<unsigned long long>(v); |
| @@ -883,16 +882,14 @@ QPDFObjectHandle::getUIntValueAsUInt() const | @@ -883,16 +882,14 @@ QPDFObjectHandle::getUIntValueAsUInt() const | ||
| 883 | { | 882 | { |
| 884 | long long v = getIntValue(); | 883 | long long v = getIntValue(); |
| 885 | if (v < 0) { | 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 | return 0; | 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 | return UINT_MAX; | 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 | bool | 895 | bool |
| @@ -1235,34 +1232,30 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( | @@ -1235,34 +1232,30 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( | ||
| 1235 | all_description = description; | 1232 | all_description = description; |
| 1236 | std::vector<QPDFObjectHandle> result; | 1233 | std::vector<QPDFObjectHandle> result; |
| 1237 | if (auto array = as_array(strict)) { | 1234 | if (auto array = as_array(strict)) { |
| 1238 | - int n_items = array.size(); | 1235 | + int n_items = static_cast<int>(array.size()); |
| 1239 | for (int i = 0; i < n_items; ++i) { | 1236 | for (int i = 0; i < n_items; ++i) { |
| 1240 | QPDFObjectHandle item = array.at(i).second; | 1237 | QPDFObjectHandle item = array.at(i).second; |
| 1241 | if (item.isStream()) { | 1238 | if (item.isStream()) { |
| 1242 | result.emplace_back(item); | 1239 | result.emplace_back(item); |
| 1243 | } else { | 1240 | } else { |
| 1244 | QTC::TC("qpdf", "QPDFObjectHandle non-stream in stream array"); | 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 | } else if (isStream()) { | 1250 | } else if (isStream()) { |
| 1256 | result.emplace_back(*this); | 1251 | result.emplace_back(*this); |
| 1257 | - } else if (!isNull()) { | 1252 | + } else if (!null()) { |
| 1258 | warn( | 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 | bool first = true; | 1261 | bool first = true; |
| @@ -1824,6 +1817,12 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) | @@ -1824,6 +1817,12 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) | ||
| 1824 | return qpdf->newReserved(); | 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 | void | 1826 | void |
| 1828 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) | 1827 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) |
| 1829 | { | 1828 | { |
| @@ -1934,50 +1933,44 @@ QPDFObjectHandle::assertInitialized() const | @@ -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 | void | 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 | if (!obj) { | 1958 | if (!obj) { |
| 1945 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); | 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 | void | 1964 | void |
| 1961 | QPDFObjectHandle::warnIfPossible(std::string const& warning) const | 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 | void | 1970 | void |
| 1973 | QPDFObjectHandle::objectWarning(std::string const& warning) const | 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 | void | 1976 | void |
| @@ -2130,15 +2123,30 @@ QPDFObjectHandle::assertPageObject() const | @@ -2130,15 +2123,30 @@ QPDFObjectHandle::assertPageObject() const | ||
| 2130 | } | 2123 | } |
| 2131 | 2124 | ||
| 2132 | void | 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 | } else { | 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,7 +75,7 @@ QPDFObjectHandle | ||
| 75 | QPDFOutlineObjectHelper::getDestPage() | 75 | QPDFOutlineObjectHelper::getDestPage() |
| 76 | { | 76 | { |
| 77 | QPDFObjectHandle dest = getDest(); | 77 | QPDFObjectHandle dest = getDest(); |
| 78 | - if ((dest.isArray()) && (dest.getArrayNItems() > 0)) { | 78 | + if (!dest.empty() && dest.isArray()) { |
| 79 | return dest.getArrayItem(0); | 79 | return dest.getArrayItem(0); |
| 80 | } | 80 | } |
| 81 | return QPDFObjectHandle::newNull(); | 81 | return QPDFObjectHandle::newNull(); |
libqpdf/QPDFPageDocumentHelper.cc
| @@ -59,7 +59,7 @@ QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_fla | @@ -59,7 +59,7 @@ QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_fla | ||
| 59 | if (afdh.getNeedAppearances()) { | 59 | if (afdh.getNeedAppearances()) { |
| 60 | qpdf.getRoot() | 60 | qpdf.getRoot() |
| 61 | .getKey("/AcroForm") | 61 | .getKey("/AcroForm") |
| 62 | - .warnIfPossible( | 62 | + .warn( |
| 63 | "document does not have updated appearance streams, so form fields " | 63 | "document does not have updated appearance streams, so form fields " |
| 64 | "will not be flattened"); | 64 | "will not be flattened"); |
| 65 | } | 65 | } |
libqpdf/QPDFPageObjectHelper.cc
| @@ -12,6 +12,8 @@ | @@ -12,6 +12,8 @@ | ||
| 12 | #include <qpdf/QUtil.hh> | 12 | #include <qpdf/QUtil.hh> |
| 13 | #include <qpdf/ResourceFinder.hh> | 13 | #include <qpdf/ResourceFinder.hh> |
| 14 | 14 | ||
| 15 | +using namespace std::literals; | ||
| 16 | + | ||
| 15 | namespace | 17 | namespace |
| 16 | { | 18 | { |
| 17 | class ContentProvider: public QPDFObjectHandle::StreamDataProvider | 19 | class ContentProvider: public QPDFObjectHandle::StreamDataProvider |
| @@ -118,7 +120,7 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) | @@ -118,7 +120,7 @@ InlineImageTracker::convertIIDict(QPDFObjectHandle odict) | ||
| 118 | QTC::TC("qpdf", "QPDFPageObjectHelper colorspace lookup"); | 120 | QTC::TC("qpdf", "QPDFPageObjectHelper colorspace lookup"); |
| 119 | value = colorspace.getKey(name); | 121 | value = colorspace.getKey(name); |
| 120 | } else { | 122 | } else { |
| 121 | - resources.warnIfPossible("unable to resolve colorspace " + name); | 123 | + resources.warn("unable to resolve colorspace " + name); |
| 122 | } | 124 | } |
| 123 | name.clear(); | 125 | name.clear(); |
| 124 | } | 126 | } |
| @@ -414,8 +416,8 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) | @@ -414,8 +416,8 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) | ||
| 414 | filterContents(&iit, &b); | 416 | filterContents(&iit, &b); |
| 415 | filtered = true; | 417 | filtered = true; |
| 416 | } catch (std::exception& e) { | 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 | "; not attempting to externalize inline images from this stream"); | 421 | "; not attempting to externalize inline images from this stream"); |
| 420 | } | 422 | } |
| 421 | if (filtered && iit.any_images) { | 423 | if (filtered && iit.any_images) { |
| @@ -443,14 +445,9 @@ std::vector<QPDFAnnotationObjectHelper> | @@ -443,14 +445,9 @@ std::vector<QPDFAnnotationObjectHelper> | ||
| 443 | QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) | 445 | QPDFPageObjectHelper::getAnnotations(std::string const& only_subtype) |
| 444 | { | 446 | { |
| 445 | std::vector<QPDFAnnotationObjectHelper> result; | 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 | return result; | 453 | return result; |
| @@ -555,15 +552,15 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( | @@ -555,15 +552,15 @@ QPDFPageObjectHelper::removeUnreferencedResourcesHelper( | ||
| 555 | ph.parseContents(&rf); | 552 | ph.parseContents(&rf); |
| 556 | size_t after_nw = (q ? q->numWarnings() : 0); | 553 | size_t after_nw = (q ? q->numWarnings() : 0); |
| 557 | if (after_nw > before_nw) { | 554 | if (after_nw > before_nw) { |
| 558 | - ph.oh().warnIfPossible( | 555 | + ph.warn( |
| 559 | "Bad token found while scanning content stream; " | 556 | "Bad token found while scanning content stream; " |
| 560 | "not attempting to remove unreferenced objects from this object"); | 557 | "not attempting to remove unreferenced objects from this object"); |
| 561 | return false; | 558 | return false; |
| 562 | } | 559 | } |
| 563 | } catch (std::exception& e) { | 560 | } catch (std::exception& e) { |
| 564 | QTC::TC("qpdf", "QPDFPageObjectHelper bad token finding names"); | 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 | "; not attempting to remove unreferenced objects from this object"); | 564 | "; not attempting to remove unreferenced objects from this object"); |
| 568 | return false; | 565 | return false; |
| 569 | } | 566 | } |
| @@ -719,8 +716,7 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) | @@ -719,8 +716,7 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations) | ||
| 719 | newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); | 716 | newdict.replaceKey("/Group", getAttribute("/Group", false).shallowCopy()); |
| 720 | QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); | 717 | QPDFObjectHandle bbox = getTrimBox(false).shallowCopy(); |
| 721 | if (!bbox.isRectangle()) { | 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 | newdict.replaceKey("/BBox", bbox); | 721 | newdict.replaceKey("/BBox", bbox); |
| 726 | auto provider = | 722 | auto provider = |
libqpdf/QPDFWriter.cc
| @@ -1396,8 +1396,8 @@ QPDFWriter::willFilterStream( | @@ -1396,8 +1396,8 @@ QPDFWriter::willFilterStream( | ||
| 1396 | } | 1396 | } |
| 1397 | } catch (std::runtime_error& e) { | 1397 | } catch (std::runtime_error& e) { |
| 1398 | if (filter && first_attempt) { | 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 | filter = false; | 1401 | filter = false; |
| 1402 | stream.setFilterOnWrite(false); | 1402 | stream.setFilterOnWrite(false); |
| 1403 | continue; | 1403 | continue; |
| @@ -1538,9 +1538,7 @@ QPDFWriter::unparseObject( | @@ -1538,9 +1538,7 @@ QPDFWriter::unparseObject( | ||
| 1538 | object.removeKey("/Length"); | 1538 | object.removeKey("/Length"); |
| 1539 | 1539 | ||
| 1540 | // If /DecodeParms is an empty list, remove it. | 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 | object.removeKey("/DecodeParms"); | 1542 | object.removeKey("/DecodeParms"); |
| 1545 | } | 1543 | } |
| 1546 | 1544 | ||
| @@ -1558,22 +1556,19 @@ QPDFWriter::unparseObject( | @@ -1558,22 +1556,19 @@ QPDFWriter::unparseObject( | ||
| 1558 | object.removeKey("/Filter"); | 1556 | object.removeKey("/Filter"); |
| 1559 | object.removeKey("/DecodeParms"); | 1557 | object.removeKey("/DecodeParms"); |
| 1560 | } else { | 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 | if (item.isNameAndEquals("/Crypt")) { | 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 | break; | 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,7 +1737,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1742 | if (obj_to_write.isStream()) { | 1737 | if (obj_to_write.isStream()) { |
| 1743 | // This condition occurred in a fuzz input. Ideally we should block it at parse | 1738 | // This condition occurred in a fuzz input. Ideally we should block it at parse |
| 1744 | // time, but it's not clear to me how to construct a case for this. | 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 | obj_to_write = QPDFObjectHandle::newNull(); | 1741 | obj_to_write = QPDFObjectHandle::newNull(); |
| 1747 | } | 1742 | } |
| 1748 | writeObject(obj_to_write, count); | 1743 | writeObject(obj_to_write, count); |
| @@ -1965,7 +1960,7 @@ QPDFWriter::initializeSpecialStreams() | @@ -1965,7 +1960,7 @@ QPDFWriter::initializeSpecialStreams() | ||
| 1965 | QPDFObjectHandle contents = page.getKey("/Contents"); | 1960 | QPDFObjectHandle contents = page.getKey("/Contents"); |
| 1966 | std::vector<QPDFObjGen> contents_objects; | 1961 | std::vector<QPDFObjGen> contents_objects; |
| 1967 | if (contents.isArray()) { | 1962 | if (contents.isArray()) { |
| 1968 | - int n = contents.getArrayNItems(); | 1963 | + int n = static_cast<int>(contents.size()); |
| 1969 | for (int i = 0; i < n; ++i) { | 1964 | for (int i = 0; i < n; ++i) { |
| 1970 | contents_objects.push_back(contents.getArrayItem(i).getObjGen()); | 1965 | contents_objects.push_back(contents.getArrayItem(i).getObjGen()); |
| 1971 | } | 1966 | } |
libqpdf/QPDF_Array.cc
| @@ -2,11 +2,25 @@ | @@ -2,11 +2,25 @@ | ||
| 2 | 2 | ||
| 3 | #include <qpdf/QTC.hh> | 3 | #include <qpdf/QTC.hh> |
| 4 | 4 | ||
| 5 | +#include <utility> | ||
| 6 | + | ||
| 5 | using namespace std::literals; | 7 | using namespace std::literals; |
| 6 | using namespace qpdf; | 8 | using namespace qpdf; |
| 7 | 9 | ||
| 8 | static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); | 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 | inline void | 24 | inline void |
| 11 | Array::checkOwnership(QPDFObjectHandle const& item) const | 25 | Array::checkOwnership(QPDFObjectHandle const& item) const |
| 12 | { | 26 | { |
| @@ -142,24 +156,24 @@ Array::null() const | @@ -142,24 +156,24 @@ Array::null() const | ||
| 142 | return null_oh; | 156 | return null_oh; |
| 143 | } | 157 | } |
| 144 | 158 | ||
| 145 | -int | 159 | +size_t |
| 146 | Array::size() const | 160 | Array::size() const |
| 147 | { | 161 | { |
| 148 | auto a = array(); | 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 | std::pair<bool, QPDFObjectHandle> | 166 | std::pair<bool, QPDFObjectHandle> |
| 153 | Array::at(int n) const | 167 | Array::at(int n) const |
| 154 | { | 168 | { |
| 155 | auto a = array(); | 169 | auto a = array(); |
| 156 | - if (n < 0 || n >= size()) { | 170 | + if (n < 0 || std::cmp_greater_equal(n, size())) { |
| 157 | return {false, {}}; | 171 | return {false, {}}; |
| 158 | } | 172 | } |
| 159 | if (!a->sp) { | 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 | return {true, iter == a->sp->elements.end() ? null() : iter->second}; | 177 | return {true, iter == a->sp->elements.end() ? null() : iter->second}; |
| 164 | } | 178 | } |
| 165 | 179 | ||
| @@ -169,12 +183,12 @@ Array::getAsVector() const | @@ -169,12 +183,12 @@ Array::getAsVector() const | ||
| 169 | auto a = array(); | 183 | auto a = array(); |
| 170 | if (a->sp) { | 184 | if (a->sp) { |
| 171 | std::vector<QPDFObjectHandle> v; | 185 | std::vector<QPDFObjectHandle> v; |
| 172 | - v.reserve(size_t(size())); | 186 | + v.reserve(size()); |
| 173 | for (auto const& item: a->sp->elements) { | 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 | v.emplace_back(item.second); | 189 | v.emplace_back(item.second); |
| 176 | } | 190 | } |
| 177 | - v.resize(size_t(size()), null_oh); | 191 | + v.resize(size(), null_oh); |
| 178 | return v; | 192 | return v; |
| 179 | } else { | 193 | } else { |
| 180 | return a->elements; | 194 | return a->elements; |
| @@ -184,15 +198,15 @@ Array::getAsVector() const | @@ -184,15 +198,15 @@ Array::getAsVector() const | ||
| 184 | bool | 198 | bool |
| 185 | Array::setAt(int at, QPDFObjectHandle const& oh) | 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 | return false; | 202 | return false; |
| 189 | } | 203 | } |
| 190 | auto a = array(); | 204 | auto a = array(); |
| 191 | checkOwnership(oh); | 205 | checkOwnership(oh); |
| 192 | if (a->sp) { | 206 | if (a->sp) { |
| 193 | - a->sp->elements[at] = oh; | 207 | + a->sp->elements[to_s(at)] = oh; |
| 194 | } else { | 208 | } else { |
| 195 | - a->elements[size_t(at)] = oh; | 209 | + a->elements[to_s(at)] = oh; |
| 196 | } | 210 | } |
| 197 | return true; | 211 | return true; |
| 198 | } | 212 | } |
| @@ -210,34 +224,39 @@ Array::setFromVector(std::vector<QPDFObjectHandle> const& v) | @@ -210,34 +224,39 @@ Array::setFromVector(std::vector<QPDFObjectHandle> const& v) | ||
| 210 | } | 224 | } |
| 211 | 225 | ||
| 212 | bool | 226 | bool |
| 213 | -Array::insert(int at, QPDFObjectHandle const& item) | 227 | +Array::insert(int at_i, QPDFObjectHandle const& item) |
| 214 | { | 228 | { |
| 215 | auto a = array(); | 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 | return false; | 236 | return false; |
| 220 | - } else if (at == sz) { | 237 | + } |
| 238 | + if (at == sz) { | ||
| 239 | + // As special case, also allow insert beyond the end | ||
| 221 | push_back(item); | 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 | return true; | 261 | return true; |
| 243 | } | 262 | } |
| @@ -255,10 +274,14 @@ Array::push_back(QPDFObjectHandle const& item) | @@ -255,10 +274,14 @@ Array::push_back(QPDFObjectHandle const& item) | ||
| 255 | } | 274 | } |
| 256 | 275 | ||
| 257 | bool | 276 | bool |
| 258 | -Array::erase(int at) | 277 | +Array::erase(int at_i) |
| 259 | { | 278 | { |
| 260 | auto a = array(); | 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 | return false; | 285 | return false; |
| 263 | } | 286 | } |
| 264 | if (a->sp) { | 287 | if (a->sp) { |
| @@ -277,7 +300,7 @@ Array::erase(int at) | @@ -277,7 +300,7 @@ Array::erase(int at) | ||
| 277 | } | 300 | } |
| 278 | --(a->sp->size); | 301 | --(a->sp->size); |
| 279 | } else { | 302 | } else { |
| 280 | - a->elements.erase(a->elements.cbegin() + at); | 303 | + a->elements.erase(a->elements.cbegin() + at_i); |
| 281 | } | 304 | } |
| 282 | return true; | 305 | return true; |
| 283 | } | 306 | } |
| @@ -286,7 +309,7 @@ int | @@ -286,7 +309,7 @@ int | ||
| 286 | QPDFObjectHandle::getArrayNItems() const | 309 | QPDFObjectHandle::getArrayNItems() const |
| 287 | { | 310 | { |
| 288 | if (auto array = as_array(strict)) { | 311 | if (auto array = as_array(strict)) { |
| 289 | - return array.size(); | 312 | + return to_i(array.size()); |
| 290 | } | 313 | } |
| 291 | typeWarning("array", "treating as empty"); | 314 | typeWarning("array", "treating as empty"); |
| 292 | QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); | 315 | QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); |
| @@ -471,7 +494,37 @@ QPDFObjectHandle | @@ -471,7 +494,37 @@ QPDFObjectHandle | ||
| 471 | QPDFObjectHandle::eraseItemAndGetOld(int at) | 494 | QPDFObjectHandle::eraseItemAndGetOld(int at) |
| 472 | { | 495 | { |
| 473 | auto array = as_array(strict); | 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 | eraseItem(at); | 499 | eraseItem(at); |
| 476 | return result; | 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,7 +664,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) | ||
| 664 | 664 | ||
| 665 | std::string id1; | 665 | std::string id1; |
| 666 | auto id_obj = trailer.getKey("/ID"); | 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 | // Treating a missing ID as the empty string enables qpdf to decrypt some invalid encrypted | 668 | // Treating a missing ID as the empty string enables qpdf to decrypt some invalid encrypted |
| 669 | // files with no /ID that poppler can read but Adobe Reader can't. | 669 | // files with no /ID that poppler can read but Adobe Reader can't. |
| 670 | qpdf.warn(qpdf.damagedPDF("trailer", "invalid /ID in trailer dictionary")); | 670 | qpdf.warn(qpdf.damagedPDF("trailer", "invalid /ID in trailer dictionary")); |
| @@ -961,19 +961,21 @@ QPDF::decryptStream( | @@ -961,19 +961,21 @@ QPDF::decryptStream( | ||
| 961 | } else if ( | 961 | } else if ( |
| 962 | stream_dict.getKey("/DecodeParms").isArray() && | 962 | stream_dict.getKey("/DecodeParms").isArray() && |
| 963 | stream_dict.getKey("/Filter").isArray()) { | 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 | if (crypt_params.isDictionary() && | 971 | if (crypt_params.isDictionary() && |
| 971 | crypt_params.getKey("/Name").isName()) { | 972 | crypt_params.getKey("/Name").isName()) { |
| 972 | - QTC::TC("qpdf", "QPDF_encrypt crypt array"); | ||
| 973 | method = encp->interpretCF(crypt_params.getKey("/Name")); | 973 | method = encp->interpretCF(crypt_params.getKey("/Name")); |
| 974 | method_source = "stream's Crypt decode parameters (array)"; | 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,14 +174,13 @@ QPDF::readLinearizationData() | ||
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | // Hint table array: offset length [ offset length ] | 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 | throw damagedPDF("linearization dictionary", "H has the wrong number of items"); | 179 | throw damagedPDF("linearization dictionary", "H has the wrong number of items"); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | std::vector<int> H_items; | 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 | if (oh.isInteger()) { | 184 | if (oh.isInteger()) { |
| 186 | H_items.push_back(oh.getIntValueAsInt()); | 185 | H_items.push_back(oh.getIntValueAsInt()); |
| 187 | } else { | 186 | } else { |
libqpdf/QPDF_objects.cc
| @@ -782,7 +782,7 @@ std::pair<int, std::array<int, 3>> | @@ -782,7 +782,7 @@ std::pair<int, std::array<int, 3>> | ||
| 782 | QPDF::processXRefW(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged) | 782 | QPDF::processXRefW(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged) |
| 783 | { | 783 | { |
| 784 | auto W_obj = dict.getKey("/W"); | 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 | W_obj.getArrayItem(1).isInteger() && W_obj.getArrayItem(2).isInteger())) { | 786 | W_obj.getArrayItem(1).isInteger() && W_obj.getArrayItem(2).isInteger())) { |
| 787 | throw damaged("Cross-reference stream does not have a proper /W key"); | 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,7 +57,7 @@ QPDF::getAllPages() | ||
| 57 | // Files have been found in the wild where /Pages in the catalog points to the first | 57 | // Files have been found in the wild where /Pages in the catalog points to the first |
| 58 | // page. Try to work around this and similar cases with this heuristic. | 58 | // page. Try to work around this and similar cases with this heuristic. |
| 59 | if (!warned) { | 59 | if (!warned) { |
| 60 | - root.warnIfPossible( | 60 | + root.warn( |
| 61 | "document page tree root (root -> /Pages) doesn't point" | 61 | "document page tree root (root -> /Pages) doesn't point" |
| 62 | " to the root of the page tree; attempting to correct"); | 62 | " to the root of the page tree; attempting to correct"); |
| 63 | warned = true; | 63 | warned = true; |
| @@ -109,7 +109,7 @@ QPDF::getAllPagesInternal( | @@ -109,7 +109,7 @@ QPDF::getAllPagesInternal( | ||
| 109 | // During fuzzing files were encountered where the root object appeared in the pages tree. | 109 | // During fuzzing files were encountered where the root object appeared in the pages tree. |
| 110 | // Unconditionally setting the /Type to /Pages could cause problems, but trying to | 110 | // Unconditionally setting the /Type to /Pages could cause problems, but trying to |
| 111 | // accommodate the possibility may be excessive. | 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 | cur_node.replaceKey("/Type", "/Pages"_qpdf); | 113 | cur_node.replaceKey("/Type", "/Pages"_qpdf); |
| 114 | } | 114 | } |
| 115 | if (!media_box) { | 115 | if (!media_box) { |
| @@ -134,13 +134,13 @@ QPDF::getAllPagesInternal( | @@ -134,13 +134,13 @@ QPDF::getAllPagesInternal( | ||
| 134 | int errors = 0; | 134 | int errors = 0; |
| 135 | 135 | ||
| 136 | if (!kid.isDictionary()) { | 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 | m->invalid_page_found = true; | 138 | m->invalid_page_found = true; |
| 139 | continue; | 139 | continue; |
| 140 | } | 140 | } |
| 141 | if (!kid.isIndirect()) { | 141 | if (!kid.isIndirect()) { |
| 142 | QTC::TC("qpdf", "QPDF handle direct page object"); | 142 | QTC::TC("qpdf", "QPDF handle direct page object"); |
| 143 | - cur_node.warnIfPossible( | 143 | + cur_node.warn( |
| 144 | "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); | 144 | "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); |
| 145 | kid = makeIndirectObject(kid); | 145 | kid = makeIndirectObject(kid); |
| 146 | ++errors; | 146 | ++errors; |
| @@ -150,7 +150,7 @@ QPDF::getAllPagesInternal( | @@ -150,7 +150,7 @@ QPDF::getAllPagesInternal( | ||
| 150 | } else { | 150 | } else { |
| 151 | if (!media_box && !kid.getKey("/MediaBox").isRectangle()) { | 151 | if (!media_box && !kid.getKey("/MediaBox").isRectangle()) { |
| 152 | QTC::TC("qpdf", "QPDF missing mediabox"); | 152 | QTC::TC("qpdf", "QPDF missing mediabox"); |
| 153 | - kid.warnIfPossible( | 153 | + kid.warn( |
| 154 | "kid " + std::to_string(i) + | 154 | "kid " + std::to_string(i) + |
| 155 | " (from 0) MediaBox is undefined; setting to letter / ANSI A"); | 155 | " (from 0) MediaBox is undefined; setting to letter / ANSI A"); |
| 156 | kid.replaceKey( | 156 | kid.replaceKey( |
| @@ -167,7 +167,7 @@ QPDF::getAllPagesInternal( | @@ -167,7 +167,7 @@ QPDF::getAllPagesInternal( | ||
| 167 | // QPDFPageObjectHelper. | 167 | // QPDFPageObjectHelper. |
| 168 | QTC::TC("qpdf", "QPDF resolve duplicated page object"); | 168 | QTC::TC("qpdf", "QPDF resolve duplicated page object"); |
| 169 | if (!m->reconstructed_xref) { | 169 | if (!m->reconstructed_xref) { |
| 170 | - cur_node.warnIfPossible( | 170 | + cur_node.warn( |
| 171 | "kid " + std::to_string(i) + | 171 | "kid " + std::to_string(i) + |
| 172 | " (from 0) appears more than once in the pages tree;" | 172 | " (from 0) appears more than once in the pages tree;" |
| 173 | " creating a new page object as a copy"); | 173 | " creating a new page object as a copy"); |
| @@ -176,7 +176,7 @@ QPDF::getAllPagesInternal( | @@ -176,7 +176,7 @@ QPDF::getAllPagesInternal( | ||
| 176 | kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); | 176 | kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); |
| 177 | seen.add(kid); | 177 | seen.add(kid); |
| 178 | } else { | 178 | } else { |
| 179 | - cur_node.warnIfPossible( | 179 | + cur_node.warn( |
| 180 | "kid " + std::to_string(i) + | 180 | "kid " + std::to_string(i) + |
| 181 | " (from 0) appears more than once in the pages tree; ignoring duplicate"); | 181 | " (from 0) appears more than once in the pages tree; ignoring duplicate"); |
| 182 | m->invalid_page_found = true; | 182 | m->invalid_page_found = true; |
| @@ -189,12 +189,12 @@ QPDF::getAllPagesInternal( | @@ -189,12 +189,12 @@ QPDF::getAllPagesInternal( | ||
| 189 | } | 189 | } |
| 190 | } | 190 | } |
| 191 | if (!kid.isDictionaryOfType("/Page")) { | 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 | kid.replaceKey("/Type", "/Page"_qpdf); | 193 | kid.replaceKey("/Type", "/Page"_qpdf); |
| 194 | ++errors; | 194 | ++errors; |
| 195 | } | 195 | } |
| 196 | if (m->reconstructed_xref && errors > 2) { | 196 | if (m->reconstructed_xref && errors > 2) { |
| 197 | - cur_node.warnIfPossible( | 197 | + cur_node.warn( |
| 198 | "kid " + std::to_string(i) + " (from 0) has too many errors; ignoring page"); | 198 | "kid " + std::to_string(i) + " (from 0) has too many errors; ignoring page"); |
| 199 | m->invalid_page_found = true; | 199 | m->invalid_page_found = true; |
| 200 | kid = QPDFObjectHandle::newNull(); | 200 | kid = QPDFObjectHandle::newNull(); |
| @@ -313,7 +313,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) | @@ -313,7 +313,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos) | ||
| 313 | 313 | ||
| 314 | newpage.replaceKey("/Parent", pages); | 314 | newpage.replaceKey("/Parent", pages); |
| 315 | kids.insertItem(pos, newpage); | 315 | kids.insertItem(pos, newpage); |
| 316 | - int npages = kids.getArrayNItems(); | 316 | + int npages = static_cast<int>(kids.size()); |
| 317 | pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); | 317 | pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); |
| 318 | m->all_pages.insert(m->all_pages.begin() + pos, newpage); | 318 | m->all_pages.insert(m->all_pages.begin() + pos, newpage); |
| 319 | for (int i = pos + 1; i < npages; ++i) { | 319 | for (int i = pos + 1; i < npages; ++i) { |
| @@ -337,7 +337,7 @@ QPDF::removePage(QPDFObjectHandle page) | @@ -337,7 +337,7 @@ QPDF::removePage(QPDFObjectHandle page) | ||
| 337 | QPDFObjectHandle kids = pages.getKey("/Kids"); | 337 | QPDFObjectHandle kids = pages.getKey("/Kids"); |
| 338 | 338 | ||
| 339 | kids.eraseItem(pos); | 339 | kids.eraseItem(pos); |
| 340 | - int npages = kids.getArrayNItems(); | 340 | + int npages = static_cast<int>(kids.size()); |
| 341 | pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); | 341 | pages.replaceKey("/Count", QPDFObjectHandle::newInteger(npages)); |
| 342 | m->all_pages.erase(m->all_pages.begin() + pos); | 342 | m->all_pages.erase(m->all_pages.begin() + pos); |
| 343 | m->pageobj_to_pages_pos.erase(page.getObjGen()); | 343 | m->pageobj_to_pages_pos.erase(page.getObjGen()); |
libqpdf/qpdf/QPDFObjectHandle_private.hh
| @@ -38,7 +38,7 @@ namespace qpdf | @@ -38,7 +38,7 @@ namespace qpdf | ||
| 38 | 38 | ||
| 39 | const_reverse_iterator crend(); | 39 | const_reverse_iterator crend(); |
| 40 | 40 | ||
| 41 | - int size() const; | 41 | + size_t size() const; |
| 42 | std::pair<bool, QPDFObjectHandle> at(int n) const; | 42 | std::pair<bool, QPDFObjectHandle> at(int n) const; |
| 43 | bool setAt(int at, QPDFObjectHandle const& oh); | 43 | bool setAt(int at, QPDFObjectHandle const& oh); |
| 44 | bool insert(int at, QPDFObjectHandle const& item); | 44 | bool insert(int at, QPDFObjectHandle const& item); |
libqpdf/qpdf/QPDFObject_private.hh
| @@ -35,8 +35,8 @@ class QPDF_Array final | @@ -35,8 +35,8 @@ class QPDF_Array final | ||
| 35 | private: | 35 | private: |
| 36 | struct Sparse | 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 | public: | 42 | public: |
| @@ -65,10 +65,10 @@ class QPDF_Array final | @@ -65,10 +65,10 @@ class QPDF_Array final | ||
| 65 | { | 65 | { |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | - int | 68 | + size_t |
| 69 | size() const | 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 | std::unique_ptr<Sparse> sp; | 74 | std::unique_ptr<Sparse> sp; |
| @@ -434,13 +434,6 @@ class QPDFObject | @@ -434,13 +434,6 @@ class QPDFObject | ||
| 434 | parsed_offset = offset; | 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 | qpdf_offset_t | 437 | qpdf_offset_t |
| 445 | getParsedOffset() | 438 | getParsedOffset() |
| 446 | { | 439 | { |
libtests/sparse_array.cc
| @@ -7,6 +7,12 @@ | @@ -7,6 +7,12 @@ | ||
| 7 | #include <iostream> | 7 | #include <iostream> |
| 8 | 8 | ||
| 9 | int | 9 | int |
| 10 | +to_i(size_t n) | ||
| 11 | +{ | ||
| 12 | + return static_cast<int>(n); | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +int | ||
| 10 | main() | 16 | main() |
| 11 | { | 17 | { |
| 12 | auto obj = QPDFObject::create<QPDF_Array>(std::vector<QPDFObjectHandle>(), true); | 18 | auto obj = QPDFObject::create<QPDF_Array>(std::vector<QPDFObjectHandle>(), true); |
| @@ -65,20 +71,20 @@ main() | @@ -65,20 +71,20 @@ main() | ||
| 65 | a.setAt(4, QPDFObjectHandle::newNull()); | 71 | a.setAt(4, QPDFObjectHandle::newNull()); |
| 66 | assert(a.at(4).second.isNull()); | 72 | assert(a.at(4).second.isNull()); |
| 67 | 73 | ||
| 68 | - a.erase(a.size() - 1); | 74 | + a.erase(to_i(a.size()) - 1); |
| 69 | assert(a.size() == 5); | 75 | assert(a.size() == 5); |
| 70 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); | 76 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); |
| 71 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); | 77 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); |
| 72 | assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); | 78 | assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); |
| 73 | assert(a.at(4).second.isNull()); | 79 | assert(a.at(4).second.isNull()); |
| 74 | 80 | ||
| 75 | - a.erase(a.size() - 1); | 81 | + a.erase(to_i(a.size()) - 1); |
| 76 | assert(a.size() == 4); | 82 | assert(a.size() == 4); |
| 77 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); | 83 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); |
| 78 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); | 84 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); |
| 79 | assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); | 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 | assert(a.size() == 3); | 88 | assert(a.size() == 3); |
| 83 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); | 89 | assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); |
| 84 | assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); | 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,9 +237,7 @@ QPDFWriter remove ADBE 0 | ||
| 237 | QPDFWriter remove existing Extensions 0 | 237 | QPDFWriter remove existing Extensions 0 |
| 238 | QPDFWriter preserve ADBE 0 | 238 | QPDFWriter preserve ADBE 0 |
| 239 | QPDF_encryption skip 0x28 0 | 239 | QPDF_encryption skip 0x28 0 |
| 240 | -QPDF_encrypt crypt array 0 | ||
| 241 | QPDF_encryption CFM AESV3 0 | 240 | QPDF_encryption CFM AESV3 0 |
| 242 | -QPDFWriter remove Crypt 0 | ||
| 243 | qpdf-c called qpdf_get_pdf_extension_level 0 | 241 | qpdf-c called qpdf_get_pdf_extension_level 0 |
| 244 | qpdf-c called qpdf_set_r5_encryption_parameters 0 | 242 | qpdf-c called qpdf_set_r5_encryption_parameters 0 |
| 245 | qpdf-c called qpdf_set_r6_encryption_parameters 0 | 243 | qpdf-c called qpdf_set_r6_encryption_parameters 0 |
| @@ -423,12 +421,6 @@ QPDFPageObjectHelper externalize inline image 0 | @@ -423,12 +421,6 @@ QPDFPageObjectHelper externalize inline image 0 | ||
| 423 | QPDFPageObjectHelper keep inline image 0 | 421 | QPDFPageObjectHelper keep inline image 0 |
| 424 | QPDFJob image optimize colorspace 0 | 422 | QPDFJob image optimize colorspace 0 |
| 425 | QPDFJob image optimize bits per component 0 | 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 | QPDF xref skipped space 0 | 424 | QPDF xref skipped space 0 |
| 433 | QPDF eof skipping spaces before xref 1 | 425 | QPDF eof skipping spaces before xref 1 |
| 434 | QPDF_encryption user matches owner V < 5 0 | 426 | QPDF_encryption user matches owner V < 5 0 |
| @@ -580,9 +572,7 @@ QPDFAcroFormDocumentHelper copy annotation 3 | @@ -580,9 +572,7 @@ QPDFAcroFormDocumentHelper copy annotation 3 | ||
| 580 | QPDFAcroFormDocumentHelper field with parent 3 | 572 | QPDFAcroFormDocumentHelper field with parent 3 |
| 581 | QPDFAcroFormDocumentHelper modify ap matrix 0 | 573 | QPDFAcroFormDocumentHelper modify ap matrix 0 |
| 582 | QPDFJob copy form fields in split_pages 0 | 574 | QPDFJob copy form fields in split_pages 0 |
| 583 | -QPDFJob keep some fields in pages 0 | ||
| 584 | QPDFJob pages keeping field from original 0 | 575 | QPDFJob pages keeping field from original 0 |
| 585 | -QPDFJob no more fields in pages 0 | ||
| 586 | QPDFObjectHandle merge reuse 0 | 576 | QPDFObjectHandle merge reuse 0 |
| 587 | QPDFObjectHandle merge generate 0 | 577 | QPDFObjectHandle merge generate 0 |
| 588 | QPDFFormFieldObjectHelper get font from /DR 0 | 578 | QPDFFormFieldObjectHelper get font from /DR 0 |
| @@ -592,7 +582,7 @@ QPDFAcroFormDocumentHelper replaced DA token 0 | @@ -592,7 +582,7 @@ QPDFAcroFormDocumentHelper replaced DA token 0 | ||
| 592 | QPDFAcroFormDocumentHelper ap conflict 0 | 582 | QPDFAcroFormDocumentHelper ap conflict 0 |
| 593 | QPDFAcroFormDocumentHelper ap rename 0 | 583 | QPDFAcroFormDocumentHelper ap rename 0 |
| 594 | QPDFAcroFormDocumentHelper /DA parse error 0 | 584 | QPDFAcroFormDocumentHelper /DA parse error 0 |
| 595 | -QPDFAcroFormDocumentHelper AP parse error 0 | 585 | +QPDFAcroFormDocumentHelper AP parse error 1 |
| 596 | QPDFJob copy fields not this file 0 | 586 | QPDFJob copy fields not this file 0 |
| 597 | QPDFJob copy fields non-first from orig 0 | 587 | QPDFJob copy fields non-first from orig 0 |
| 598 | QPDF resolve duplicated page in insert 0 | 588 | QPDF resolve duplicated page in insert 0 |