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 2346  
2347 2347 if (foreign_tc == ::ot_array) {
2348 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 2352 } else if (foreign_tc == ::ot_dictionary) {
2354 2353 QTC::TC("qpdf", "QPDF reserve dictionary");
... ... @@ -2384,11 +2383,8 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier&amp; obj_cop
2384 2383 } else if (foreign_tc == ::ot_array) {
2385 2384 QTC::TC("qpdf", "QPDF replace array");
2386 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 2389 } else if (foreign_tc == ::ot_dictionary) {
2394 2390 QTC::TC("qpdf", "QPDF replace dictionary");
... ... @@ -2714,11 +2710,8 @@ QPDF::getCompressibleObjGens()
2714 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 7 #include <qpdf/QUtil.hh>
8 8 #include <qpdf/ResourceFinder.hh>
9 9  
  10 +using namespace qpdf;
  11 +
10 12 QPDFAcroFormDocumentHelper::Members::Members() :
11 13 cache_valid(false)
12 14 {
... ... @@ -239,26 +241,25 @@ QPDFAcroFormDocumentHelper::analyze()
239 241 return;
240 242 }
241 243 m->cache_valid = true;
242   - QPDFObjectHandle acroform = this->qpdf.getRoot().getKey("/AcroForm");
  244 + QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm");
243 245 if (!(acroform.isDictionary() && acroform.hasKey("/Fields"))) {
244 246 return;
245 247 }
246 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 258 QTC::TC("qpdf", "QPDFAcroFormDocumentHelper fields not array");
249 259 acroform.warnIfPossible("/Fields key of /AcroForm dictionary is not an array; ignoring");
250 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 263 // All Widget annotations should have been encountered by traversing /AcroForm, but in case any
263 264 // weren't, find them by walking through pages, and treat any widget annotation that is not
264 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 326  
326 327 bool is_annotation = false;
327 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 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 334 } else {
336 335 if (field.hasKey("/Parent")) {
... ...
libqpdf/QPDFFormFieldObjectHelper.cc
... ... @@ -272,14 +272,9 @@ QPDFFormFieldObjectHelper::getChoices()
272 272 if (!isChoice()) {
273 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 280 return result;
... ... @@ -369,30 +364,21 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
369 364  
370 365 QPDFObjectHandle kids = oh().getKey("/Kids");
371 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 368 return;
376 369 }
377 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 372 QPDFObjectHandle AP = kid.getKey("/AP");
382 373 QPDFObjectHandle annot;
383   - if (AP.isNull()) {
  374 + if (AP.null()) {
384 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 384 } else {
... ... @@ -419,20 +405,16 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value)
419 405 {
420 406 QPDFObjectHandle AP = oh().getKey("/AP");
421 407 QPDFObjectHandle annot;
422   - if (AP.isNull()) {
  408 + if (AP.null()) {
423 409 // The widget may be below. If there is more than one, just
424 410 // find the first one.
425 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 420 } else {
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -365,7 +365,7 @@ QPDFObject::copy(bool shallow)
365 365 case ::ot_reference:
366 366 return qpdf->getObject(og).getObj();
367 367 }
368   - return {}; // does not return
  368 + return {}; // unreachable
369 369 }
370 370  
371 371 std::string
... ... @@ -446,7 +446,7 @@ QPDFObject::unparse()
446 446 case ::ot_reference:
447 447 return og.unparse(' ') + " R";
448 448 }
449   - return {}; // does not return
  449 + return {}; // unreachable
450 450 }
451 451  
452 452 void
... ... @@ -644,9 +644,8 @@ QPDFObject::getStringValue() const
644 644 return std::get<QPDF_Reference>(value).obj->getStringValue();
645 645 default:
646 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 651 bool
... ... @@ -1927,12 +1926,10 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1927 1926  
1928 1927 if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) {
1929 1928 this->obj = obj->copy(true);
1930   - } else if (isArray()) {
  1929 + } else if (auto a = as_array(strict)) {
1931 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 1933 items.back().makeDirect(visited, stop_at_streams);
1937 1934 }
1938 1935 this->obj = QPDFObject::create<QPDF_Array>(items);
... ...
libqpdf/QPDFWriter.cc
... ... @@ -1129,7 +1129,7 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
1129 1129 return;
1130 1130 } else if (!m->linearized) {
1131 1131 if (object.isArray()) {
1132   - for (auto& item: object.getArrayAsVector()) {
  1132 + for (auto& item: object.as_array()) {
1133 1133 enqueueObject(item);
1134 1134 }
1135 1135 } else if (auto d = object.as_dictionary()) {
... ... @@ -1350,7 +1350,7 @@ QPDFWriter::unparseObject(
1350 1350 // [ in the /H key of the linearization parameter dictionary. We'll do this unconditionally
1351 1351 // for all arrays because it looks nicer and doesn't make the files that much bigger.
1352 1352 writeString("[");
1353   - for (auto const& item: object.getArrayAsVector()) {
  1353 + for (auto const& item: object.as_array()) {
1354 1354 writeString(indent);
1355 1355 writeStringQDF(" ");
1356 1356 unparseChild(item, level + 1, child_flags);
... ... @@ -1892,12 +1892,10 @@ QPDFWriter::generateID()
1892 1892 }
1893 1893 seed += " QPDF ";
1894 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 1897 seed += " ";
1900   - seed += obj.getStringValue();
  1898 + seed += item.second.getStringValue();
1901 1899 }
1902 1900 }
1903 1901 }
... ... @@ -1923,8 +1921,7 @@ QPDFWriter::generateID()
1923 1921 void
1924 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 1925 std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages();
1929 1926 int num = 0;
1930 1927 for (auto& page: pages) {
... ...
libqpdf/QPDF_optimization.cc
... ... @@ -319,9 +319,8 @@ QPDF::updateObjectMaps(
319 319 }
320 320  
321 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 325 } else if (cur.oh.isDictionary() || cur.oh.isStream()) {
327 326 QPDFObjectHandle dict = cur.oh;
... ...
libqpdf/QPDF_pages.cc
1 1 #include <qpdf/QPDF.hh>
2 2  
3 3 #include <qpdf/QPDFExc.hh>
  4 +#include <qpdf/QPDFObjectHandle_private.hh>
4 5 #include <qpdf/QTC.hh>
5 6 #include <qpdf/QUtil.hh>
6 7  
... ... @@ -108,9 +109,9 @@ QPDF::getAllPagesInternal(
108 109 QTC::TC("qpdf", "QPDF inherit mediabox", media_box ? 0 : 1);
109 110 }
110 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 115 if (!kid.isDictionary()) {
115 116 kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring");
116 117 m->invalid_page_found = true;
... ... @@ -133,7 +134,6 @@ QPDF::getAllPagesInternal(
133 134 cur_node.warnIfPossible(
134 135 "kid " + std::to_string(i) + " (from 0) is direct; converting to indirect");
135 136 kid = makeIndirectObject(kid);
136   - kids.setArrayItem(i, kid);
137 137 } else if (!seen.add(kid)) {
138 138 // Make a copy of the page. This does the same as shallowCopyPage in
139 139 // QPDFPageObjectHelper.
... ... @@ -144,7 +144,6 @@ QPDF::getAllPagesInternal(
144 144 " creating a new page object as a copy");
145 145 kid = makeIndirectObject(QPDFObjectHandle(kid).shallowCopy());
146 146 seen.add(kid);
147   - kids.setArrayItem(i, kid);
148 147 }
149 148 if (!kid.isDictionaryOfType("/Page")) {
150 149 kid.warnIfPossible("/Type key should be /Page but is not; overriding");
... ...