From 266d4797350044994ad1578eebdd104774bd38cf Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 17 Mar 2024 17:14:47 +0000 Subject: [PATCH] Refactor QPDF_Array::at Change the return type to a std::pair in order to allow a default constructed object handle (which is currently returned to indicate failure) to become a valid object. --- libqpdf/QPDFObjectHandle.cc | 19 ++++----- libqpdf/QPDF_Array.cc | 8 ++-- libqpdf/qpdf/QPDF_Array.hh | 2 +- libtests/sparse_array.cc | 80 ++++++++++++++++++------------------- 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index b4583b13..dbe109a2 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -1021,8 +1021,9 @@ QPDFObjectHandle::getArrayItem(int n) const #endif { if (auto array = asArray()) { - if (auto result = array->at(n); result.obj != nullptr) { - return result; + auto result = array->at(n); + if (result.first) { + return result.second; } else { objectWarning("returning null for out of bounds array access"); QTC::TC("qpdf", "QPDFObjectHandle array bounds"); @@ -1045,7 +1046,7 @@ QPDFObjectHandle::isRectangle() const { if (auto array = asArray()) { for (int i = 0; i < 4; ++i) { - if (auto item = array->at(i); !(item.obj && item.isNumber())) { + if (auto item = array->at(i).second; !item.isNumber()) { return false; } } @@ -1064,7 +1065,7 @@ QPDFObjectHandle::isMatrix() const { if (auto array = asArray()) { for (int i = 0; i < 6; ++i) { - if (auto item = array->at(i); !(item.obj && item.isNumber())) { + if (auto item = array->at(i).second; !item.isNumber()) { return false; } } @@ -1087,7 +1088,7 @@ QPDFObjectHandle::getArrayAsRectangle() const } double items[4]; for (int i = 0; i < 4; ++i) { - if (!array->at(i).getValueAsNumber(items[i])) { + if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) { return {}; } } @@ -1114,7 +1115,7 @@ QPDFObjectHandle::getArrayAsMatrix() const } double items[6]; for (int i = 0; i < 6; ++i) { - if (!array->at(i).getValueAsNumber(items[i])) { + if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) { return {}; } } @@ -1224,7 +1225,7 @@ QPDFObjectHandle QPDFObjectHandle::eraseItemAndGetOld(int at) { auto array = asArray(); - auto result = (array && at < array->size() && at >= 0) ? array->at(at) : newNull(); + auto result = (array && at < array->size() && at >= 0) ? array->at(at).second : newNull(); eraseItem(at); return result; } @@ -1764,7 +1765,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( if (auto array = asArray()) { int n_items = array->size(); for (int i = 0; i < n_items; ++i) { - QPDFObjectHandle item = array->at(i); + QPDFObjectHandle item = array->at(i).second; if (item.isStream()) { result.push_back(item); } else { @@ -2465,7 +2466,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams) auto array = asArray(); int n = array->size(); for (int i = 0; i < n; ++i) { - items.push_back(array->at(i)); + items.push_back(array->at(i).second); items.back().makeDirect(visited, stop_at_streams); } this->obj = QPDF_Array::create(items); diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc index 315d297e..4ce15ad8 100644 --- a/libqpdf/QPDF_Array.cc +++ b/libqpdf/QPDF_Array.cc @@ -184,16 +184,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer& p) p.writeEnd(']'); } -QPDFObjectHandle +std::pair QPDF_Array::at(int n) const noexcept { if (n < 0 || n >= size()) { - return {}; + return {false, {}}; } else if (sp) { auto const& iter = sp->elements.find(n); - return iter == sp->elements.end() ? null_oh : (*iter).second; + return {true, iter == sp->elements.end() ? null_oh : (*iter).second}; } else { - return elements[size_t(n)]; + return {true, elements[size_t(n)]}; } } diff --git a/libqpdf/qpdf/QPDF_Array.hh b/libqpdf/qpdf/QPDF_Array.hh index 88b2a3d3..645e5919 100644 --- a/libqpdf/qpdf/QPDF_Array.hh +++ b/libqpdf/qpdf/QPDF_Array.hh @@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue { return sp ? sp->size : int(elements.size()); } - QPDFObjectHandle at(int n) const noexcept; + std::pair at(int n) const noexcept; bool setAt(int n, QPDFObjectHandle const& oh); std::vector getAsVector() const; void setFromVector(std::vector const& items); diff --git a/libtests/sparse_array.cc b/libtests/sparse_array.cc index 9405a89b..2182d5a9 100644 --- a/libtests/sparse_array.cc +++ b/libtests/sparse_array.cc @@ -21,69 +21,69 @@ main() a.push_back(QPDFObjectHandle::parse("null")); a.push_back(QPDFObjectHandle::parse("/Quack")); assert(a.size() == 5); - assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1)); - assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato")); - assert(a.at(2).isNull()); - assert(a.at(3).isNull()); - assert(a.at(4).isName() && (a.at(4).getName() == "/Quack")); + assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1)); + assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato")); + assert(a.at(2).second.isNull()); + assert(a.at(3).second.isNull()); + assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/Quack")); a.insert(4, QPDFObjectHandle::parse("/BeforeQuack")); assert(a.size() == 6); - assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1)); - assert(a.at(4).isName() && (a.at(4).getName() == "/BeforeQuack")); - assert(a.at(5).isName() && (a.at(5).getName() == "/Quack")); + assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1)); + assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/BeforeQuack")); + assert(a.at(5).second.isName() && (a.at(5).second.getName() == "/Quack")); a.insert(2, QPDFObjectHandle::parse("/Third")); assert(a.size() == 7); - assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato")); - assert(a.at(2).isName() && (a.at(2).getName() == "/Third")); - assert(a.at(3).isNull()); - assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); + assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato")); + assert(a.at(2).second.isName() && (a.at(2).second.getName() == "/Third")); + assert(a.at(3).second.isNull()); + assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack")); a.insert(0, QPDFObjectHandle::parse("/First")); assert(a.size() == 8); - assert(a.at(0).isName() && (a.at(0).getName() == "/First")); - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); - assert(a.at(7).isName() && (a.at(7).getName() == "/Quack")); + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); + assert(a.at(7).second.isName() && (a.at(7).second.getName() == "/Quack")); a.erase(6); assert(a.size() == 7); - assert(a.at(0).isName() && (a.at(0).getName() == "/First")); - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); - assert(a.at(5).isNull()); - assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); + assert(a.at(5).second.isNull()); + assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack")); a.erase(6); assert(a.size() == 6); - assert(a.at(0).isName() && (a.at(0).getName() == "/First")); - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); - assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); - assert(a.at(4).isNull()); - assert(a.at(5).isNull()); + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); + assert(a.at(4).second.isNull()); + assert(a.at(5).second.isNull()); a.setAt(4, QPDFObjectHandle::parse("12")); - assert(a.at(4).isInteger() && (a.at(4).getIntValue() == 12)); + assert(a.at(4).second.isInteger() && (a.at(4).second.getIntValue() == 12)); a.setAt(4, QPDFObjectHandle::newNull()); - assert(a.at(4).isNull()); + assert(a.at(4).second.isNull()); a.erase(a.size() - 1); assert(a.size() == 5); - assert(a.at(0).isName() && (a.at(0).getName() == "/First")); - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); - assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); - assert(a.at(4).isNull()); + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); + assert(a.at(4).second.isNull()); a.erase(a.size() - 1); assert(a.size() == 4); - assert(a.at(0).isName() && (a.at(0).getName() == "/First")); - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); - assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third")); a.erase(a.size() - 1); assert(a.size() == 3); - assert(a.at(0).isName() && (a.at(0).getName() == "/First")); - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); - assert(a.at(2).isString() && (a.at(2).getStringValue() == "potato")); + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First")); + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1)); + assert(a.at(2).second.isString() && (a.at(2).second.getStringValue() == "potato")); QPDF pdf; pdf.emptyPDF(); @@ -92,13 +92,13 @@ main() QPDF_Array& b = *obj->as(); b.setAt(5, pdf.newIndirectNull()); b.setAt(7, "[0 1 2 3]"_qpdf); - assert(b.at(3).isNull()); - assert(b.at(8).isNull()); - assert(b.at(5).isIndirect()); + assert(b.at(3).second.isNull()); + assert(b.at(8).second.isNull()); + assert(b.at(5).second.isIndirect()); assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); auto c = b.copy(true); auto d = b.copy(false); - b.at(7).setArrayItem(2, "42"_qpdf); + b.at(7).second.setArrayItem(2, "42"_qpdf); assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");