Commit 38afdcea7b08226aa6cc12a8fcda93a6f35a0a18
1 parent
07afb668
Add QPDFObjectHandle::unsafeShallowCopy
Showing
3 changed files
with
50 additions
and
11 deletions
ChangeLog
| 1 | 2020-04-02 Jay Berkenbilt <ejb@ql.org> | 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 | * Remove Members class indirection for QPDFObjectHandle. Those are | 7 | * Remove Members class indirection for QPDFObjectHandle. Those are |
| 4 | copied and assigned too often, and that change caused a very | 8 | copied and assigned too often, and that change caused a very |
| 5 | substantial performance hit. | 9 | substantial performance hit. |
include/qpdf/QPDFObjectHandle.hh
| @@ -670,10 +670,24 @@ class QPDFObjectHandle | @@ -670,10 +670,24 @@ class QPDFObjectHandle | ||
| 670 | // traverse across indirect object boundaries. That means that, | 670 | // traverse across indirect object boundaries. That means that, |
| 671 | // for dictionaries and arrays, any keys or items that were | 671 | // for dictionaries and arrays, any keys or items that were |
| 672 | // indirect objects will still be indirect objects that point to | 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 | QPDF_DLL | 677 | QPDF_DLL |
| 675 | QPDFObjectHandle shallowCopy(); | 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 | // Mutator methods. Use with caution. | 691 | // Mutator methods. Use with caution. |
| 678 | 692 | ||
| 679 | // Recursively copy this object, making it direct. Throws an | 693 | // Recursively copy this object, making it direct. Throws an |
| @@ -1053,7 +1067,9 @@ class QPDFObjectHandle | @@ -1053,7 +1067,9 @@ class QPDFObjectHandle | ||
| 1053 | void objectWarning(std::string const& warning); | 1067 | void objectWarning(std::string const& warning); |
| 1054 | void assertType(char const* type_name, bool istype); | 1068 | void assertType(char const* type_name, bool istype); |
| 1055 | void dereference(); | 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 | void releaseResolved(); | 1073 | void releaseResolved(); |
| 1058 | static void setObjectDescriptionFromInput( | 1074 | static void setObjectDescriptionFromInput( |
| 1059 | QPDFObjectHandle, QPDF*, std::string const&, | 1075 | QPDFObjectHandle, QPDF*, std::string const&, |
libqpdf/QPDFObjectHandle.cc
| @@ -2461,6 +2461,23 @@ QPDFObjectHandle::hasObjectDescription() | @@ -2461,6 +2461,23 @@ QPDFObjectHandle::hasObjectDescription() | ||
| 2461 | QPDFObjectHandle | 2461 | QPDFObjectHandle |
| 2462 | QPDFObjectHandle::shallowCopy() | 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 | assertInitialized(); | 2481 | assertInitialized(); |
| 2465 | 2482 | ||
| 2466 | if (isStream()) | 2483 | if (isStream()) |
| @@ -2470,7 +2487,6 @@ QPDFObjectHandle::shallowCopy() | @@ -2470,7 +2487,6 @@ QPDFObjectHandle::shallowCopy() | ||
| 2470 | "attempt to make a shallow copy of a stream"); | 2487 | "attempt to make a shallow copy of a stream"); |
| 2471 | } | 2488 | } |
| 2472 | 2489 | ||
| 2473 | - QPDFObjectHandle new_obj; | ||
| 2474 | if (isArray()) | 2490 | if (isArray()) |
| 2475 | { | 2491 | { |
| 2476 | QTC::TC("qpdf", "QPDFObjectHandle shallow copy array"); | 2492 | QTC::TC("qpdf", "QPDFObjectHandle shallow copy array"); |
| @@ -2491,13 +2507,12 @@ QPDFObjectHandle::shallowCopy() | @@ -2491,13 +2507,12 @@ QPDFObjectHandle::shallowCopy() | ||
| 2491 | } | 2507 | } |
| 2492 | 2508 | ||
| 2493 | std::set<QPDFObjGen> visited; | 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 | void | 2513 | void |
| 2499 | QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, | 2514 | QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, |
| 2500 | - bool cross_indirect) | 2515 | + bool cross_indirect, bool first_level_only) |
| 2501 | { | 2516 | { |
| 2502 | assertInitialized(); | 2517 | assertInitialized(); |
| 2503 | 2518 | ||
| @@ -2573,9 +2588,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, | @@ -2573,9 +2588,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, | ||
| 2573 | for (int i = 0; i < n; ++i) | 2588 | for (int i = 0; i < n; ++i) |
| 2574 | { | 2589 | { |
| 2575 | items.push_back(getArrayItem(i)); | 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 | new_obj = new QPDF_Array(items); | 2598 | new_obj = new QPDF_Array(items); |
| @@ -2589,9 +2606,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, | @@ -2589,9 +2606,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, | ||
| 2589 | iter != keys.end(); ++iter) | 2606 | iter != keys.end(); ++iter) |
| 2590 | { | 2607 | { |
| 2591 | items[*iter] = getKey(*iter); | 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 | new_obj = new QPDF_Dictionary(items); | 2616 | new_obj = new QPDF_Dictionary(items); |
| @@ -2614,7 +2633,7 @@ void | @@ -2614,7 +2633,7 @@ void | ||
| 2614 | QPDFObjectHandle::makeDirect() | 2633 | QPDFObjectHandle::makeDirect() |
| 2615 | { | 2634 | { |
| 2616 | std::set<QPDFObjGen> visited; | 2635 | std::set<QPDFObjGen> visited; |
| 2617 | - copyObject(visited, true); | 2636 | + copyObject(visited, true, false); |
| 2618 | } | 2637 | } |
| 2619 | 2638 | ||
| 2620 | void | 2639 | void |