2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-11-13 08:16:29 +00:00

Refactor QPDF_Array::at

Change the return type to a std::pair<bool, QPDFObjectHandle> in order to
allow a default constructed object handle (which is currently returned to
indicate failure) to become a valid object.
This commit is contained in:
m-holger 2024-03-17 17:14:47 +00:00 committed by m-holger
parent 0afaaea22a
commit 266d479735
4 changed files with 55 additions and 54 deletions

View File

@ -1021,8 +1021,9 @@ QPDFObjectHandle::getArrayItem(int n) const
#endif #endif
{ {
if (auto array = asArray()) { if (auto array = asArray()) {
if (auto result = array->at(n); result.obj != nullptr) { auto result = array->at(n);
return result; if (result.first) {
return result.second;
} else { } else {
objectWarning("returning null for out of bounds array access"); objectWarning("returning null for out of bounds array access");
QTC::TC("qpdf", "QPDFObjectHandle array bounds"); QTC::TC("qpdf", "QPDFObjectHandle array bounds");
@ -1045,7 +1046,7 @@ QPDFObjectHandle::isRectangle() const
{ {
if (auto array = asArray()) { if (auto array = asArray()) {
for (int i = 0; i < 4; ++i) { 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; return false;
} }
} }
@ -1064,7 +1065,7 @@ QPDFObjectHandle::isMatrix() const
{ {
if (auto array = asArray()) { if (auto array = asArray()) {
for (int i = 0; i < 6; ++i) { 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; return false;
} }
} }
@ -1087,7 +1088,7 @@ QPDFObjectHandle::getArrayAsRectangle() const
} }
double items[4]; double items[4];
for (int i = 0; i < 4; ++i) { 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 {}; return {};
} }
} }
@ -1114,7 +1115,7 @@ QPDFObjectHandle::getArrayAsMatrix() const
} }
double items[6]; double items[6];
for (int i = 0; i < 6; ++i) { 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 {}; return {};
} }
} }
@ -1224,7 +1225,7 @@ QPDFObjectHandle
QPDFObjectHandle::eraseItemAndGetOld(int at) QPDFObjectHandle::eraseItemAndGetOld(int at)
{ {
auto array = asArray(); 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); eraseItem(at);
return result; return result;
} }
@ -1764,7 +1765,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
if (auto array = asArray()) { if (auto array = asArray()) {
int n_items = array->size(); int n_items = array->size();
for (int i = 0; i < n_items; ++i) { for (int i = 0; i < n_items; ++i) {
QPDFObjectHandle item = array->at(i); QPDFObjectHandle item = array->at(i).second;
if (item.isStream()) { if (item.isStream()) {
result.push_back(item); result.push_back(item);
} else { } else {
@ -2465,7 +2466,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set& visited, bool stop_at_streams)
auto array = asArray(); auto array = asArray();
int n = array->size(); int n = array->size();
for (int i = 0; i < n; ++i) { 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); items.back().makeDirect(visited, stop_at_streams);
} }
this->obj = QPDF_Array::create(items); this->obj = QPDF_Array::create(items);

View File

@ -184,16 +184,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
p.writeEnd(']'); p.writeEnd(']');
} }
QPDFObjectHandle std::pair<bool, QPDFObjectHandle>
QPDF_Array::at(int n) const noexcept QPDF_Array::at(int n) const noexcept
{ {
if (n < 0 || n >= size()) { if (n < 0 || n >= size()) {
return {}; return {false, {}};
} else if (sp) { } else if (sp) {
auto const& iter = sp->elements.find(n); 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 { } else {
return elements[size_t(n)]; return {true, elements[size_t(n)]};
} }
} }

View File

@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue
{ {
return sp ? sp->size : int(elements.size()); return sp ? sp->size : int(elements.size());
} }
QPDFObjectHandle at(int n) const noexcept; std::pair<bool, QPDFObjectHandle> at(int n) const noexcept;
bool setAt(int n, QPDFObjectHandle const& oh); bool setAt(int n, QPDFObjectHandle const& oh);
std::vector<QPDFObjectHandle> getAsVector() const; std::vector<QPDFObjectHandle> getAsVector() const;
void setFromVector(std::vector<QPDFObjectHandle> const& items); void setFromVector(std::vector<QPDFObjectHandle> const& items);

View File

@ -21,69 +21,69 @@ main()
a.push_back(QPDFObjectHandle::parse("null")); a.push_back(QPDFObjectHandle::parse("null"));
a.push_back(QPDFObjectHandle::parse("/Quack")); a.push_back(QPDFObjectHandle::parse("/Quack"));
assert(a.size() == 5); assert(a.size() == 5);
assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1)); assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1));
assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato")); assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato"));
assert(a.at(2).isNull()); assert(a.at(2).second.isNull());
assert(a.at(3).isNull()); assert(a.at(3).second.isNull());
assert(a.at(4).isName() && (a.at(4).getName() == "/Quack")); assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/Quack"));
a.insert(4, QPDFObjectHandle::parse("/BeforeQuack")); a.insert(4, QPDFObjectHandle::parse("/BeforeQuack"));
assert(a.size() == 6); assert(a.size() == 6);
assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1)); assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1));
assert(a.at(4).isName() && (a.at(4).getName() == "/BeforeQuack")); assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/BeforeQuack"));
assert(a.at(5).isName() && (a.at(5).getName() == "/Quack")); assert(a.at(5).second.isName() && (a.at(5).second.getName() == "/Quack"));
a.insert(2, QPDFObjectHandle::parse("/Third")); a.insert(2, QPDFObjectHandle::parse("/Third"));
assert(a.size() == 7); assert(a.size() == 7);
assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato")); assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato"));
assert(a.at(2).isName() && (a.at(2).getName() == "/Third")); assert(a.at(2).second.isName() && (a.at(2).second.getName() == "/Third"));
assert(a.at(3).isNull()); assert(a.at(3).second.isNull());
assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack"));
a.insert(0, QPDFObjectHandle::parse("/First")); a.insert(0, QPDFObjectHandle::parse("/First"));
assert(a.size() == 8); assert(a.size() == 8);
assert(a.at(0).isName() && (a.at(0).getName() == "/First")); assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
assert(a.at(7).isName() && (a.at(7).getName() == "/Quack")); assert(a.at(7).second.isName() && (a.at(7).second.getName() == "/Quack"));
a.erase(6); a.erase(6);
assert(a.size() == 7); assert(a.size() == 7);
assert(a.at(0).isName() && (a.at(0).getName() == "/First")); assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
assert(a.at(5).isNull()); assert(a.at(5).second.isNull());
assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack"));
a.erase(6); a.erase(6);
assert(a.size() == 6); assert(a.size() == 6);
assert(a.at(0).isName() && (a.at(0).getName() == "/First")); assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
assert(a.at(4).isNull()); assert(a.at(4).second.isNull());
assert(a.at(5).isNull()); assert(a.at(5).second.isNull());
a.setAt(4, QPDFObjectHandle::parse("12")); 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()); a.setAt(4, QPDFObjectHandle::newNull());
assert(a.at(4).isNull()); assert(a.at(4).second.isNull());
a.erase(a.size() - 1); a.erase(a.size() - 1);
assert(a.size() == 5); assert(a.size() == 5);
assert(a.at(0).isName() && (a.at(0).getName() == "/First")); assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
assert(a.at(4).isNull()); assert(a.at(4).second.isNull());
a.erase(a.size() - 1); a.erase(a.size() - 1);
assert(a.size() == 4); assert(a.size() == 4);
assert(a.at(0).isName() && (a.at(0).getName() == "/First")); assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
a.erase(a.size() - 1); a.erase(a.size() - 1);
assert(a.size() == 3); assert(a.size() == 3);
assert(a.at(0).isName() && (a.at(0).getName() == "/First")); assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1)); assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
assert(a.at(2).isString() && (a.at(2).getStringValue() == "potato")); assert(a.at(2).second.isString() && (a.at(2).second.getStringValue() == "potato"));
QPDF pdf; QPDF pdf;
pdf.emptyPDF(); pdf.emptyPDF();
@ -92,13 +92,13 @@ main()
QPDF_Array& b = *obj->as<QPDF_Array>(); QPDF_Array& b = *obj->as<QPDF_Array>();
b.setAt(5, pdf.newIndirectNull()); b.setAt(5, pdf.newIndirectNull());
b.setAt(7, "[0 1 2 3]"_qpdf); b.setAt(7, "[0 1 2 3]"_qpdf);
assert(b.at(3).isNull()); assert(b.at(3).second.isNull());
assert(b.at(8).isNull()); assert(b.at(8).second.isNull());
assert(b.at(5).isIndirect()); assert(b.at(5).second.isIndirect());
assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
auto c = b.copy(true); auto c = b.copy(true);
auto d = b.copy(false); 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(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 ]"); assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");