Commit 38afdcea7b08226aa6cc12a8fcda93a6f35a0a18
1 parent
07afb668
Add QPDFObjectHandle::unsafeShallowCopy
Showing
3 changed files
with
50 additions
and
11 deletions
ChangeLog
| 1 | 1 | 2020-04-02 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | |
| 3 | + * Add method QPDFObjectHandle::unsafeShallowCopy for copying only | |
| 4 | + top-level dictionary keys or array items. See comments in | |
| 5 | + QPDFObjectHandle.hh for when this should be used. | |
| 6 | + | |
| 3 | 7 | * Remove Members class indirection for QPDFObjectHandle. Those are |
| 4 | 8 | copied and assigned too often, and that change caused a very |
| 5 | 9 | substantial performance hit. | ... | ... |
include/qpdf/QPDFObjectHandle.hh
| ... | ... | @@ -670,10 +670,24 @@ class QPDFObjectHandle |
| 670 | 670 | // traverse across indirect object boundaries. That means that, |
| 671 | 671 | // for dictionaries and arrays, any keys or items that were |
| 672 | 672 | // indirect objects will still be indirect objects that point to |
| 673 | - // the same place. | |
| 673 | + // the same place. In the strictest sense, this is not a shallow | |
| 674 | + // copy because it recursively descends arrays and dictionaries; | |
| 675 | + // it just doesn't cross over indirect objects. See also | |
| 676 | + // unsafeShallowCopy(). | |
| 674 | 677 | QPDF_DLL |
| 675 | 678 | QPDFObjectHandle shallowCopy(); |
| 676 | 679 | |
| 680 | + // Create a true shallow copy of an array or dictionary, just | |
| 681 | + // copying the immediate items (array) or keys (dictionary). This | |
| 682 | + // is "unsafe" because, if you *modify* any of the items in the | |
| 683 | + // copy, you are modifying the original, which is almost never | |
| 684 | + // what you want. However, if your intention is merely to | |
| 685 | + // *replace* top-level items or keys and not to modify lower-level | |
| 686 | + // items in the copy, this method is much faster than | |
| 687 | + // shallowCopy(). | |
| 688 | + QPDF_DLL | |
| 689 | + QPDFObjectHandle unsafeShallowCopy(); | |
| 690 | + | |
| 677 | 691 | // Mutator methods. Use with caution. |
| 678 | 692 | |
| 679 | 693 | // Recursively copy this object, making it direct. Throws an |
| ... | ... | @@ -1053,7 +1067,9 @@ class QPDFObjectHandle |
| 1053 | 1067 | void objectWarning(std::string const& warning); |
| 1054 | 1068 | void assertType(char const* type_name, bool istype); |
| 1055 | 1069 | void dereference(); |
| 1056 | - void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect); | |
| 1070 | + void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect, | |
| 1071 | + bool first_level_only); | |
| 1072 | + void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only); | |
| 1057 | 1073 | void releaseResolved(); |
| 1058 | 1074 | static void setObjectDescriptionFromInput( |
| 1059 | 1075 | QPDFObjectHandle, QPDF*, std::string const&, | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -2461,6 +2461,23 @@ QPDFObjectHandle::hasObjectDescription() |
| 2461 | 2461 | QPDFObjectHandle |
| 2462 | 2462 | QPDFObjectHandle::shallowCopy() |
| 2463 | 2463 | { |
| 2464 | + QPDFObjectHandle result; | |
| 2465 | + shallowCopyInternal(result, false); | |
| 2466 | + return result; | |
| 2467 | +} | |
| 2468 | + | |
| 2469 | +QPDFObjectHandle | |
| 2470 | +QPDFObjectHandle::unsafeShallowCopy() | |
| 2471 | +{ | |
| 2472 | + QPDFObjectHandle result; | |
| 2473 | + shallowCopyInternal(result, true); | |
| 2474 | + return result; | |
| 2475 | +} | |
| 2476 | + | |
| 2477 | +void | |
| 2478 | +QPDFObjectHandle::shallowCopyInternal(QPDFObjectHandle& new_obj, | |
| 2479 | + bool first_level_only) | |
| 2480 | +{ | |
| 2464 | 2481 | assertInitialized(); |
| 2465 | 2482 | |
| 2466 | 2483 | if (isStream()) |
| ... | ... | @@ -2470,7 +2487,6 @@ QPDFObjectHandle::shallowCopy() |
| 2470 | 2487 | "attempt to make a shallow copy of a stream"); |
| 2471 | 2488 | } |
| 2472 | 2489 | |
| 2473 | - QPDFObjectHandle new_obj; | |
| 2474 | 2490 | if (isArray()) |
| 2475 | 2491 | { |
| 2476 | 2492 | QTC::TC("qpdf", "QPDFObjectHandle shallow copy array"); |
| ... | ... | @@ -2491,13 +2507,12 @@ QPDFObjectHandle::shallowCopy() |
| 2491 | 2507 | } |
| 2492 | 2508 | |
| 2493 | 2509 | std::set<QPDFObjGen> visited; |
| 2494 | - new_obj.copyObject(visited, false); | |
| 2495 | - return new_obj; | |
| 2510 | + new_obj.copyObject(visited, false, first_level_only); | |
| 2496 | 2511 | } |
| 2497 | 2512 | |
| 2498 | 2513 | void |
| 2499 | 2514 | QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, |
| 2500 | - bool cross_indirect) | |
| 2515 | + bool cross_indirect, bool first_level_only) | |
| 2501 | 2516 | { |
| 2502 | 2517 | assertInitialized(); |
| 2503 | 2518 | |
| ... | ... | @@ -2573,9 +2588,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, |
| 2573 | 2588 | for (int i = 0; i < n; ++i) |
| 2574 | 2589 | { |
| 2575 | 2590 | items.push_back(getArrayItem(i)); |
| 2576 | - if (cross_indirect || (! items.back().isIndirect())) | |
| 2591 | + if ((! first_level_only) && | |
| 2592 | + (cross_indirect || (! items.back().isIndirect()))) | |
| 2577 | 2593 | { |
| 2578 | - items.back().copyObject(visited, cross_indirect); | |
| 2594 | + items.back().copyObject( | |
| 2595 | + visited, cross_indirect, first_level_only); | |
| 2579 | 2596 | } |
| 2580 | 2597 | } |
| 2581 | 2598 | new_obj = new QPDF_Array(items); |
| ... | ... | @@ -2589,9 +2606,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, |
| 2589 | 2606 | iter != keys.end(); ++iter) |
| 2590 | 2607 | { |
| 2591 | 2608 | items[*iter] = getKey(*iter); |
| 2592 | - if (cross_indirect || (! items[*iter].isIndirect())) | |
| 2609 | + if ((! first_level_only) && | |
| 2610 | + (cross_indirect || (! items[*iter].isIndirect()))) | |
| 2593 | 2611 | { |
| 2594 | - items[*iter].copyObject(visited, cross_indirect); | |
| 2612 | + items[*iter].copyObject( | |
| 2613 | + visited, cross_indirect, first_level_only); | |
| 2595 | 2614 | } |
| 2596 | 2615 | } |
| 2597 | 2616 | new_obj = new QPDF_Dictionary(items); |
| ... | ... | @@ -2614,7 +2633,7 @@ void |
| 2614 | 2633 | QPDFObjectHandle::makeDirect() |
| 2615 | 2634 | { |
| 2616 | 2635 | std::set<QPDFObjGen> visited; |
| 2617 | - copyObject(visited, true); | |
| 2636 | + copyObject(visited, true, false); | |
| 2618 | 2637 | } |
| 2619 | 2638 | |
| 2620 | 2639 | void | ... | ... |