Commit d4a563647ff62e5a01a32ea758de9cadf5a6ca0d

Authored by m-holger
1 parent 32e0bbe4

Refactor `NNTree::deepen`: replace `getKey` with subscript operator for `Array` …

…access, and streamline logic.
libqpdf/NNTree.cc
@@ -382,7 +382,7 @@ NNTreeIterator::remove() @@ -382,7 +382,7 @@ NNTreeIterator::remove()
382 if (!valid()) { 382 if (!valid()) {
383 throw std::logic_error("attempt made to remove an invalid iterator"); 383 throw std::logic_error("attempt made to remove an invalid iterator");
384 } 384 }
385 - Array items = node.getKey(impl.itemsKey()); 385 + Array items = node[impl.itemsKey()];
386 int nitems = static_cast<int>(items.size()); 386 int nitems = static_cast<int>(items.size());
387 if (std::cmp_greater(item_number + 2, nitems)) { 387 if (std::cmp_greater(item_number + 2, nitems)) {
388 impl.error(node, "found short items array while removing an item"); 388 impl.error(node, "found short items array while removing an item");
@@ -429,7 +429,7 @@ NNTreeIterator::remove() @@ -429,7 +429,7 @@ NNTreeIterator::remove()
429 auto element = lastPathElement(); 429 auto element = lastPathElement();
430 auto parent = element; 430 auto parent = element;
431 --parent; 431 --parent;
432 - Array kids = element->node.getKey("/Kids"); 432 + Array kids = element->node["/Kids"];
433 kids.erase(element->kid_number); 433 kids.erase(element->kid_number);
434 auto nkids = kids.size(); 434 auto nkids = kids.size();
435 if (nkids > 0) { 435 if (nkids > 0) {
@@ -489,14 +489,14 @@ NNTreeIterator::operator==(NNTreeIterator const&amp; other) const @@ -489,14 +489,14 @@ NNTreeIterator::operator==(NNTreeIterator const&amp; other) const
489 } 489 }
490 490
491 bool 491 bool
492 -NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) 492 +NNTreeIterator::deepen(Dictionary a_node, bool first, bool allow_empty)
493 { 493 {
494 // Starting at this node, descend through the first or last kid until we reach a node with 494 // Starting at this node, descend through the first or last kid until we reach a node with
495 // items. If we succeed, return true; otherwise return false and leave path alone. 495 // items. If we succeed, return true; otherwise return false and leave path alone.
496 496
497 auto opath = path; 497 auto opath = path;
498 498
499 - auto fail = [this, &opath](QPDFObjectHandle const& failed_node, std::string const& msg) { 499 + auto fail = [this, &opath](Dictionary const& failed_node, std::string const& msg) {
500 impl.warn(failed_node, msg); 500 impl.warn(failed_node, msg);
501 path = opath; 501 path = opath;
502 return false; 502 return false;
@@ -511,51 +511,52 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) @@ -511,51 +511,52 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty)
511 return fail(a_node, "loop detected while traversing name/number tree"); 511 return fail(a_node, "loop detected while traversing name/number tree");
512 } 512 }
513 513
514 - if (!a_node.isDictionary()) { 514 + if (!a_node) {
515 return fail(a_node, "non-dictionary node while traversing name/number tree"); 515 return fail(a_node, "non-dictionary node while traversing name/number tree");
516 } 516 }
517 517
518 - Array items = a_node.getKey(impl.itemsKey()); 518 + Array items = a_node[impl.itemsKey()];
519 int nitems = static_cast<int>(items.size()); 519 int nitems = static_cast<int>(items.size());
520 if (nitems > 1) { 520 if (nitems > 1) {
521 setItemNumber(a_node, first ? 0 : nitems - 2); 521 setItemNumber(a_node, first ? 0 : nitems - 2);
522 - break; 522 + return true;
523 } 523 }
524 524
525 - Array kids = a_node.getKey("/Kids"); 525 + Array kids = a_node["/Kids"];
526 int nkids = static_cast<int>(kids.size()); 526 int nkids = static_cast<int>(kids.size());
527 - if (nkids > 0) {  
528 - int kid_number = first ? 0 : nkids - 1;  
529 - addPathElement(a_node, kid_number);  
530 - auto next = kids[kid_number];  
531 - if (!next) {  
532 - return fail(a_node, "kid number " + std::to_string(kid_number) + " is invalid"); 527 + if (nkids == 0) {
  528 + if (allow_empty && items) {
  529 + setItemNumber(a_node, -1);
  530 + return true;
533 } 531 }
534 - if (!next.indirect()) {  
535 - if (impl.auto_repair) {  
536 - impl.warn(  
537 - a_node,  
538 - "converting kid number " + std::to_string(kid_number) +  
539 - " to an indirect object");  
540 - next = impl.qpdf.makeIndirectObject(next);  
541 - kids.set(kid_number, next);  
542 - } else {  
543 - impl.warn(  
544 - a_node,  
545 - "kid number " + std::to_string(kid_number) + " is not an indirect object");  
546 - }  
547 - }  
548 - a_node = next;  
549 - } else if (allow_empty && items) {  
550 - setItemNumber(a_node, -1);  
551 - break;  
552 - } else {  
553 return fail( 532 return fail(
554 a_node, 533 a_node,
555 "name/number tree node has neither non-empty " + impl.itemsKey() + " nor /Kids"); 534 "name/number tree node has neither non-empty " + impl.itemsKey() + " nor /Kids");
556 } 535 }
  536 +
  537 + int kid_number = first ? 0 : nkids - 1;
  538 + addPathElement(a_node, kid_number);
  539 + Dictionary next = kids[kid_number];
  540 + if (!next) {
  541 + return fail(a_node, "kid number " + std::to_string(kid_number) + " is invalid");
  542 + }
  543 + if (!next.indirect()) {
  544 + if (impl.auto_repair) {
  545 + impl.warn(
  546 + a_node,
  547 + "converting kid number " + std::to_string(kid_number) +
  548 + " to an indirect object");
  549 + next = impl.qpdf.makeIndirectObject(next);
  550 + kids.set(kid_number, next);
  551 + } else {
  552 + impl.warn(
  553 + a_node,
  554 + "kid number " + std::to_string(kid_number) + " is not an indirect object");
  555 + }
  556 + }
  557 +
  558 + a_node = next;
557 } 559 }
558 - return true;  
559 } 560 }
560 561
561 NNTreeImpl::iterator 562 NNTreeImpl::iterator
libqpdf/qpdf/NNTree.hh
@@ -92,7 +92,7 @@ class NNTreeIterator final @@ -92,7 +92,7 @@ class NNTreeIterator final
92 { 92 {
93 } 93 }
94 void updateIValue(bool allow_invalid = true); 94 void updateIValue(bool allow_invalid = true);
95 - bool deepen(QPDFObjectHandle node, bool first, bool allow_empty); 95 + bool deepen(qpdf::Dictionary node, bool first, bool allow_empty);
96 void 96 void
97 setItemNumber(QPDFObjectHandle const& a_node, int n) 97 setItemNumber(QPDFObjectHandle const& a_node, int n)
98 { 98 {
qpdf/qtest/qpdf/name-tree.out
@@ -33,7 +33,7 @@ WARNING: name-tree.pdf (Name/Number tree node (object 17)): skipping over invali @@ -33,7 +33,7 @@ WARNING: name-tree.pdf (Name/Number tree node (object 17)): skipping over invali
33 B 33 B
34 W 34 W
35 /Bad3 -- invalid kid 35 /Bad3 -- invalid kid
36 -WARNING: name-tree.pdf (Name/Number tree node (object 25)): non-dictionary node while traversing name/number tree 36 +WARNING: name-tree.pdf (Name/Number tree node (object 22)): kid number 0 is invalid
37 /Bad4 -- invalid kid 37 /Bad4 -- invalid kid
38 WARNING: name-tree.pdf (Name/Number tree node (object 23)): attempting to repair after error: name-tree.pdf (Name/Number tree node (object 23)): invalid kid at index 1 38 WARNING: name-tree.pdf (Name/Number tree node (object 23)): attempting to repair after error: name-tree.pdf (Name/Number tree node (object 23)): invalid kid at index 1
39 WARNING: name-tree.pdf (Name/Number tree node (object 23)): skipping over invalid kid at index 1 39 WARNING: name-tree.pdf (Name/Number tree node (object 23)): skipping over invalid kid at index 1