2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-04 19:30:53 +00:00

Add QPDFObjectHandle::unsafeShallowCopy

This commit is contained in:
Jay Berkenbilt 2020-04-02 17:52:21 -04:00
parent 07afb668b1
commit 38afdcea7b
3 changed files with 50 additions and 11 deletions

View File

@ -1,5 +1,9 @@
2020-04-02 Jay Berkenbilt <ejb@ql.org> 2020-04-02 Jay Berkenbilt <ejb@ql.org>
* Add method QPDFObjectHandle::unsafeShallowCopy for copying only
top-level dictionary keys or array items. See comments in
QPDFObjectHandle.hh for when this should be used.
* Remove Members class indirection for QPDFObjectHandle. Those are * Remove Members class indirection for QPDFObjectHandle. Those are
copied and assigned too often, and that change caused a very copied and assigned too often, and that change caused a very
substantial performance hit. substantial performance hit.

View File

@ -670,10 +670,24 @@ class QPDFObjectHandle
// traverse across indirect object boundaries. That means that, // traverse across indirect object boundaries. That means that,
// for dictionaries and arrays, any keys or items that were // for dictionaries and arrays, any keys or items that were
// indirect objects will still be indirect objects that point to // indirect objects will still be indirect objects that point to
// the same place. // the same place. In the strictest sense, this is not a shallow
// copy because it recursively descends arrays and dictionaries;
// it just doesn't cross over indirect objects. See also
// unsafeShallowCopy().
QPDF_DLL QPDF_DLL
QPDFObjectHandle shallowCopy(); QPDFObjectHandle shallowCopy();
// Create a true shallow copy of an array or dictionary, just
// copying the immediate items (array) or keys (dictionary). This
// is "unsafe" because, if you *modify* any of the items in the
// copy, you are modifying the original, which is almost never
// what you want. However, if your intention is merely to
// *replace* top-level items or keys and not to modify lower-level
// items in the copy, this method is much faster than
// shallowCopy().
QPDF_DLL
QPDFObjectHandle unsafeShallowCopy();
// Mutator methods. Use with caution. // Mutator methods. Use with caution.
// Recursively copy this object, making it direct. Throws an // Recursively copy this object, making it direct. Throws an
@ -1053,7 +1067,9 @@ class QPDFObjectHandle
void objectWarning(std::string const& warning); void objectWarning(std::string const& warning);
void assertType(char const* type_name, bool istype); void assertType(char const* type_name, bool istype);
void dereference(); void dereference();
void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect); void copyObject(std::set<QPDFObjGen>& visited, bool cross_indirect,
bool first_level_only);
void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only);
void releaseResolved(); void releaseResolved();
static void setObjectDescriptionFromInput( static void setObjectDescriptionFromInput(
QPDFObjectHandle, QPDF*, std::string const&, QPDFObjectHandle, QPDF*, std::string const&,

View File

@ -2460,6 +2460,23 @@ QPDFObjectHandle::hasObjectDescription()
QPDFObjectHandle QPDFObjectHandle
QPDFObjectHandle::shallowCopy() QPDFObjectHandle::shallowCopy()
{
QPDFObjectHandle result;
shallowCopyInternal(result, false);
return result;
}
QPDFObjectHandle
QPDFObjectHandle::unsafeShallowCopy()
{
QPDFObjectHandle result;
shallowCopyInternal(result, true);
return result;
}
void
QPDFObjectHandle::shallowCopyInternal(QPDFObjectHandle& new_obj,
bool first_level_only)
{ {
assertInitialized(); assertInitialized();
@ -2470,7 +2487,6 @@ QPDFObjectHandle::shallowCopy()
"attempt to make a shallow copy of a stream"); "attempt to make a shallow copy of a stream");
} }
QPDFObjectHandle new_obj;
if (isArray()) if (isArray())
{ {
QTC::TC("qpdf", "QPDFObjectHandle shallow copy array"); QTC::TC("qpdf", "QPDFObjectHandle shallow copy array");
@ -2491,13 +2507,12 @@ QPDFObjectHandle::shallowCopy()
} }
std::set<QPDFObjGen> visited; std::set<QPDFObjGen> visited;
new_obj.copyObject(visited, false); new_obj.copyObject(visited, false, first_level_only);
return new_obj;
} }
void void
QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited, QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited,
bool cross_indirect) bool cross_indirect, bool first_level_only)
{ {
assertInitialized(); assertInitialized();
@ -2573,9 +2588,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited,
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
items.push_back(getArrayItem(i)); items.push_back(getArrayItem(i));
if (cross_indirect || (! items.back().isIndirect())) if ((! first_level_only) &&
(cross_indirect || (! items.back().isIndirect())))
{ {
items.back().copyObject(visited, cross_indirect); items.back().copyObject(
visited, cross_indirect, first_level_only);
} }
} }
new_obj = new QPDF_Array(items); new_obj = new QPDF_Array(items);
@ -2589,9 +2606,11 @@ QPDFObjectHandle::copyObject(std::set<QPDFObjGen>& visited,
iter != keys.end(); ++iter) iter != keys.end(); ++iter)
{ {
items[*iter] = getKey(*iter); items[*iter] = getKey(*iter);
if (cross_indirect || (! items[*iter].isIndirect())) if ((! first_level_only) &&
(cross_indirect || (! items[*iter].isIndirect())))
{ {
items[*iter].copyObject(visited, cross_indirect); items[*iter].copyObject(
visited, cross_indirect, first_level_only);
} }
} }
new_obj = new QPDF_Dictionary(items); new_obj = new QPDF_Dictionary(items);
@ -2614,7 +2633,7 @@ void
QPDFObjectHandle::makeDirect() QPDFObjectHandle::makeDirect()
{ {
std::set<QPDFObjGen> visited; std::set<QPDFObjGen> visited;
copyObject(visited, true); copyObject(visited, true, false);
} }
void void