From b1eb1a958438025efbf90f7a7f45dbe33c746d91 Mon Sep 17 00:00:00 2001 From: m-holger Date: Mon, 14 Nov 2022 22:06:04 +0000 Subject: [PATCH] Refactor QPDFObjectHandle::copyObject1 --- libqpdf/QPDFObjectHandle.cc | 37 ++++++++---------------------- libqpdf/QPDF_Array.cc | 2 +- libqpdf/QPDF_Dictionary.cc | 12 +++++++++- libqpdf/QPDF_Stream.cc | 1 + libqpdf/SparseOHArray.cc | 13 +++++++++++ libqpdf/qpdf/SparseOHArray.hh | 1 + qpdf/qpdf.testcov | 2 +- qpdf/qtest/qpdf/shallow_stream.out | 2 +- 8 files changed, 38 insertions(+), 32 deletions(-) diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index 3e37a966..2990b019 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -2211,8 +2211,7 @@ QPDFObjectHandle::shallowCopyInternal1(QPDFObjectHandle& new_obj) assertInitialized(); if (isStream()) { - QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream"); - throw std::runtime_error("attempt to make a shallow copy of a stream"); + // Handled bt QPDF_Stream::copy() } new_obj = QPDFObjectHandle(obj->copy(true)); @@ -2225,9 +2224,10 @@ QPDFObjectHandle::copyObject1(std::set& visited) { assertInitialized(); + std::shared_ptr new_obj; + if (isStream()) { - throw std::runtime_error( - "attempt to make a stream into a direct object"); + new_obj = obj->copy(); } auto cur_og = getObjGen(); @@ -2241,36 +2241,17 @@ QPDFObjectHandle::copyObject1(std::set& visited) } if (isReserved()) { - throw std::logic_error("QPDFObjectHandle: attempting to make a" - " reserved object handle direct"); + new_obj = obj->copy(); } - std::shared_ptr new_obj; - if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) { - new_obj = obj->copy(true); + // copy(true) and copy(false) are the same + new_obj = obj->copy(); } else if (isArray()) { - std::vector items; - auto array = asArray(); - int n = array->getNItems(); - for (int i = 0; i < n; ++i) { - items.push_back(array->getItem(i)); - if (!items.back().isIndirect()) { - items.back().copyObject1(visited); - } - } - new_obj = QPDF_Array::create(items); + new_obj = obj->copy(); } else if (isDictionary()) { - std::map items; - auto dict = asDictionary(); - for (auto const& key: getKeys()) { - items[key] = dict->getKey(key); - if (!items[key].isIndirect()) { - items[key].copyObject1(visited); - } - } - new_obj = QPDF_Dictionary::create(items); + new_obj = obj->copy(); } else { throw std::logic_error("QPDFObjectHandle::makeDirectInternal: " "unknown object type"); diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc index f33ad99d..6e8db5e9 100644 --- a/libqpdf/QPDF_Array.cc +++ b/libqpdf/QPDF_Array.cc @@ -31,7 +31,7 @@ QPDF_Array::create(SparseOHArray const& items) std::shared_ptr QPDF_Array::copy(bool shallow) { - return create(elements); + return create(shallow ? elements : elements.copy()); } void diff --git a/libqpdf/QPDF_Dictionary.cc b/libqpdf/QPDF_Dictionary.cc index 5b1e03d8..1df4f8f0 100644 --- a/libqpdf/QPDF_Dictionary.cc +++ b/libqpdf/QPDF_Dictionary.cc @@ -18,7 +18,17 @@ QPDF_Dictionary::create(std::map const& items) std::shared_ptr QPDF_Dictionary::copy(bool shallow) { - return create(items); + if (shallow) { + return create(items); + } else { + std::map new_items; + for (auto const& item: this->items) { + auto value = item.second; + new_items[item.first] = + value.isIndirect() ? value : value.shallowCopy(); + } + return create(new_items); + } } void diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 332eaa37..480bb6e9 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -142,6 +142,7 @@ QPDF_Stream::create( std::shared_ptr QPDF_Stream::copy(bool shallow) { + QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream"); throw std::runtime_error("stream objects cannot be cloned"); } diff --git a/libqpdf/SparseOHArray.cc b/libqpdf/SparseOHArray.cc index 6ff02f6c..567f9d0b 100644 --- a/libqpdf/SparseOHArray.cc +++ b/libqpdf/SparseOHArray.cc @@ -110,6 +110,19 @@ SparseOHArray::insert(size_t idx, QPDFObjectHandle oh) } } +SparseOHArray +SparseOHArray::copy() +{ + SparseOHArray result; + result.n_elements = this->n_elements; + for (auto const& element: this->elements) { + auto value = element.second; + result.elements[element.first] = + value.isIndirect() ? value : value.shallowCopy(); + } + return result; +} + SparseOHArray::const_iterator SparseOHArray::begin() const { diff --git a/libqpdf/qpdf/SparseOHArray.hh b/libqpdf/qpdf/SparseOHArray.hh index 440c0b2d..b6918cb5 100644 --- a/libqpdf/qpdf/SparseOHArray.hh +++ b/libqpdf/qpdf/SparseOHArray.hh @@ -15,6 +15,7 @@ class SparseOHArray void setAt(size_t idx, QPDFObjectHandle oh); void erase(size_t idx); void insert(size_t idx, QPDFObjectHandle oh); + SparseOHArray copy(); void disconnect(); typedef std::unordered_map::const_iterator diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index f99d3f74..d9215dd1 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -192,7 +192,7 @@ QPDF insert page 2 QPDF updateAllPagesCache 0 QPDF insert non-indirect page 0 QPDF insert indirect page 0 -QPDFObjectHandle ERR shallow copy stream 0 +QPDF_Stream ERR shallow copy stream 0 QPDFObjectHandle newStream with string 0 QPDF unknown key not inherited 0 QPDF_Stream provider length not provided 0 diff --git a/qpdf/qtest/qpdf/shallow_stream.out b/qpdf/qtest/qpdf/shallow_stream.out index fec1aa83..f77e9de5 100644 --- a/qpdf/qtest/qpdf/shallow_stream.out +++ b/qpdf/qtest/qpdf/shallow_stream.out @@ -1 +1 @@ -attempt to make a shallow copy of a stream +stream objects cannot be cloned