aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/CMakeLists.txt1
-rw-r--r--libqpdf/OHArray.cc148
-rw-r--r--libqpdf/QPDF_Array.cc181
-rw-r--r--libqpdf/qpdf/OHArray.hh35
-rw-r--r--libqpdf/qpdf/QPDF_Array.hh7
5 files changed, 330 insertions, 42 deletions
diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt
index 5e3a628e..2d857f45 100644
--- a/libqpdf/CMakeLists.txt
+++ b/libqpdf/CMakeLists.txt
@@ -116,6 +116,7 @@ set(libqpdf_SOURCES
SecureRandomDataProvider.cc
SF_FlateLzwDecode.cc
SparseOHArray.cc
+ OHArray.cc
qpdf-c.cc
qpdfjob-c.cc
qpdflogger-c.cc)
diff --git a/libqpdf/OHArray.cc b/libqpdf/OHArray.cc
new file mode 100644
index 00000000..436fa4f2
--- /dev/null
+++ b/libqpdf/OHArray.cc
@@ -0,0 +1,148 @@
+#include <qpdf/OHArray.hh>
+
+#include <qpdf/QPDFObjectHandle.hh>
+#include <qpdf/QPDFObject_private.hh>
+
+#include <stdexcept>
+
+OHArray::OHArray() :
+ n_elements(0)
+{
+}
+
+size_t
+OHArray::size() const
+{
+ return this->n_elements;
+}
+
+void
+OHArray::append(QPDFObjectHandle oh)
+{
+ if (!oh.isDirectNull()) {
+ this->elements[this->n_elements] = oh;
+ }
+ ++this->n_elements;
+}
+
+void
+OHArray::append(std::shared_ptr<QPDFObject>&& obj)
+{
+ if (obj->getTypeCode() != ::ot_null || !obj->getObjGen().isIndirect()) {
+ this->elements[this->n_elements] = std::move(obj);
+ }
+ ++this->n_elements;
+}
+
+QPDFObjectHandle
+OHArray::at(size_t idx) const
+{
+ if (idx >= this->n_elements) {
+ throw std::logic_error(
+ "INTERNAL ERROR: bounds error accessing OHArray element");
+ }
+ auto const& iter = this->elements.find(idx);
+ if (iter == this->elements.end()) {
+ return QPDFObjectHandle::newNull();
+ } else {
+ return (*iter).second;
+ }
+}
+
+void
+OHArray::remove_last()
+{
+ if (this->n_elements == 0) {
+ throw std::logic_error("INTERNAL ERROR: attempt to remove"
+ " last item from empty OHArray");
+ }
+ --this->n_elements;
+ this->elements.erase(this->n_elements);
+}
+
+void
+OHArray::disconnect()
+{
+ for (auto& iter: this->elements) {
+ QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
+ }
+}
+
+void
+OHArray::setAt(size_t idx, QPDFObjectHandle oh)
+{
+ if (idx >= this->n_elements) {
+ throw std::logic_error("bounds error setting item in OHArray");
+ }
+ if (oh.isDirectNull()) {
+ this->elements.erase(idx);
+ } else {
+ this->elements[idx] = oh;
+ }
+}
+
+void
+OHArray::erase(size_t idx)
+{
+ if (idx >= this->n_elements) {
+ throw std::logic_error("bounds error erasing item from OHArray");
+ }
+ decltype(this->elements) dest;
+ for (auto const& iter: this->elements) {
+ if (iter.first < idx) {
+ dest.insert(iter);
+ } else if (iter.first > idx) {
+ dest[iter.first - 1] = iter.second;
+ }
+ }
+ this->elements = dest;
+ --this->n_elements;
+}
+
+void
+OHArray::insert(size_t idx, QPDFObjectHandle oh)
+{
+ if (idx > this->n_elements) {
+ throw std::logic_error("bounds error inserting item to OHArray");
+ } else if (idx == this->n_elements) {
+ // Allow inserting to the last position
+ append(oh);
+ } else {
+ decltype(this->elements) dest;
+ for (auto const& iter: this->elements) {
+ if (iter.first < idx) {
+ dest.insert(iter);
+ } else {
+ dest[iter.first + 1] = iter.second;
+ }
+ }
+ this->elements = dest;
+ this->elements[idx] = oh;
+ ++this->n_elements;
+ }
+}
+
+OHArray
+OHArray::copy()
+{
+ OHArray 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;
+}
+
+OHArray::const_iterator
+OHArray::begin() const
+{
+ return this->elements.begin();
+}
+
+OHArray::const_iterator
+OHArray::end() const
+{
+ return this->elements.end();
+}
diff --git a/libqpdf/QPDF_Array.cc b/libqpdf/QPDF_Array.cc
index 93fbf928..ed43245f 100644
--- a/libqpdf/QPDF_Array.cc
+++ b/libqpdf/QPDF_Array.cc
@@ -19,6 +19,13 @@ QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v) :
QPDF_Array::QPDF_Array(SparseOHArray const& items) :
QPDFValue(::ot_array, "array"),
+ sp_elements(items)
+{
+}
+
+QPDF_Array::QPDF_Array(OHArray const& items) :
+ QPDFValue(::ot_array, "array"),
+ sparse(false),
elements(items)
{
}
@@ -42,92 +49,167 @@ QPDF_Array::create(SparseOHArray const& items)
}
std::shared_ptr<QPDFObject>
+QPDF_Array::create(OHArray const& items)
+{
+ return do_create(new QPDF_Array(items));
+}
+
+std::shared_ptr<QPDFObject>
QPDF_Array::copy(bool shallow)
{
- return create(shallow ? elements : elements.copy());
+ if (sparse) {
+ return create(shallow ? sp_elements : sp_elements.copy());
+ } else {
+ return create(shallow ? elements : elements.copy());
+ }
}
void
QPDF_Array::disconnect()
{
- elements.disconnect();
+ if (sparse) {
+ sp_elements.disconnect();
+ } else {
+ elements.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) {
+ std::string result = "[ ";
+ size_t size = sp_elements.size();
+ for (size_t i = 0; i < size; ++i) {
+ result += sp_elements.at(i).unparse();
+ result += " ";
+ }
+ result += "]";
+ return result;
+ } else {
+ std::string result = "[ ";
+ size_t size = elements.size();
+ for (size_t i = 0; i < size; ++i) {
+ result += elements.at(i).unparse();
+ result += " ";
+ }
+ result += "]";
+ return result;
}
- result += "]";
- return result;
}
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));
+ if (sparse) {
+ JSON j = JSON::makeArray();
+ size_t size = sp_elements.size();
+ for (size_t i = 0; i < size; ++i) {
+ j.addArrayElement(sp_elements.at(i).getJSON(json_version));
+ }
+ return j;
+ } else {
+ JSON j = JSON::makeArray();
+ size_t size = elements.size();
+ for (size_t i = 0; i < size; ++i) {
+ j.addArrayElement(elements.at(i).getJSON(json_version));
+ }
+ return j;
}
- 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());
+ if (sparse) {
+ // This should really return a size_t, but changing it would break
+ // a lot of code.
+ return QIntC::to_int(sp_elements.size());
+ } else {
+ return QIntC::to_int(elements.size());
+ }
}
QPDFObjectHandle
QPDF_Array::getItem(int n) const
{
- if ((n < 0) || (n >= QIntC::to_int(elements.size()))) {
- throw std::logic_error(
- "INTERNAL ERROR: bounds error accessing QPDF_Array element");
+ if (sparse) {
+ if ((n < 0) || (n >= QIntC::to_int(sp_elements.size()))) {
+ throw std::logic_error(
+ "INTERNAL ERROR: bounds error accessing QPDF_Array element");
+ }
+ return sp_elements.at(QIntC::to_size(n));
+ } else {
+ if ((n < 0) || (n >= QIntC::to_int(elements.size()))) {
+ throw std::logic_error(
+ "INTERNAL ERROR: bounds error accessing QPDF_Array element");
+ }
+ return elements.at(QIntC::to_size(n));
}
- return this->elements.at(QIntC::to_size(n));
}
void
QPDF_Array::getAsVector(std::vector<QPDFObjectHandle>& v) const
{
- size_t size = this->elements.size();
- for (size_t i = 0; i < size; ++i) {
- v.push_back(this->elements.at(i));
+ if (sparse) {
+ size_t size = sp_elements.size();
+ for (size_t i = 0; i < size; ++i) {
+ v.push_back(sp_elements.at(i));
+ }
+ } else {
+ size_t size = elements.size();
+ for (size_t i = 0; i < size; ++i) {
+ v.push_back(elements.at(i));
+ }
}
}
void
QPDF_Array::setItem(int n, QPDFObjectHandle const& oh)
{
- this->elements.setAt(QIntC::to_size(n), oh);
+ if (sparse) {
+ sp_elements.setAt(QIntC::to_size(n), oh);
+ } else {
+ elements.setAt(QIntC::to_size(n), oh);
+ }
}
void
QPDF_Array::setFromVector(std::vector<QPDFObjectHandle> const& v)
{
- this->elements = SparseOHArray();
- for (auto const& iter: v) {
- this->elements.append(iter);
+ if (sparse) {
+ sp_elements = SparseOHArray();
+ for (auto const& iter: v) {
+ sp_elements.append(iter);
+ }
+ } else {
+ elements = OHArray();
+ for (auto const& iter: v) {
+ elements.append(iter);
+ }
}
}
void
QPDF_Array::setFromVector(std::vector<std::shared_ptr<QPDFObject>>&& v)
{
- this->elements = SparseOHArray();
- for (auto&& item: v) {
- if (item) {
- this->elements.append(item);
- } else {
- ++this->elements.n_elements;
+ if (sparse) {
+ sp_elements = SparseOHArray();
+ for (auto&& item: v) {
+ if (item) {
+ sp_elements.append(item);
+ } else {
+ ++sp_elements.n_elements;
+ }
+ }
+ } else {
+ elements = OHArray();
+ for (auto&& item: v) {
+ if (item) {
+ elements.append(item);
+ } else {
+ ++elements.n_elements;
+ }
}
}
}
@@ -135,22 +217,39 @@ QPDF_Array::setFromVector(std::vector<std::shared_ptr<QPDFObject>>&& v)
void
QPDF_Array::insertItem(int at, 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");
+ if (sparse) {
+ // As special case, also allow insert beyond the end
+ if ((at < 0) || (at > QIntC::to_int(sp_elements.size()))) {
+ throw std::logic_error(
+ "INTERNAL ERROR: bounds error accessing QPDF_Array element");
+ }
+ sp_elements.insert(QIntC::to_size(at), item);
+ } else {
+ // As special case, also allow insert beyond the end
+ if ((at < 0) || (at > QIntC::to_int(elements.size()))) {
+ throw std::logic_error(
+ "INTERNAL ERROR: bounds error accessing QPDF_Array element");
+ }
+ elements.insert(QIntC::to_size(at), item);
}
- this->elements.insert(QIntC::to_size(at), item);
}
void
QPDF_Array::appendItem(QPDFObjectHandle const& item)
{
- this->elements.append(item);
+ if (sparse) {
+ sp_elements.append(item);
+ } else {
+ elements.append(item);
+ }
}
void
QPDF_Array::eraseItem(int at)
{
- this->elements.erase(QIntC::to_size(at));
+ if (sparse) {
+ sp_elements.erase(QIntC::to_size(at));
+ } else {
+ elements.erase(QIntC::to_size(at));
+ }
}
diff --git a/libqpdf/qpdf/OHArray.hh b/libqpdf/qpdf/OHArray.hh
new file mode 100644
index 00000000..66223c4f
--- /dev/null
+++ b/libqpdf/qpdf/OHArray.hh
@@ -0,0 +1,35 @@
+#ifndef QPDF_OHARRAY_HH
+#define QPDF_OHARRAY_HH
+
+#include <qpdf/QPDFObjectHandle.hh>
+#include <unordered_map>
+
+class QPDF_Array;
+
+class OHArray
+{
+ public:
+ OHArray();
+ size_t size() const;
+ void append(QPDFObjectHandle oh);
+ void append(std::shared_ptr<QPDFObject>&& obj);
+ QPDFObjectHandle at(size_t idx) const;
+ void remove_last();
+ void setAt(size_t idx, QPDFObjectHandle oh);
+ void erase(size_t idx);
+ void insert(size_t idx, QPDFObjectHandle oh);
+ OHArray copy();
+ void disconnect();
+
+ typedef std::unordered_map<size_t, QPDFObjectHandle>::const_iterator
+ const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ private:
+ friend class QPDF_Array;
+ std::unordered_map<size_t, QPDFObjectHandle> elements;
+ size_t n_elements;
+};
+
+#endif // QPDF_OHARRAY_HH
diff --git a/libqpdf/qpdf/QPDF_Array.hh b/libqpdf/qpdf/QPDF_Array.hh
index 88397ba7..1c4227ba 100644
--- a/libqpdf/qpdf/QPDF_Array.hh
+++ b/libqpdf/qpdf/QPDF_Array.hh
@@ -3,6 +3,7 @@
#include <qpdf/QPDFValue.hh>
+#include <qpdf/OHArray.hh>
#include <qpdf/SparseOHArray.hh>
#include <list>
#include <vector>
@@ -16,6 +17,7 @@ class QPDF_Array: public QPDFValue
static std::shared_ptr<QPDFObject>
create(std::vector<std::shared_ptr<QPDFObject>>&& items);
static std::shared_ptr<QPDFObject> create(SparseOHArray const& items);
+ static std::shared_ptr<QPDFObject> create(OHArray const& items);
virtual std::shared_ptr<QPDFObject> copy(bool shallow = false);
virtual std::string unparse();
virtual JSON getJSON(int json_version);
@@ -36,7 +38,10 @@ class QPDF_Array: public QPDFValue
QPDF_Array(std::vector<QPDFObjectHandle> const& items);
QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items);
QPDF_Array(SparseOHArray const& items);
- SparseOHArray elements;
+ QPDF_Array(OHArray const& items);
+ bool sparse{false};
+ SparseOHArray sp_elements;
+ OHArray elements;
};
#endif // QPDF_ARRAY_HH