diff options
author | Jay Berkenbilt <jberkenbilt@users.noreply.github.com> | 2023-04-01 17:05:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-01 17:05:07 +0200 |
commit | f8e39253be9d1806ccdb88d8117b7418f2045da1 (patch) | |
tree | 1d4922b77141be39dfceecb8f2d39525d6bd4f97 /libqpdf/QPDF_Array.cc | |
parent | 40e4d1f97cbf5cb58d5324380da415f12d3aaa32 (diff) | |
parent | 0b53b648ab79a35b9ec0da56c0b936955a51d135 (diff) | |
download | qpdf-f8e39253be9d1806ccdb88d8117b7418f2045da1.tar.zst |
Merge pull request #863 from m-holger/array
Refactor QPDF_Array
Diffstat (limited to 'libqpdf/QPDF_Array.cc')
-rw-r--r-- | libqpdf/QPDF_Array.cc | 312 |
1 files changed, 232 insertions, 80 deletions
diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc index de34103e..3bd139b1 100644 --- a/libqpdf/QPDF_Array.cc +++ b/libqpdf/QPDF_Array.cc @@ -1,66 +1,157 @@ #include <qpdf/QPDF_Array.hh> -#include <qpdf/QIntC.hh> +#include <qpdf/QPDFObjectHandle.hh> #include <qpdf/QPDFObject_private.hh> -#include <qpdf/QUtil.hh> -#include <stdexcept> -QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) : - QPDFValue(::ot_array, "array") +static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); + +inline void +QPDF_Array::checkOwnership(QPDFObjectHandle const& item) const { - setFromVector(v); + if (auto obj = item.getObjectPtr()) { + if (qpdf) { + if (auto item_qpdf = obj->getQPDF()) { + if (qpdf != item_qpdf) { + throw std::logic_error( + "Attempting to add an object from a different QPDF. " + "Use QPDF::copyForeignObject to add objects from " + "another file."); + } + } + } + } else { + throw std::logic_error( + "Attempting to add an uninitialized object to a QPDF_Array."); + } } -QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v) : +QPDF_Array::QPDF_Array() : QPDFValue(::ot_array, "array") { - setFromVector(std::move(v)); } -QPDF_Array::QPDF_Array(SparseOHArray const& items) : +QPDF_Array::QPDF_Array(QPDF_Array const& other) : QPDFValue(::ot_array, "array"), - elements(items) + sparse(other.sparse), + sp_size(other.sp_size), + sp_elements(other.sp_elements), + elements(other.elements) { } -std::shared_ptr<QPDFObject> -QPDF_Array::create(std::vector<QPDFObjectHandle> const& items) +QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) : + QPDFValue(::ot_array, "array") { - return do_create(new QPDF_Array(items)); + setFromVector(v); } -std::shared_ptr<QPDFObject> -QPDF_Array::create(std::vector<std::shared_ptr<QPDFObject>>&& items) +QPDF_Array::QPDF_Array( + std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse) : + QPDFValue(::ot_array, "array"), + sparse(sparse) { - return do_create(new QPDF_Array(std::move(items))); + if (sparse) { + for (auto&& item: v) { + if (item->getTypeCode() != ::ot_null || + item->getObjGen().isIndirect()) { + sp_elements[sp_size] = std::move(item); + } + ++sp_size; + } + } else { + elements = std::move(v); + } } std::shared_ptr<QPDFObject> -QPDF_Array::create(SparseOHArray const& items) +QPDF_Array::create(std::vector<QPDFObjectHandle> const& items) { return do_create(new QPDF_Array(items)); } std::shared_ptr<QPDFObject> +QPDF_Array::create( + std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse) +{ + return do_create(new QPDF_Array(std::move(items), sparse)); +} + +std::shared_ptr<QPDFObject> QPDF_Array::copy(bool shallow) { - return create(shallow ? elements : elements.copy()); + if (shallow) { + return do_create(new QPDF_Array(*this)); + } else { + if (sparse) { + QPDF_Array* result = new QPDF_Array(); + result->sp_size = sp_size; + for (auto const& element: sp_elements) { + auto const& obj = element.second; + result->sp_elements[element.first] = + obj->getObjGen().isIndirect() ? obj : obj->copy(); + } + return do_create(result); + } else { + std::vector<std::shared_ptr<QPDFObject>> result; + result.reserve(elements.size()); + for (auto const& element: elements) { + result.push_back( + element + ? (element->getObjGen().isIndirect() ? element + : element->copy()) + : element); + } + return create(std::move(result), false); + } + } } void QPDF_Array::disconnect() { - elements.disconnect(); + if (sparse) { + for (auto& item: sp_elements) { + auto& obj = item.second; + if (!obj->getObjGen().isIndirect()) { + obj->disconnect(); + } + } + } else { + for (auto& obj: elements) { + if (!obj->getObjGen().isIndirect()) { + obj->disconnect(); + } + } + } } std::string QPDF_Array::unparse() { std::string result = "[ "; - size_t size = this->elements.size(); - for (size_t i = 0; i < size; ++i) { - result += this->elements.at(i).unparse(); - result += " "; + if (sparse) { + int next = 0; + for (auto& item: sp_elements) { + int key = item.first; + for (int j = next; j < key; ++j) { + result += "null "; + } + item.second->resolve(); + auto og = item.second->getObjGen(); + result += og.isIndirect() ? og.unparse(' ') + " R " + : item.second->unparse() + " "; + next = ++key; + } + for (int j = next; j < sp_size; ++j) { + result += "null "; + } + } else { + for (auto const& item: elements) { + item->resolve(); + auto og = item->getObjGen(); + result += og.isIndirect() ? og.unparse(' ') + " R " + : item->unparse() + " "; + } } result += "]"; return result; @@ -69,96 +160,157 @@ QPDF_Array::unparse() JSON QPDF_Array::getJSON(int json_version) { - JSON j = JSON::makeArray(); - size_t size = this->elements.size(); - for (size_t i = 0; i < size; ++i) { - j.addArrayElement(this->elements.at(i).getJSON(json_version)); + static const JSON j_null = JSON::makeNull(); + JSON j_array = JSON::makeArray(); + if (sparse) { + int next = 0; + for (auto& item: sp_elements) { + int key = item.first; + for (int j = next; j < key; ++j) { + j_array.addArrayElement(j_null); + } + auto og = item.second->getObjGen(); + j_array.addArrayElement( + og.isIndirect() ? JSON::makeString(og.unparse(' ') + " R") + : item.second->getJSON(json_version)); + next = ++key; + } + for (int j = next; j < sp_size; ++j) { + j_array.addArrayElement(j_null); + } + } else { + for (auto const& item: elements) { + auto og = item->getObjGen(); + j_array.addArrayElement( + og.isIndirect() ? JSON::makeString(og.unparse(' ') + " R") + : item->getJSON(json_version)); + } } - return j; -} - -int -QPDF_Array::getNItems() const -{ - // This should really return a size_t, but changing it would break - // a lot of code. - return QIntC::to_int(this->elements.size()); + return j_array; } QPDFObjectHandle -QPDF_Array::getItem(int n) const +QPDF_Array::at(int n) const noexcept { - if ((n < 0) || (n >= QIntC::to_int(elements.size()))) { - throw std::logic_error( - "INTERNAL ERROR: bounds error accessing QPDF_Array element"); + if (n < 0 || n >= size()) { + return {}; + } else if (sparse) { + auto const& iter = sp_elements.find(n); + return iter == sp_elements.end() ? null_oh : (*iter).second; + } else { + return elements[size_t(n)]; } - return this->elements.at(QIntC::to_size(n)); } -void -QPDF_Array::getAsVector(std::vector<QPDFObjectHandle>& v) const +std::vector<QPDFObjectHandle> +QPDF_Array::getAsVector() const { - size_t size = this->elements.size(); - for (size_t i = 0; i < size; ++i) { - v.push_back(this->elements.at(i)); + if (sparse) { + std::vector<QPDFObjectHandle> v; + v.reserve(size_t(size())); + for (auto const& item: sp_elements) { + v.resize(size_t(item.first), null_oh); + v.push_back(item.second); + } + v.resize(size_t(size()), null_oh); + return v; + } else { + return {elements.cbegin(), elements.cend()}; } } -void -QPDF_Array::setItem(int n, QPDFObjectHandle const& oh) +bool +QPDF_Array::setAt(int at, QPDFObjectHandle const& oh) { - this->elements.setAt(QIntC::to_size(n), oh); + if (at < 0 || at >= size()) { + return false; + } + checkOwnership(oh); + if (sparse) { + sp_elements[at] = oh.getObj(); + } else { + elements[size_t(at)] = oh.getObj(); + } + return true; } void QPDF_Array::setFromVector(std::vector<QPDFObjectHandle> const& v) { - this->elements = SparseOHArray(); - for (auto const& iter: v) { - this->elements.append(iter); + elements.resize(0); + elements.reserve(v.size()); + for (auto const& item: v) { + checkOwnership(item); + elements.push_back(item.getObj()); } } -void -QPDF_Array::setFromVector(std::vector<std::shared_ptr<QPDFObject>>&& v) +bool +QPDF_Array::insert(int at, QPDFObjectHandle const& item) { - this->elements = SparseOHArray(); - for (auto&& item: v) { - if (item) { - this->elements.append(item); + int sz = size(); + if (at < 0 || at > sz) { + // As special case, also allow insert beyond the end + return false; + } else if (at == sz) { + push_back(item); + } else { + checkOwnership(item); + if (sparse) { + auto iter = sp_elements.crbegin(); + while (iter != sp_elements.crend()) { + auto key = (iter++)->first; + if (key >= at) { + auto nh = sp_elements.extract(key); + ++nh.key(); + sp_elements.insert(std::move(nh)); + } else { + break; + } + } + sp_elements[at] = item.getObj(); + ++sp_size; } else { - ++this->elements.n_elements; + elements.insert(elements.cbegin() + at, item.getObj()); } } + return true; } void -QPDF_Array::insertItem(int at, QPDFObjectHandle const& item) +QPDF_Array::push_back(QPDFObjectHandle const& item) { - // As special case, also allow insert beyond the end - if ((at < 0) || (at > QIntC::to_int(this->elements.size()))) { - throw std::logic_error( - "INTERNAL ERROR: bounds error accessing QPDF_Array element"); + checkOwnership(item); + if (sparse) { + sp_elements[sp_size++] = item.getObj(); + } else { + elements.push_back(item.getObj()); } - this->elements.insert(QIntC::to_size(at), item); } -void -QPDF_Array::appendItem(QPDFObjectHandle const& item) +bool +QPDF_Array::erase(int at) { - this->elements.append(item); -} - -void -QPDF_Array::eraseItem(int at) -{ - this->elements.erase(QIntC::to_size(at)); -} + if (at < 0 || at >= size()) { + return false; + } + if (sparse) { + auto end = sp_elements.end(); + if (auto iter = sp_elements.lower_bound(at); iter != end) { + if (iter->first == at) { + iter++; + sp_elements.erase(at); + } -void -QPDF_Array::addExplicitElementsToList(std::list<QPDFObjectHandle>& l) const -{ - for (auto const& iter: this->elements) { - l.push_back(iter.second); + while (iter != end) { + auto nh = sp_elements.extract(iter++); + --nh.key(); + sp_elements.insert(std::move(nh)); + } + } + --sp_size; + } else { + elements.erase(elements.cbegin() + at); } + return true; } |