#include #include static const QPDFObjectHandle null_oh = QPDFObjectHandle::newNull(); inline void QPDF_Array::checkOwnership(QPDFObjectHandle const& item) const { 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 const& v) : QPDFValue(::ot_array, "array") { setFromVector(v); } QPDF_Array::QPDF_Array( std::vector>&& v, bool sparse) : QPDFValue(::ot_array, "array"), sparse(sparse) { if (sparse) { sp_elements = SparseOHArray(); for (auto&& item: v) { if (item->getTypeCode() != ::ot_null || item->getObjGen().isIndirect()) { sp_elements.elements[sp_elements.n_elements] = std::move(item); } ++sp_elements.n_elements; } } else { elements = std::move(v); } } QPDF_Array::QPDF_Array(SparseOHArray const& items) : QPDFValue(::ot_array, "array"), sparse(true), sp_elements(items) { } QPDF_Array::QPDF_Array(std::vector> const& items) : QPDFValue(::ot_array, "array"), sparse(false), elements(items) { } std::shared_ptr QPDF_Array::create(std::vector const& items) { return do_create(new QPDF_Array(items)); } std::shared_ptr QPDF_Array::create( std::vector>&& items, bool sparse) { return do_create(new QPDF_Array(std::move(items), sparse)); } std::shared_ptr QPDF_Array::create(SparseOHArray const& items) { return do_create(new QPDF_Array(items)); } std::shared_ptr QPDF_Array::create(std::vector> const& items) { return do_create(new QPDF_Array(items)); } std::shared_ptr QPDF_Array::copy(bool shallow) { if (sparse) { return create(shallow ? sp_elements : sp_elements.copy()); } else { if (shallow) { return create(elements); } else { std::vector> result; result.reserve(elements.size()); for (auto const& element: elements) { result.push_back( element ? (element->getObjGen().isIndirect() ? element : element->copy()) : element); } return create(result); } } } void QPDF_Array::disconnect() { if (sparse) { sp_elements.disconnect(); } else { for (auto const& iter: elements) { if (iter) { QPDFObjectHandle::DisconnectAccess::disconnect(iter); } } } } std::string QPDF_Array::unparse() { if (sparse) { std::string result = "[ "; int size = sp_elements.size(); for (int i = 0; i < size; ++i) { result += at(i).unparse(); result += " "; } result += "]"; return result; } else { std::string result = "[ "; auto size = elements.size(); for (int i = 0; i < int(size); ++i) { result += at(i).unparse(); result += " "; } result += "]"; return result; } } JSON QPDF_Array::getJSON(int json_version) { if (sparse) { JSON j = JSON::makeArray(); int size = sp_elements.size(); for (int i = 0; i < size; ++i) { j.addArrayElement(at(i).getJSON(json_version)); } return j; } else { JSON j = JSON::makeArray(); size_t size = elements.size(); for (int i = 0; i < int(size); ++i) { j.addArrayElement(at(i).getJSON(json_version)); } return j; } } QPDFObjectHandle QPDF_Array::at(int n) const noexcept { if (n < 0 || n >= size()) { return {}; } else if (sparse) { auto const& iter = sp_elements.elements.find(n); return iter == sp_elements.elements.end() ? null_oh : (*iter).second; } else { return elements[size_t(n)]; } } std::vector QPDF_Array::getAsVector() const { if (sparse) { std::vector v; v.reserve(size_t(size())); for (auto const& item: sp_elements.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()}; } } bool QPDF_Array::setAt(int at, QPDFObjectHandle const& oh) { if (at < 0 || at >= size()) { return false; } checkOwnership(oh); if (sparse) { sp_elements.elements[at] = oh.getObj(); } else { elements[size_t(at)] = oh.getObj(); } return true; } void QPDF_Array::setFromVector(std::vector const& v) { elements.resize(0); elements.reserve(v.size()); for (auto const& item: v) { checkOwnership(item); elements.push_back(item.getObj()); } } bool QPDF_Array::insert(int at, QPDFObjectHandle const& 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.elements.crbegin(); while (iter != sp_elements.elements.crend()) { auto key = (iter++)->first; if (key >= at) { auto nh = sp_elements.elements.extract(key); ++nh.key(); sp_elements.elements.insert(std::move(nh)); } else { break; } } sp_elements.elements[at] = item.getObj(); ++sp_elements.n_elements; } else { elements.insert(elements.cbegin() + at, item.getObj()); } } return true; } void QPDF_Array::push_back(QPDFObjectHandle const& item) { checkOwnership(item); if (sparse) { sp_elements.elements[sp_elements.n_elements++] = item.getObj(); } else { elements.push_back(item.getObj()); } } bool QPDF_Array::erase(int at) { if (at < 0 || at >= size()) { return false; } if (sparse) { auto end = sp_elements.elements.end(); if (auto iter = sp_elements.elements.lower_bound(at); iter != end) { if (iter->first == at) { iter++; sp_elements.elements.erase(at); } while (iter != end) { auto nh = sp_elements.elements.extract(iter++); --nh.key(); sp_elements.elements.insert(std::move(nh)); } } --sp_elements.n_elements; } else { elements.erase(elements.cbegin() + at); } return true; }