aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorm-holger <m-holger@kubitscheck.org>2022-11-20 13:30:05 +0100
committerJay Berkenbilt <jberkenbilt@users.noreply.github.com>2022-11-20 18:07:22 +0100
commit63d1dcb414ad92cae857da636f242b34acac394b (patch)
treef14b0974e1cb5f8be4014888a82243b164aca8ce
parentdbc5f07b90954c18445ebe725b1a445745726864 (diff)
downloadqpdf-63d1dcb414ad92cae857da636f242b34acac394b.tar.zst
Split QPDFObjectHandle::shallowCopyInternal and copyObject
Have separate versions for unsafeShallowCopy, shallowCopy and makeDirect.
-rw-r--r--include/qpdf/QPDFObjectHandle.hh13
-rw-r--r--libqpdf/QPDFObjectHandle.cc173
2 files changed, 180 insertions, 6 deletions
diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh
index 3610422e..b186d4f8 100644
--- a/include/qpdf/QPDFObjectHandle.hh
+++ b/include/qpdf/QPDFObjectHandle.hh
@@ -1628,12 +1628,23 @@ class QPDFObjectHandle
void objectWarning(std::string const& warning);
void assertType(char const* type_name, bool istype);
bool dereference();
+ void copyObject1(
+ std::set<QPDFObjGen>& visited,
+ bool cross_indirect,
+ bool first_level_only,
+ bool stop_at_streams);
+ void shallowCopyInternal1(QPDFObjectHandle& oh, bool first_level_only);
+ void copyObject2(
+ std::set<QPDFObjGen>& visited,
+ bool cross_indirect,
+ bool first_level_only,
+ bool stop_at_streams);
+ void shallowCopyInternal2(QPDFObjectHandle& oh, bool first_level_only);
void copyObject(
std::set<QPDFObjGen>& visited,
bool cross_indirect,
bool first_level_only,
bool stop_at_streams);
- void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only);
void disconnect();
void setParsedOffset(qpdf_offset_t offset);
void parseContentStream_internal(
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index 02b40c4f..3938fcd2 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -2201,32 +2201,195 @@ QPDFObjectHandle
QPDFObjectHandle::shallowCopy()
{
QPDFObjectHandle result;
- shallowCopyInternal(result, false);
+ shallowCopyInternal1(result, false);
return result;
}
+void
+QPDFObjectHandle::shallowCopyInternal1(
+ QPDFObjectHandle& new_obj, bool first_level_only)
+{
+ assertInitialized();
+
+ if (isStream()) {
+ QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream");
+ throw std::runtime_error("attempt to make a shallow copy of a stream");
+ }
+ new_obj = QPDFObjectHandle(obj->copy(true));
+
+ std::set<QPDFObjGen> visited;
+ new_obj.copyObject1(visited, false, first_level_only, false);
+}
+
+void
+QPDFObjectHandle::copyObject1(
+ std::set<QPDFObjGen>& visited,
+ bool cross_indirect,
+ bool first_level_only,
+ bool stop_at_streams)
+{
+ assertInitialized();
+
+ if (isStream()) {
+ if (stop_at_streams) {
+ return;
+ }
+ throw std::runtime_error(
+ "attempt to make a stream into a direct object");
+ }
+
+ auto cur_og = getObjGen();
+ if (cur_og.getObj() != 0) {
+ if (visited.count(cur_og)) {
+ throw std::runtime_error(
+ "loop detected while converting object from "
+ "indirect to direct");
+ }
+ visited.insert(cur_og);
+ }
+
+ if (isReserved()) {
+ throw std::logic_error("QPDFObjectHandle: attempting to make a"
+ " reserved object handle direct");
+ }
+
+ std::shared_ptr<QPDFObject> new_obj;
+
+ if (isBool() || isInteger() || isName() || isNull() || isReal() ||
+ isString()) {
+ new_obj = obj->copy(true);
+ } else if (isArray()) {
+ std::vector<QPDFObjectHandle> items;
+ auto array = asArray();
+ int n = array->getNItems();
+ for (int i = 0; i < n; ++i) {
+ items.push_back(array->getItem(i));
+ if ((!first_level_only) &&
+ (cross_indirect || (!items.back().isIndirect()))) {
+ items.back().copyObject1(
+ visited, cross_indirect, first_level_only, stop_at_streams);
+ }
+ }
+ new_obj = QPDF_Array::create(items);
+ } else if (isDictionary()) {
+ std::map<std::string, QPDFObjectHandle> items;
+ auto dict = asDictionary();
+ for (auto const& key: getKeys()) {
+ items[key] = dict->getKey(key);
+ if ((!first_level_only) &&
+ (cross_indirect || (!items[key].isIndirect()))) {
+ items[key].copyObject1(
+ visited, cross_indirect, first_level_only, stop_at_streams);
+ }
+ }
+ new_obj = QPDF_Dictionary::create(items);
+ } else {
+ throw std::logic_error("QPDFObjectHandle::makeDirectInternal: "
+ "unknown object type");
+ }
+
+ this->obj = new_obj;
+
+ if (cur_og.getObj()) {
+ visited.erase(cur_og);
+ }
+}
+
QPDFObjectHandle
QPDFObjectHandle::unsafeShallowCopy()
{
QPDFObjectHandle result;
- shallowCopyInternal(result, true);
+ shallowCopyInternal2(result, true);
return result;
}
void
-QPDFObjectHandle::shallowCopyInternal(
+QPDFObjectHandle::shallowCopyInternal2(
QPDFObjectHandle& new_obj, bool first_level_only)
{
assertInitialized();
if (isStream()) {
- QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream");
throw std::runtime_error("attempt to make a shallow copy of a stream");
}
new_obj = QPDFObjectHandle(obj->copy(true));
std::set<QPDFObjGen> visited;
- new_obj.copyObject(visited, false, first_level_only, false);
+ new_obj.copyObject2(visited, false, first_level_only, false);
+}
+
+void
+QPDFObjectHandle::copyObject2(
+ std::set<QPDFObjGen>& visited,
+ bool cross_indirect,
+ bool first_level_only,
+ bool stop_at_streams)
+{
+ assertInitialized();
+
+ if (isStream()) {
+ if (stop_at_streams) {
+ return;
+ }
+ throw std::runtime_error(
+ "attempt to make a stream into a direct object");
+ }
+
+ auto cur_og = getObjGen();
+ if (cur_og.getObj() != 0) {
+ if (visited.count(cur_og)) {
+ throw std::runtime_error(
+ "loop detected while converting object from "
+ "indirect to direct");
+ }
+ visited.insert(cur_og);
+ }
+
+ if (isReserved()) {
+ throw std::logic_error("QPDFObjectHandle: attempting to make a"
+ " reserved object handle direct");
+ }
+
+ std::shared_ptr<QPDFObject> new_obj;
+
+ if (isBool() || isInteger() || isName() || isNull() || isReal() ||
+ isString()) {
+ new_obj = obj->copy(true);
+ } else if (isArray()) {
+ std::vector<QPDFObjectHandle> items;
+ auto array = asArray();
+ int n = array->getNItems();
+ for (int i = 0; i < n; ++i) {
+ items.push_back(array->getItem(i));
+ if ((!first_level_only) &&
+ (cross_indirect || (!items.back().isIndirect()))) {
+ items.back().copyObject2(
+ visited, cross_indirect, first_level_only, stop_at_streams);
+ }
+ }
+ new_obj = QPDF_Array::create(items);
+ } else if (isDictionary()) {
+ std::map<std::string, QPDFObjectHandle> items;
+ auto dict = asDictionary();
+ for (auto const& key: getKeys()) {
+ items[key] = dict->getKey(key);
+ if ((!first_level_only) &&
+ (cross_indirect || (!items[key].isIndirect()))) {
+ items[key].copyObject2(
+ visited, cross_indirect, first_level_only, stop_at_streams);
+ }
+ }
+ new_obj = QPDF_Dictionary::create(items);
+ } else {
+ throw std::logic_error("QPDFObjectHandle::makeDirectInternal: "
+ "unknown object type");
+ }
+
+ this->obj = new_obj;
+
+ if (cur_og.getObj()) {
+ visited.erase(cur_og);
+ }
}
void