aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--fuzz/CMakeLists.txt2
-rw-r--r--fuzz/qpdf_extra/65773.fuzz1
-rw-r--r--fuzz/qpdf_extra/65777.fuzzbin0 -> 67 bytes
-rw-r--r--fuzz/qtest/fuzz.test2
-rw-r--r--include/qpdf/JSON.hh2
-rw-r--r--libqpdf/JSON.cc11
-rw-r--r--libqpdf/QPDF.cc9
-rw-r--r--libqpdf/QPDFJob_json.cc24
-rw-r--r--libtests/json.cc6
10 files changed, 38 insertions, 23 deletions
diff --git a/ChangeLog b/ChangeLog
index b36ebaa6..2265e079 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
new file mode 100644
index 00000000..066c960b
--- /dev/null
+++ b/fuzz/qpdf_extra/65777.fuzz
Binary files differ
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"