Commit 1b7c87279a1f78c881c1e7010102f8909e8356d4

Authored by m-holger
1 parent 117a35dc

Use QPDFObjectHandle::as_array to iterate over arrays in library

libqpdf/QPDF.cc
@@ -2346,9 +2346,8 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top) @@ -2346,9 +2346,8 @@ QPDF::reserveObjects(QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top)
2346 2346
2347 if (foreign_tc == ::ot_array) { 2347 if (foreign_tc == ::ot_array) {
2348 QTC::TC("qpdf", "QPDF reserve array"); 2348 QTC::TC("qpdf", "QPDF reserve array");
2349 - int n = foreign.getArrayNItems();  
2350 - for (int i = 0; i < n; ++i) {  
2351 - reserveObjects(foreign.getArrayItem(i), obj_copier, false); 2349 + for (auto const& item: foreign.as_array()) {
  2350 + reserveObjects(item, obj_copier, false);
2352 } 2351 }
2353 } else if (foreign_tc == ::ot_dictionary) { 2352 } else if (foreign_tc == ::ot_dictionary) {
2354 QTC::TC("qpdf", "QPDF reserve dictionary"); 2353 QTC::TC("qpdf", "QPDF reserve dictionary");
@@ -2384,11 +2383,8 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier&amp; obj_cop @@ -2384,11 +2383,8 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier&amp; obj_cop
2384 } else if (foreign_tc == ::ot_array) { 2383 } else if (foreign_tc == ::ot_array) {
2385 QTC::TC("qpdf", "QPDF replace array"); 2384 QTC::TC("qpdf", "QPDF replace array");
2386 result = QPDFObjectHandle::newArray(); 2385 result = QPDFObjectHandle::newArray();
2387 - int n = foreign.getArrayNItems();  
2388 - for (int i = 0; i < n; ++i) {  
2389 - result.appendItem(  
2390 - // line-break  
2391 - replaceForeignIndirectObjects(foreign.getArrayItem(i), obj_copier, false)); 2386 + for (auto const& item: foreign.as_array()) {
  2387 + result.appendItem(replaceForeignIndirectObjects(item, obj_copier, false));
2392 } 2388 }
2393 } else if (foreign_tc == ::ot_dictionary) { 2389 } else if (foreign_tc == ::ot_dictionary) {
2394 QTC::TC("qpdf", "QPDF replace dictionary"); 2390 QTC::TC("qpdf", "QPDF replace dictionary");
@@ -2714,11 +2710,8 @@ QPDF::getCompressibleObjGens() @@ -2714,11 +2710,8 @@ QPDF::getCompressibleObjGens()
2714 queue.emplace_back(iter->second); 2710 queue.emplace_back(iter->second);
2715 } 2711 }
2716 } 2712 }
2717 - } else if (obj.isArray()) {  
2718 - int n = obj.getArrayNItems();  
2719 - for (int i = 1; i <= n; ++i) {  
2720 - queue.push_back(obj.getArrayItem(n - i));  
2721 - } 2713 + } else if (auto items = obj.as_array()) {
  2714 + queue.insert(queue.end(), items.crbegin(), items.crend());
2722 } 2715 }
2723 } 2716 }
2724 2717
libqpdf/QPDFAcroFormDocumentHelper.cc
@@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
7 #include <qpdf/QUtil.hh> 7 #include <qpdf/QUtil.hh>
8 #include <qpdf/ResourceFinder.hh> 8 #include <qpdf/ResourceFinder.hh>
9 9
  10 +using namespace qpdf;
  11 +
10 QPDFAcroFormDocumentHelper::Members::Members() : 12 QPDFAcroFormDocumentHelper::Members::Members() :
11 cache_valid(false) 13 cache_valid(false)
12 { 14 {
@@ -239,26 +241,25 @@ QPDFAcroFormDocumentHelper::analyze() @@ -239,26 +241,25 @@ QPDFAcroFormDocumentHelper::analyze()
239 return; 241 return;
240 } 242 }
241 m->cache_valid = true; 243 m->cache_valid = true;
242 - QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm"); 244 + QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm");
243 if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) { 245 if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) {
244 return; 246 return;
245 } 247 }
246 QPDFObjectHandle fields = acroform.getKey("/Fields"); 248 QPDFObjectHandle fields = acroform.getKey("/Fields");
247 - if (!fields.isArray()) { 249 + if (auto fa = fields.as_array(strict)) {
  250 + // Traverse /AcroForm to find annotations and map them bidirectionally to fields.
  251 +
  252 + QPDFObjGen::set visited;
  253 + QPDFObjectHandle null(QPDFObjectHandle::newNull());
  254 + for (auto const& field: fa) {
  255 + traverseField(field, null, 0, visited);
  256 + }
  257 + } else {
248 QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array"); 258 QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array");
249 acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring"); 259 acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring");
250 fields = QPDFObjectHandle::newArray(); 260 fields = QPDFObjectHandle::newArray();
251 } 261 }
252 262
253 - // Traverse /AcroForm to find annotations and map them bidirectionally to fields.  
254 -  
255 - QPDFObjGen::set visited;  
256 - int nfields = fields.getArrayNItems();  
257 - QPDFObjectHandle null(QPDFObjectHandle::newNull());  
258 - for (int i = 0; i < nfields; ++i) {  
259 - traverseField(fields.getArrayItem(i), null, 0, visited);  
260 - }  
261 -  
262 // All Widget annotations should have been encountered by traversing /AcroForm, but in case any 263 // All Widget annotations should have been encountered by traversing /AcroForm, but in case any
263 // weren't, find them by walking through pages, and treat any widget annotation that is not 264 // weren't, find them by walking through pages, and treat any widget annotation that is not
264 // associated with a field as its own field. This just ensures that requesting the field for any 265 // associated with a field as its own field. This just ensures that requesting the field for any
@@ -325,12 +326,10 @@ QPDFAcroFormDocumentHelper::traverseField( @@ -325,12 +326,10 @@ QPDFAcroFormDocumentHelper::traverseField(
325 326
326 bool is_annotation = false; 327 bool is_annotation = false;
327 bool is_field = (0 == depth); 328 bool is_field = (0 == depth);
328 - QPDFObjectHandle kids = field.getKey("/Kids");  
329 - if (kids.isArray()) { 329 + if (auto a = field.getKey("/Kids").as_array(strict)) {
330 is_field = true; 330 is_field = true;
331 - int nkids = kids.getArrayNItems();  
332 - for (int k = 0; k < nkids; ++k) {  
333 - traverseField(kids.getArrayItem(k), field, 1 + depth, visited); 331 + for (auto const& item: a) {
  332 + traverseField(item, field, 1 + depth, visited);
334 } 333 }
335 } else { 334 } else {
336 if (field.hasKey("/Parent")) { 335 if (field.hasKey("/Parent")) {
libqpdf/QPDFFormFieldObjectHelper.cc
@@ -272,14 +272,9 @@ QPDFFormFieldObjectHelper::getChoices() @@ -272,14 +272,9 @@ QPDFFormFieldObjectHelper::getChoices()
272 if (!isChoice()) { 272 if (!isChoice()) {
273 return result; 273 return result;
274 } 274 }
275 - QPDFObjectHandle opt = getInheritableFieldValue("/Opt");  
276 - if (opt.isArray()) {  
277 - int n = opt.getArrayNItems();  
278 - for (int i = 0; i < n; ++i) {  
279 - QPDFObjectHandle item = opt.getArrayItem(i);  
280 - if (item.isString()) {  
281 - result.push_back(item.getUTF8Value());  
282 - } 275 + for (auto const& item: getInheritableFieldValue("/Opt").as_array()) {
  276 + if (item.isString()) {
  277 + result.emplace_back(item.getUTF8Value());
283 } 278 }
284 } 279 }
285 return result; 280 return result;
@@ -369,30 +364,21 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name) @@ -369,30 +364,21 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
369 364
370 QPDFObjectHandle kids = oh().getKey("/Kids"); 365 QPDFObjectHandle kids = oh().getKey("/Kids");
371 if (!(isRadioButton() && parent.isNull() && kids.isArray())) { 366 if (!(isRadioButton() && parent.isNull() && kids.isArray())) {
372 - oh().warnIfPossible(  
373 - "don't know how to set the value"  
374 - " of this field as a radio button"); 367 + oh().warnIfPossible("don't know how to set the value of this field as a radio button");
375 return; 368 return;
376 } 369 }
377 setFieldAttribute("/V", name); 370 setFieldAttribute("/V", name);
378 - int nkids = kids.getArrayNItems();  
379 - for (int i = 0; i < nkids; ++i) {  
380 - QPDFObjectHandle kid = kids.getArrayItem(i); 371 + for (auto const& kid: kids.as_array()) {
381 QPDFObjectHandle AP = kid.getKey("/AP"); 372 QPDFObjectHandle AP = kid.getKey("/AP");
382 QPDFObjectHandle annot; 373 QPDFObjectHandle annot;
383 - if (AP.isNull()) { 374 + if (AP.null()) {
384 // The widget may be below. If there is more than one, just find the first one. 375 // The widget may be below. If there is more than one, just find the first one.
385 - QPDFObjectHandle grandkids = kid.getKey("/Kids");  
386 - if (grandkids.isArray()) {  
387 - int ngrandkids = grandkids.getArrayNItems();  
388 - for (int j = 0; j < ngrandkids; ++j) {  
389 - QPDFObjectHandle grandkid = grandkids.getArrayItem(j);  
390 - AP = grandkid.getKey("/AP");  
391 - if (!AP.isNull()) {  
392 - QTC::TC("qpdf", "QPDFFormFieldObjectHelper radio button grandkid");  
393 - annot = grandkid;  
394 - break;  
395 - } 376 + for (auto const& grandkid: kid.getKey("/Kids").as_array()) {
  377 + AP = grandkid.getKey("/AP");
  378 + if (!AP.null()) {
  379 + QTC::TC("qpdf", "QPDFFormFieldObjectHelper radio button grandkid");
  380 + annot = grandkid;
  381 + break;
396 } 382 }
397 } 383 }
398 } else { 384 } else {
@@ -419,20 +405,16 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value) @@ -419,20 +405,16 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value)
419 { 405 {
420 QPDFObjectHandle AP = oh().getKey("/AP"); 406 QPDFObjectHandle AP = oh().getKey("/AP");
421 QPDFObjectHandle annot; 407 QPDFObjectHandle annot;
422 - if (AP.isNull()) { 408 + if (AP.null()) {
423 // The widget may be below. If there is more than one, just 409 // The widget may be below. If there is more than one, just
424 // find the first one. 410 // find the first one.
425 QPDFObjectHandle kids = oh().getKey("/Kids"); 411 QPDFObjectHandle kids = oh().getKey("/Kids");
426 - if (kids.isArray()) {  
427 - int nkids = kids.getArrayNItems();  
428 - for (int i = 0; i < nkids; ++i) {  
429 - QPDFObjectHandle kid = kids.getArrayItem(i);  
430 - AP = kid.getKey("/AP");  
431 - if (!AP.isNull()) {  
432 - QTC::TC("qpdf", "QPDFFormFieldObjectHelper checkbox kid widget");  
433 - annot = kid;  
434 - break;  
435 - } 412 + for (auto const& kid: oh().getKey("/Kids").as_array(qpdf::strict)) {
  413 + AP = kid.getKey("/AP");
  414 + if (!AP.null()) {
  415 + QTC::TC("qpdf", "QPDFFormFieldObjectHelper checkbox kid widget");
  416 + annot = kid;
  417 + break;
436 } 418 }
437 } 419 }
438 } else { 420 } else {
libqpdf/QPDFObjectHandle.cc
@@ -365,7 +365,7 @@ QPDFObject::copy(bool shallow) @@ -365,7 +365,7 @@ QPDFObject::copy(bool shallow)
365 case ::ot_reference: 365 case ::ot_reference:
366 return qpdf->getObject(og).getObj(); 366 return qpdf->getObject(og).getObj();
367 } 367 }
368 - return {}; // does not return 368 + return {}; // unreachable
369 } 369 }
370 370
371 std::string 371 std::string
@@ -446,7 +446,7 @@ QPDFObject::unparse() @@ -446,7 +446,7 @@ QPDFObject::unparse()
446 case ::ot_reference: 446 case ::ot_reference:
447 return og.unparse(' ') + " R"; 447 return og.unparse(' ') + " R";
448 } 448 }
449 - return {}; // does not return 449 + return {}; // unreachable
450 } 450 }
451 451
452 void 452 void
@@ -644,9 +644,8 @@ QPDFObject::getStringValue() const @@ -644,9 +644,8 @@ QPDFObject::getStringValue() const
644 return std::get<QPDF_Reference>(value).obj->getStringValue(); 644 return std::get<QPDF_Reference>(value).obj->getStringValue();
645 default: 645 default:
646 throw std::logic_error("Internal error in QPDFObject::getStringValue"); 646 throw std::logic_error("Internal error in QPDFObject::getStringValue");
647 - return ""; // does not return  
648 } 647 }
649 - return {}; // does not return 648 + return ""; // unreachable
650 } 649 }
651 650
652 bool 651 bool
@@ -1927,12 +1926,10 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams) @@ -1927,12 +1926,10 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1927 1926
1928 if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) { 1927 if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) {
1929 this->obj = obj->copy(true); 1928 this->obj = obj->copy(true);
1930 - } else if (isArray()) { 1929 + } else if (auto a = as_array(strict)) {
1931 std::vector<QPDFObjectHandle> items; 1930 std::vector<QPDFObjectHandle> items;
1932 - auto array = as_array(strict);  
1933 - int n = array.size();  
1934 - for (int i = 0; i < n; ++i) {  
1935 - items.emplace_back(array.at(i).second); 1931 + for (auto const& item: a) {
  1932 + items.emplace_back(item);
1936 items.back().makeDirect(visited, stop_at_streams); 1933 items.back().makeDirect(visited, stop_at_streams);
1937 } 1934 }
1938 this->obj = QPDFObject::create<QPDF_Array>(items); 1935 this->obj = QPDFObject::create<QPDF_Array>(items);
libqpdf/QPDFWriter.cc
@@ -1129,7 +1129,7 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) @@ -1129,7 +1129,7 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
1129 return; 1129 return;
1130 } else if (!m->linearized) { 1130 } else if (!m->linearized) {
1131 if (object.isArray()) { 1131 if (object.isArray()) {
1132 - for (auto& item: object.getArrayAsVector()) { 1132 + for (auto& item: object.as_array()) {
1133 enqueueObject(item); 1133 enqueueObject(item);
1134 } 1134 }
1135 } else if (auto d = object.as_dictionary()) { 1135 } else if (auto d = object.as_dictionary()) {
@@ -1350,7 +1350,7 @@ QPDFWriter::unparseObject( @@ -1350,7 +1350,7 @@ QPDFWriter::unparseObject(
1350 // [ in the /H key of the linearization parameter dictionary. We'll do this unconditionally 1350 // [ in the /H key of the linearization parameter dictionary. We'll do this unconditionally
1351 // for all arrays because it looks nicer and doesn't make the files that much bigger. 1351 // for all arrays because it looks nicer and doesn't make the files that much bigger.
1352 writeString("["); 1352 writeString("[");
1353 - for (auto const& item: object.getArrayAsVector()) { 1353 + for (auto const& item: object.as_array()) {
1354 writeString(indent); 1354 writeString(indent);
1355 writeStringQDF(" "); 1355 writeStringQDF(" ");
1356 unparseChild(item, level + 1, child_flags); 1356 unparseChild(item, level + 1, child_flags);
@@ -1892,12 +1892,10 @@ QPDFWriter::generateID() @@ -1892,12 +1892,10 @@ QPDFWriter::generateID()
1892 } 1892 }
1893 seed += " QPDF "; 1893 seed += " QPDF ";
1894 if (trailer.hasKey("/Info")) { 1894 if (trailer.hasKey("/Info")) {
1895 - QPDFObjectHandle info = trailer.getKey("/Info");  
1896 - for (auto const& key: info.getKeys()) {  
1897 - QPDFObjectHandle obj = info.getKey(key);  
1898 - if (obj.isString()) { 1895 + for (auto const& item: trailer.getKey("/Info").as_dictionary()) {
  1896 + if (item.second.isString()) {
1899 seed += " "; 1897 seed += " ";
1900 - seed += obj.getStringValue(); 1898 + seed += item.second.getStringValue();
1901 } 1899 }
1902 } 1900 }
1903 } 1901 }
@@ -1923,8 +1921,7 @@ QPDFWriter::generateID() @@ -1923,8 +1921,7 @@ QPDFWriter::generateID()
1923 void 1921 void
1924 QPDFWriter::initializeSpecialStreams() 1922 QPDFWriter::initializeSpecialStreams()
1925 { 1923 {
1926 - // Mark all page content streams in case we are filtering or  
1927 - // normalizing. 1924 + // Mark all page content streams in case we are filtering or normalizing.
1928 std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages(); 1925 std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages();
1929 int num = 0; 1926 int num = 0;
1930 for (auto& page: pages) { 1927 for (auto& page: pages) {
libqpdf/QPDF_optimization.cc
@@ -319,9 +319,8 @@ QPDF::updateObjectMaps( @@ -319,9 +319,8 @@ QPDF::updateObjectMaps(
319 } 319 }
320 320
321 if (cur.oh.isArray()) { 321 if (cur.oh.isArray()) {
322 - int n = cur.oh.getArrayNItems();  
323 - for (int i = 0; i < n; ++i) {  
324 - pending.emplace_back(cur.ou, cur.oh.getArrayItem(i), false); 322 + for (auto const& item: cur.oh.as_array()) {
  323 + pending.emplace_back(cur.ou, item, false);
325 } 324 }
326 } else if (cur.oh.isDictionary() || cur.oh.isStream()) { 325 } else if (cur.oh.isDictionary() || cur.oh.isStream()) {
327 QPDFObjectHandle dict = cur.oh; 326 QPDFObjectHandle dict = cur.oh;
libqpdf/QPDF_pages.cc
1 #include <qpdf/QPDF.hh> 1 #include <qpdf/QPDF.hh>
2 2
3 #include <qpdf/QPDFExc.hh> 3 #include <qpdf/QPDFExc.hh>
  4 +#include <qpdf/QPDFObjectHandle_private.hh>
4 #include <qpdf/QTC.hh> 5 #include <qpdf/QTC.hh>
5 #include <qpdf/QUtil.hh> 6 #include <qpdf/QUtil.hh>
6 7
@@ -108,9 +109,9 @@ QPDF::getAllPagesInternal( @@ -108,9 +109,9 @@ QPDF::getAllPagesInternal(
108 QTC::TC("qpdf", "QPDF inherit mediabox", media_box ? 0 : 1); 109 QTC::TC("qpdf", "QPDF inherit mediabox", media_box ? 0 : 1);
109 } 110 }
110 auto kids = cur_node.getKey("/Kids"); 111 auto kids = cur_node.getKey("/Kids");
111 - int n = kids.getArrayNItems();  
112 - for (int i = 0; i < n; ++i) {  
113 - auto kid = kids.getArrayItem(i); 112 + int i = -1;
  113 + for (auto& kid: kids.as_array()) {
  114 + ++i;
114 if (!kid.isDictionary()) { 115 if (!kid.isDictionary()) {
115 kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring"); 116 kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring");
116 m->invalid_page_found = true; 117 m->invalid_page_found = true;
@@ -133,7 +134,6 @@ QPDF::getAllPagesInternal( @@ -133,7 +134,6 @@ QPDF::getAllPagesInternal(
133 cur_node.warnIfPossible( 134 cur_node.warnIfPossible(
134 "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect"); 135 "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect");
135 kid = makeIndirectObject(kid); 136 kid = makeIndirectObject(kid);
136 - kids.setArrayItem(i, kid);  
137 } else if (!seen.add(kid)) { 137 } else if (!seen.add(kid)) {
138 // Make a copy of the page. This does the same as shallowCopyPage in 138 // Make a copy of the page. This does the same as shallowCopyPage in
139 // QPDFPageObjectHelper. 139 // QPDFPageObjectHelper.
@@ -144,7 +144,6 @@ QPDF::getAllPagesInternal( @@ -144,7 +144,6 @@ QPDF::getAllPagesInternal(
144 " creating a new page object as a copy"); 144 " creating a new page object as a copy");
145 kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy()); 145 kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy());
146 seen.add(kid); 146 seen.add(kid);
147 - kids.setArrayItem(i, kid);  
148 } 147 }
149 if (!kid.isDictionaryOfType("/Page")) { 148 if (!kid.isDictionaryOfType("/Page")) {
150 kid.warnIfPossible("/Type key should be /Page but is not; overriding"); 149 kid.warnIfPossible("/Type key should be /Page but is not; overriding");