diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | fuzz/CMakeLists.txt | 2 | ||||
-rw-r--r-- | fuzz/qpdf_extra/65773.fuzz | 1 | ||||
-rw-r--r-- | fuzz/qpdf_extra/65777.fuzz | bin | 0 -> 67 bytes | |||
-rw-r--r-- | fuzz/qtest/fuzz.test | 2 | ||||
-rw-r--r-- | include/qpdf/JSON.hh | 2 | ||||
-rw-r--r-- | libqpdf/JSON.cc | 11 | ||||
-rw-r--r-- | libqpdf/QPDF.cc | 9 | ||||
-rw-r--r-- | libqpdf/QPDFJob_json.cc | 24 | ||||
-rw-r--r-- | libtests/json.cc | 6 |
10 files changed, 38 insertions, 23 deletions
@@ -1,3 +1,7 @@ +2024-01-15 Jay Berkenbilt <ejb@ql.org> + + * Add JSON::getDictItem (from m-holger) + 2024-01-10 Jay Berkenbilt <ejb@ql.org> * Allow --overlay and --underlay to be repeated. They may appear diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index df1fa807..e4a8cf36 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -111,6 +111,8 @@ set(CORPUS_OTHER 37740.fuzz 57639.fuzz 65681.fuzz + 65773.fuzz + 65777.fuzz ) set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus) diff --git a/fuzz/qpdf_extra/65773.fuzz b/fuzz/qpdf_extra/65773.fuzz new file mode 100644 index 00000000..2d0aabf5 --- /dev/null +++ b/fuzz/qpdf_extra/65773.fuzz @@ -0,0 +1 @@ +trailer<</Root<<[-2147483648 7 R 8 4 R]>>>>
\ No newline at end of file diff --git a/fuzz/qpdf_extra/65777.fuzz b/fuzz/qpdf_extra/65777.fuzz Binary files differnew file mode 100644 index 00000000..066c960b --- /dev/null +++ b/fuzz/qpdf_extra/65777.fuzz diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index adce995c..7ca371fd 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -20,7 +20,7 @@ my @fuzzers = ( ['pngpredictor' => 1], ['runlength' => 6], ['tiffpredictor' => 1], - ['qpdf' => 54], # increment when adding new files + ['qpdf' => 56], # increment when adding new files ); my $n_tests = 0; diff --git a/include/qpdf/JSON.hh b/include/qpdf/JSON.hh index 81abe89c..e3c8a7dc 100644 --- a/include/qpdf/JSON.hh +++ b/include/qpdf/JSON.hh @@ -162,6 +162,8 @@ class JSON QPDF_DLL bool isNull() const; QPDF_DLL + JSON getDictItem(std::string const& key) const; + QPDF_DLL bool forEachDictItem(std::function<void(std::string const& key, JSON value)> fn) const; QPDF_DLL bool forEachArrayItem(std::function<void(JSON value)> fn) const; diff --git a/libqpdf/JSON.cc b/libqpdf/JSON.cc index f6401642..35b8fd76 100644 --- a/libqpdf/JSON.cc +++ b/libqpdf/JSON.cc @@ -410,6 +410,17 @@ JSON::isNull() const return m->value->type_code == vt_null; } +JSON +JSON::getDictItem(std::string const& key) const +{ + if (auto v = dynamic_cast<JSON_dictionary const*>(m->value.get())) { + if (auto it = v->members.find(key); it != v->members.end()) { + return it->second; + } + } + return makeNull(); +} + bool JSON::forEachDictItem(std::function<void(std::string const& key, JSON value)> fn) const { diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 89d4a0a8..8cff3dfd 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -709,10 +709,11 @@ QPDF::read_xref(qpdf_offset_t xref_offset) // Make sure we keep only the highest generation for any object. QPDFObjGen last_og{-1, 0}; - for (auto const& og: m->xref_table) { - if (og.first.getObj() == last_og.getObj()) + for (auto const& item: m->xref_table) { + auto id = item.first.getObj(); + if (id == last_og.getObj() && id > 0) removeObject(last_og); - last_og = og.first; + last_og = item.first; } } @@ -2405,7 +2406,7 @@ QPDF::getCompressibleObjGens() while (!queue.empty()) { auto obj = queue.back(); queue.pop_back(); - if (obj.isIndirect()) { + if (obj.getObjectID() > 0) { QPDFObjGen og = obj.getObjGen(); const size_t id = toS(og.getObj() - 1); if (id >= max_obj) diff --git a/libqpdf/QPDFJob_json.cc b/libqpdf/QPDFJob_json.cc index fefe8fff..83bc856c 100644 --- a/libqpdf/QPDFJob_json.cc +++ b/libqpdf/QPDFJob_json.cc @@ -59,7 +59,7 @@ namespace void beginUnderOverlay(JSON const& j); - std::list<std::shared_ptr<JSONHandler>> json_handlers; + std::vector<std::shared_ptr<JSONHandler>> json_handlers; bool partial; JSONHandler* jh{nullptr}; // points to last of json_handlers std::shared_ptr<QPDFJob::Config> c_main; @@ -100,7 +100,7 @@ Handlers::bindJSON(void (Handlers::*f)(JSON)) void Handlers::initHandlers() { - this->json_handlers.push_back(std::make_shared<JSONHandler>()); + this->json_handlers.emplace_back(std::make_shared<JSONHandler>()); this->jh = this->json_handlers.back().get(); jh->addDictHandlers( [](std::string const&, JSON) {}, @@ -184,8 +184,8 @@ Handlers::pushKey(std::string const& key) { auto new_jh = std::make_shared<JSONHandler>(); this->jh->addDictKeyHandler(key, new_jh); - this->json_handlers.push_back(new_jh); this->jh = new_jh.get(); + this->json_handlers.emplace_back(std::move(new_jh)); } void @@ -205,8 +205,8 @@ Handlers::beginArray(json_handler_t start_fn, bare_handler_t end_fn) [end_fn](std::string const&) { end_fn(); }, item_jh); jh->addFallbackHandler(item_jh); - this->json_handlers.push_back(item_jh); this->jh = item_jh.get(); + this->json_handlers.emplace_back(std::move(item_jh)); } void @@ -232,14 +232,8 @@ void Handlers::beginUnderOverlay(JSON const& j) { // File has to be processed before items, so handle it here. - bool file_seen = false; std::string file; - j.forEachDictItem([&](std::string const& key, JSON const& value) { - if (key == "file") { - file_seen = value.getString(file); - } - }); - if (!file_seen) { + if (!j.getDictItem("file").getString(file)) { QTC::TC("qpdf", "QPDFJob json over/under no file"); usage("file is required in underlay/overlay specification"); } @@ -488,14 +482,8 @@ Handlers::endPagesArray() void Handlers::beginPages(JSON j) { - bool file_seen = false; std::string file; - j.forEachDictItem([&](std::string const& key, JSON const& value) { - if (key == "file") { - file_seen = value.getString(file); - } - }); - if (!file_seen) { + if (!j.getDictItem("file").getString(file)) { QTC::TC("qpdf", "QPDFJob json pages no file"); usage("file is required in page specification"); } diff --git a/libtests/json.cc b/libtests/json.cc index 98e332e7..f265f6f6 100644 --- a/libtests/json.cc +++ b/libtests/json.cc @@ -78,6 +78,12 @@ test_main() jmap.addDictionaryMember("empty_dict", JSON::makeDictionary()); jmap.addDictionaryMember("empty_list", JSON::makeArray()); jmap.addDictionaryMember("single", JSON::makeArray()).addArrayElement(JSON::makeInt(12)); + std::string jm_str; + assert(jmap.getDictItem("b").getString(jm_str)); + assert(!jmap.getDictItem("b2").getString(jm_str)); + assert(!jstr2.getDictItem("b").getString(jm_str)); + assert(jm_str == "a\tb"); + check( jmap, "{\n" |