Commit 266d4797350044994ad1578eebdd104774bd38cf

Authored by m-holger
Committed by m-holger
1 parent 0afaaea2

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.
libqpdf/QPDFObjectHandle.cc
@@ -1021,8 +1021,9 @@ QPDFObjectHandle::getArrayItem(int n) const @@ -1021,8 +1021,9 @@ QPDFObjectHandle::getArrayItem(int n) const
1021 #endif 1021 #endif
1022 { 1022 {
1023 if (auto array = asArray()) { 1023 if (auto array = asArray()) {
1024 - if (auto result = array->at(n); result.obj != nullptr) {  
1025 - return result; 1024 + auto result = array->at(n);
  1025 + if (result.first) {
  1026 + return result.second;
1026 } else { 1027 } else {
1027 objectWarning("returning null for out of bounds array access"); 1028 objectWarning("returning null for out of bounds array access");
1028 QTC::TC("qpdf", "QPDFObjectHandle array bounds"); 1029 QTC::TC("qpdf", "QPDFObjectHandle array bounds");
@@ -1045,7 +1046,7 @@ QPDFObjectHandle::isRectangle() const @@ -1045,7 +1046,7 @@ QPDFObjectHandle::isRectangle() const
1045 { 1046 {
1046 if (auto array = asArray()) { 1047 if (auto array = asArray()) {
1047 for (int i = 0; i < 4; ++i) { 1048 for (int i = 0; i < 4; ++i) {
1048 - if (auto item = array->at(i); !(item.obj && item.isNumber())) { 1049 + if (auto item = array->at(i).second; !item.isNumber()) {
1049 return false; 1050 return false;
1050 } 1051 }
1051 } 1052 }
@@ -1064,7 +1065,7 @@ QPDFObjectHandle::isMatrix() const @@ -1064,7 +1065,7 @@ QPDFObjectHandle::isMatrix() const
1064 { 1065 {
1065 if (auto array = asArray()) { 1066 if (auto array = asArray()) {
1066 for (int i = 0; i < 6; ++i) { 1067 for (int i = 0; i < 6; ++i) {
1067 - if (auto item = array->at(i); !(item.obj && item.isNumber())) { 1068 + if (auto item = array->at(i).second; !item.isNumber()) {
1068 return false; 1069 return false;
1069 } 1070 }
1070 } 1071 }
@@ -1087,7 +1088,7 @@ QPDFObjectHandle::getArrayAsRectangle() const @@ -1087,7 +1088,7 @@ QPDFObjectHandle::getArrayAsRectangle() const
1087 } 1088 }
1088 double items[4]; 1089 double items[4];
1089 for (int i = 0; i < 4; ++i) { 1090 for (int i = 0; i < 4; ++i) {
1090 - if (!array->at(i).getValueAsNumber(items[i])) { 1091 + if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) {
1091 return {}; 1092 return {};
1092 } 1093 }
1093 } 1094 }
@@ -1114,7 +1115,7 @@ QPDFObjectHandle::getArrayAsMatrix() const @@ -1114,7 +1115,7 @@ QPDFObjectHandle::getArrayAsMatrix() const
1114 } 1115 }
1115 double items[6]; 1116 double items[6];
1116 for (int i = 0; i < 6; ++i) { 1117 for (int i = 0; i < 6; ++i) {
1117 - if (!array->at(i).getValueAsNumber(items[i])) { 1118 + if (auto item = array->at(i).second; !item.getValueAsNumber(items[i])) {
1118 return {}; 1119 return {};
1119 } 1120 }
1120 } 1121 }
@@ -1224,7 +1225,7 @@ QPDFObjectHandle @@ -1224,7 +1225,7 @@ QPDFObjectHandle
1224 QPDFObjectHandle::eraseItemAndGetOld(int at) 1225 QPDFObjectHandle::eraseItemAndGetOld(int at)
1225 { 1226 {
1226 auto array = asArray(); 1227 auto array = asArray();
1227 - auto result = (array && at < array->size() && at >= 0) ? array->at(at) : newNull(); 1228 + auto result = (array && at < array->size() && at >= 0) ? array->at(at).second : newNull();
1228 eraseItem(at); 1229 eraseItem(at);
1229 return result; 1230 return result;
1230 } 1231 }
@@ -1764,7 +1765,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( @@ -1764,7 +1765,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
1764 if (auto array = asArray()) { 1765 if (auto array = asArray()) {
1765 int n_items = array->size(); 1766 int n_items = array->size();
1766 for (int i = 0; i < n_items; ++i) { 1767 for (int i = 0; i < n_items; ++i) {
1767 - QPDFObjectHandle item = array->at(i); 1768 + QPDFObjectHandle item = array->at(i).second;
1768 if (item.isStream()) { 1769 if (item.isStream()) {
1769 result.push_back(item); 1770 result.push_back(item);
1770 } else { 1771 } else {
@@ -2465,7 +2466,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams) @@ -2465,7 +2466,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
2465 auto array = asArray(); 2466 auto array = asArray();
2466 int n = array->size(); 2467 int n = array->size();
2467 for (int i = 0; i < n; ++i) { 2468 for (int i = 0; i < n; ++i) {
2468 - items.push_back(array->at(i)); 2469 + items.push_back(array->at(i).second);
2469 items.back().makeDirect(visited, stop_at_streams); 2470 items.back().makeDirect(visited, stop_at_streams);
2470 } 2471 }
2471 this->obj = QPDF_Array::create(items); 2472 this->obj = QPDF_Array::create(items);
libqpdf/QPDF_Array.cc
@@ -184,16 +184,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer&amp; p) @@ -184,16 +184,16 @@ QPDF_Array::writeJSON(int json_version, JSON::Writer&amp; p)
184 p.writeEnd(']'); 184 p.writeEnd(']');
185 } 185 }
186 186
187 -QPDFObjectHandle 187 +std::pair<bool, QPDFObjectHandle>
188 QPDF_Array::at(int n) const noexcept 188 QPDF_Array::at(int n) const noexcept
189 { 189 {
190 if (n < 0 || n >= size()) { 190 if (n < 0 || n >= size()) {
191 - return {}; 191 + return {false, {}};
192 } else if (sp) { 192 } else if (sp) {
193 auto const& iter = sp->elements.find(n); 193 auto const& iter = sp->elements.find(n);
194 - return iter == sp->elements.end() ? null_oh : (*iter).second; 194 + return {true, iter == sp->elements.end() ? null_oh : (*iter).second};
195 } else { 195 } else {
196 - return elements[size_t(n)]; 196 + return {true, elements[size_t(n)]};
197 } 197 }
198 } 198 }
199 199
libqpdf/qpdf/QPDF_Array.hh
@@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue @@ -30,7 +30,7 @@ class QPDF_Array: public QPDFValue
30 { 30 {
31 return sp ? sp->size : int(elements.size()); 31 return sp ? sp->size : int(elements.size());
32 } 32 }
33 - QPDFObjectHandle at(int n) const noexcept; 33 + std::pair<bool, QPDFObjectHandle> at(int n) const noexcept;
34 bool setAt(int n, QPDFObjectHandle const& oh); 34 bool setAt(int n, QPDFObjectHandle const& oh);
35 std::vector<QPDFObjectHandle> getAsVector() const; 35 std::vector<QPDFObjectHandle> getAsVector() const;
36 void setFromVector(std::vector<QPDFObjectHandle> const& items); 36 void setFromVector(std::vector<QPDFObjectHandle> const& items);
libtests/sparse_array.cc
@@ -21,69 +21,69 @@ main() @@ -21,69 +21,69 @@ main()
21 a.push_back(QPDFObjectHandle::parse("null")); 21 a.push_back(QPDFObjectHandle::parse("null"));
22 a.push_back(QPDFObjectHandle::parse("/Quack")); 22 a.push_back(QPDFObjectHandle::parse("/Quack"));
23 assert(a.size() == 5); 23 assert(a.size() == 5);
24 - assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1));  
25 - assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato"));  
26 - assert(a.at(2).isNull());  
27 - assert(a.at(3).isNull());  
28 - assert(a.at(4).isName() && (a.at(4).getName() == "/Quack")); 24 + assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1));
  25 + assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato"));
  26 + assert(a.at(2).second.isNull());
  27 + assert(a.at(3).second.isNull());
  28 + assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/Quack"));
29 29
30 a.insert(4, QPDFObjectHandle::parse("/BeforeQuack")); 30 a.insert(4, QPDFObjectHandle::parse("/BeforeQuack"));
31 assert(a.size() == 6); 31 assert(a.size() == 6);
32 - assert(a.at(0).isInteger() && (a.at(0).getIntValue() == 1));  
33 - assert(a.at(4).isName() && (a.at(4).getName() == "/BeforeQuack"));  
34 - assert(a.at(5).isName() && (a.at(5).getName() == "/Quack")); 32 + assert(a.at(0).second.isInteger() && (a.at(0).second.getIntValue() == 1));
  33 + assert(a.at(4).second.isName() && (a.at(4).second.getName() == "/BeforeQuack"));
  34 + assert(a.at(5).second.isName() && (a.at(5).second.getName() == "/Quack"));
35 35
36 a.insert(2, QPDFObjectHandle::parse("/Third")); 36 a.insert(2, QPDFObjectHandle::parse("/Third"));
37 assert(a.size() == 7); 37 assert(a.size() == 7);
38 - assert(a.at(1).isString() && (a.at(1).getStringValue() == "potato"));  
39 - assert(a.at(2).isName() && (a.at(2).getName() == "/Third"));  
40 - assert(a.at(3).isNull());  
41 - assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); 38 + assert(a.at(1).second.isString() && (a.at(1).second.getStringValue() == "potato"));
  39 + assert(a.at(2).second.isName() && (a.at(2).second.getName() == "/Third"));
  40 + assert(a.at(3).second.isNull());
  41 + assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack"));
42 42
43 a.insert(0, QPDFObjectHandle::parse("/First")); 43 a.insert(0, QPDFObjectHandle::parse("/First"));
44 assert(a.size() == 8); 44 assert(a.size() == 8);
45 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
46 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
47 - assert(a.at(7).isName() && (a.at(7).getName() == "/Quack")); 45 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  46 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  47 + assert(a.at(7).second.isName() && (a.at(7).second.getName() == "/Quack"));
48 48
49 a.erase(6); 49 a.erase(6);
50 assert(a.size() == 7); 50 assert(a.size() == 7);
51 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
52 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
53 - assert(a.at(5).isNull());  
54 - assert(a.at(6).isName() && (a.at(6).getName() == "/Quack")); 51 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  52 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  53 + assert(a.at(5).second.isNull());
  54 + assert(a.at(6).second.isName() && (a.at(6).second.getName() == "/Quack"));
55 55
56 a.erase(6); 56 a.erase(6);
57 assert(a.size() == 6); 57 assert(a.size() == 6);
58 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
59 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
60 - assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));  
61 - assert(a.at(4).isNull());  
62 - assert(a.at(5).isNull()); 58 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  59 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  60 + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
  61 + assert(a.at(4).second.isNull());
  62 + assert(a.at(5).second.isNull());
63 63
64 a.setAt(4, QPDFObjectHandle::parse("12")); 64 a.setAt(4, QPDFObjectHandle::parse("12"));
65 - assert(a.at(4).isInteger() && (a.at(4).getIntValue() == 12)); 65 + assert(a.at(4).second.isInteger() && (a.at(4).second.getIntValue() == 12));
66 a.setAt(4, QPDFObjectHandle::newNull()); 66 a.setAt(4, QPDFObjectHandle::newNull());
67 - assert(a.at(4).isNull()); 67 + assert(a.at(4).second.isNull());
68 68
69 a.erase(a.size() - 1); 69 a.erase(a.size() - 1);
70 assert(a.size() == 5); 70 assert(a.size() == 5);
71 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
72 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
73 - assert(a.at(3).isName() && (a.at(3).getName() == "/Third"));  
74 - assert(a.at(4).isNull()); 71 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  72 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  73 + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
  74 + assert(a.at(4).second.isNull());
75 75
76 a.erase(a.size() - 1); 76 a.erase(a.size() - 1);
77 assert(a.size() == 4); 77 assert(a.size() == 4);
78 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
79 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
80 - assert(a.at(3).isName() && (a.at(3).getName() == "/Third")); 78 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  79 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  80 + assert(a.at(3).second.isName() && (a.at(3).second.getName() == "/Third"));
81 81
82 a.erase(a.size() - 1); 82 a.erase(a.size() - 1);
83 assert(a.size() == 3); 83 assert(a.size() == 3);
84 - assert(a.at(0).isName() && (a.at(0).getName() == "/First"));  
85 - assert(a.at(1).isInteger() && (a.at(1).getIntValue() == 1));  
86 - assert(a.at(2).isString() && (a.at(2).getStringValue() == "potato")); 84 + assert(a.at(0).second.isName() && (a.at(0).second.getName() == "/First"));
  85 + assert(a.at(1).second.isInteger() && (a.at(1).second.getIntValue() == 1));
  86 + assert(a.at(2).second.isString() && (a.at(2).second.getStringValue() == "potato"));
87 87
88 QPDF pdf; 88 QPDF pdf;
89 pdf.emptyPDF(); 89 pdf.emptyPDF();
@@ -92,13 +92,13 @@ main() @@ -92,13 +92,13 @@ main()
92 QPDF_Array& b = *obj->as<QPDF_Array>(); 92 QPDF_Array& b = *obj->as<QPDF_Array>();
93 b.setAt(5, pdf.newIndirectNull()); 93 b.setAt(5, pdf.newIndirectNull());
94 b.setAt(7, "[0 1 2 3]"_qpdf); 94 b.setAt(7, "[0 1 2 3]"_qpdf);
95 - assert(b.at(3).isNull());  
96 - assert(b.at(8).isNull());  
97 - assert(b.at(5).isIndirect()); 95 + assert(b.at(3).second.isNull());
  96 + assert(b.at(8).second.isNull());
  97 + assert(b.at(5).second.isIndirect());
98 assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); 98 assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
99 auto c = b.copy(true); 99 auto c = b.copy(true);
100 auto d = b.copy(false); 100 auto d = b.copy(false);
101 - b.at(7).setArrayItem(2, "42"_qpdf); 101 + b.at(7).second.setArrayItem(2, "42"_qpdf);
102 assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); 102 assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]");
103 assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); 103 assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
104 104