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
parent e9166457fa
commit 7a7a8c4471
4 changed files with 55 additions and 54 deletions

View File

@ -771,8 +771,9 @@ QPDFObjectHandle
QPDFObjectHandle::getArrayItem(int n)
{
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");
@ -790,7 +791,7 @@ QPDFObjectHandle::isRectangle()
{
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;
}
}
@ -804,7 +805,7 @@ QPDFObjectHandle::isMatrix()
{
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;
}
}
@ -822,7 +823,7 @@ QPDFObjectHandle::getArrayAsRectangle()
}
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 {};
}
}
@ -844,7 +845,7 @@ QPDFObjectHandle::getArrayAsMatrix()
}
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 {};
}
}
@ -949,7 +950,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;
}
@ -1443,7 +1444,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 {
@ -2105,7 +2106,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);

View File

@ -186,16 +186,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
p.writeEnd(']');
}
QPDFObjectHandle
std::pair<bool, QPDFObjectHandle>
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)]};
}
}

View File

@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue
{
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);
std::vector<QPDFObjectHandle> getAsVector() const;
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("/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<QPDF_Array>();
b.setAt(5, pdf.getObject(5, 0));
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 5 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 5 0 R null [ 0 1 42 3 ] null null ]");
assert(d->unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]");