Commit 38cf7c16283ec2d476514a54e2b1a7016b0b770a

Authored by m-holger
1 parent de29fd56

Add separate sparse mode to QPDF_Array

Add temporary clone of SparseOHArray  to implement non-sparse mode.
include/qpdf/QPDFObjectHandle.hh
... ... @@ -1497,6 +1497,7 @@ class QPDFObjectHandle
1497 1497 friend class QPDF_Dictionary;
1498 1498 friend class QPDF_Stream;
1499 1499 friend class SparseOHArray;
  1500 + friend class OHArray;
1500 1501  
1501 1502 private:
1502 1503 static void
... ...
libqpdf/CMakeLists.txt
... ... @@ -116,6 +116,7 @@ set(libqpdf_SOURCES
116 116 SecureRandomDataProvider.cc
117 117 SF_FlateLzwDecode.cc
118 118 SparseOHArray.cc
  119 + OHArray.cc
119 120 qpdf-c.cc
120 121 qpdfjob-c.cc
121 122 qpdflogger-c.cc)
... ...
libqpdf/OHArray.cc 0 → 100644
  1 +#include <qpdf/OHArray.hh>
  2 +
  3 +#include <qpdf/QPDFObjectHandle.hh>
  4 +#include <qpdf/QPDFObject_private.hh>
  5 +
  6 +#include <stdexcept>
  7 +
  8 +OHArray::OHArray() :
  9 + n_elements(0)
  10 +{
  11 +}
  12 +
  13 +size_t
  14 +OHArray::size() const
  15 +{
  16 + return this->n_elements;
  17 +}
  18 +
  19 +void
  20 +OHArray::append(QPDFObjectHandle oh)
  21 +{
  22 + if (!oh.isDirectNull()) {
  23 + this->elements[this->n_elements] = oh;
  24 + }
  25 + ++this->n_elements;
  26 +}
  27 +
  28 +void
  29 +OHArray::append(std::shared_ptr<QPDFObject>&& obj)
  30 +{
  31 + if (obj->getTypeCode() != ::ot_null || !obj->getObjGen().isIndirect()) {
  32 + this->elements[this->n_elements] = std::move(obj);
  33 + }
  34 + ++this->n_elements;
  35 +}
  36 +
  37 +QPDFObjectHandle
  38 +OHArray::at(size_t idx) const
  39 +{
  40 + if (idx >= this->n_elements) {
  41 + throw std::logic_error(
  42 + "INTERNAL ERROR: bounds error accessing OHArray element");
  43 + }
  44 + auto const& iter = this->elements.find(idx);
  45 + if (iter == this->elements.end()) {
  46 + return QPDFObjectHandle::newNull();
  47 + } else {
  48 + return (*iter).second;
  49 + }
  50 +}
  51 +
  52 +void
  53 +OHArray::remove_last()
  54 +{
  55 + if (this->n_elements == 0) {
  56 + throw std::logic_error("INTERNAL ERROR: attempt to remove"
  57 + " last item from empty OHArray");
  58 + }
  59 + --this->n_elements;
  60 + this->elements.erase(this->n_elements);
  61 +}
  62 +
  63 +void
  64 +OHArray::disconnect()
  65 +{
  66 + for (auto& iter: this->elements) {
  67 + QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
  68 + }
  69 +}
  70 +
  71 +void
  72 +OHArray::setAt(size_t idx, QPDFObjectHandle oh)
  73 +{
  74 + if (idx >= this->n_elements) {
  75 + throw std::logic_error("bounds error setting item in OHArray");
  76 + }
  77 + if (oh.isDirectNull()) {
  78 + this->elements.erase(idx);
  79 + } else {
  80 + this->elements[idx] = oh;
  81 + }
  82 +}
  83 +
  84 +void
  85 +OHArray::erase(size_t idx)
  86 +{
  87 + if (idx >= this->n_elements) {
  88 + throw std::logic_error("bounds error erasing item from OHArray");
  89 + }
  90 + decltype(this->elements) dest;
  91 + for (auto const& iter: this->elements) {
  92 + if (iter.first < idx) {
  93 + dest.insert(iter);
  94 + } else if (iter.first > idx) {
  95 + dest[iter.first - 1] = iter.second;
  96 + }
  97 + }
  98 + this->elements = dest;
  99 + --this->n_elements;
  100 +}
  101 +
  102 +void
  103 +OHArray::insert(size_t idx, QPDFObjectHandle oh)
  104 +{
  105 + if (idx > this->n_elements) {
  106 + throw std::logic_error("bounds error inserting item to OHArray");
  107 + } else if (idx == this->n_elements) {
  108 + // Allow inserting to the last position
  109 + append(oh);
  110 + } else {
  111 + decltype(this->elements) dest;
  112 + for (auto const& iter: this->elements) {
  113 + if (iter.first < idx) {
  114 + dest.insert(iter);
  115 + } else {
  116 + dest[iter.first + 1] = iter.second;
  117 + }
  118 + }
  119 + this->elements = dest;
  120 + this->elements[idx] = oh;
  121 + ++this->n_elements;
  122 + }
  123 +}
  124 +
  125 +OHArray
  126 +OHArray::copy()
  127 +{
  128 + OHArray result;
  129 + result.n_elements = this->n_elements;
  130 + for (auto const& element: this->elements) {
  131 + auto value = element.second;
  132 + result.elements[element.first] =
  133 + value.isIndirect() ? value : value.shallowCopy();
  134 + }
  135 + return result;
  136 +}
  137 +
  138 +OHArray::const_iterator
  139 +OHArray::begin() const
  140 +{
  141 + return this->elements.begin();
  142 +}
  143 +
  144 +OHArray::const_iterator
  145 +OHArray::end() const
  146 +{
  147 + return this->elements.end();
  148 +}
... ...
libqpdf/QPDF_Array.cc
... ... @@ -19,6 +19,13 @@ QPDF_Array::QPDF_Array(std::vector&lt;std::shared_ptr&lt;QPDFObject&gt;&gt;&amp;&amp; v) :
19 19  
20 20 QPDF_Array::QPDF_Array(SparseOHArray const& items) :
21 21 QPDFValue(::ot_array, "array"),
  22 + sp_elements(items)
  23 +{
  24 +}
  25 +
  26 +QPDF_Array::QPDF_Array(OHArray const& items) :
  27 + QPDFValue(::ot_array, "array"),
  28 + sparse(false),
22 29 elements(items)
23 30 {
24 31 }
... ... @@ -42,92 +49,167 @@ QPDF_Array::create(SparseOHArray const&amp; items)
42 49 }
43 50  
44 51 std::shared_ptr<QPDFObject>
  52 +QPDF_Array::create(OHArray const& items)
  53 +{
  54 + return do_create(new QPDF_Array(items));
  55 +}
  56 +
  57 +std::shared_ptr<QPDFObject>
45 58 QPDF_Array::copy(bool shallow)
46 59 {
47   - return create(shallow ? elements : elements.copy());
  60 + if (sparse) {
  61 + return create(shallow ? sp_elements : sp_elements.copy());
  62 + } else {
  63 + return create(shallow ? elements : elements.copy());
  64 + }
48 65 }
49 66  
50 67 void
51 68 QPDF_Array::disconnect()
52 69 {
53   - elements.disconnect();
  70 + if (sparse) {
  71 + sp_elements.disconnect();
  72 + } else {
  73 + elements.disconnect();
  74 + }
54 75 }
55 76  
56 77 std::string
57 78 QPDF_Array::unparse()
58 79 {
59   - std::string result = "[ ";
60   - size_t size = this->elements.size();
61   - for (size_t i = 0; i < size; ++i) {
62   - result += this->elements.at(i).unparse();
63   - result += " ";
  80 + if (sparse) {
  81 + std::string result = "[ ";
  82 + size_t size = sp_elements.size();
  83 + for (size_t i = 0; i < size; ++i) {
  84 + result += sp_elements.at(i).unparse();
  85 + result += " ";
  86 + }
  87 + result += "]";
  88 + return result;
  89 + } else {
  90 + std::string result = "[ ";
  91 + size_t size = elements.size();
  92 + for (size_t i = 0; i < size; ++i) {
  93 + result += elements.at(i).unparse();
  94 + result += " ";
  95 + }
  96 + result += "]";
  97 + return result;
64 98 }
65   - result += "]";
66   - return result;
67 99 }
68 100  
69 101 JSON
70 102 QPDF_Array::getJSON(int json_version)
71 103 {
72   - JSON j = JSON::makeArray();
73   - size_t size = this->elements.size();
74   - for (size_t i = 0; i < size; ++i) {
75   - j.addArrayElement(this->elements.at(i).getJSON(json_version));
  104 + if (sparse) {
  105 + JSON j = JSON::makeArray();
  106 + size_t size = sp_elements.size();
  107 + for (size_t i = 0; i < size; ++i) {
  108 + j.addArrayElement(sp_elements.at(i).getJSON(json_version));
  109 + }
  110 + return j;
  111 + } else {
  112 + JSON j = JSON::makeArray();
  113 + size_t size = elements.size();
  114 + for (size_t i = 0; i < size; ++i) {
  115 + j.addArrayElement(elements.at(i).getJSON(json_version));
  116 + }
  117 + return j;
76 118 }
77   - return j;
78 119 }
79 120  
80 121 int
81 122 QPDF_Array::getNItems() const
82 123 {
83   - // This should really return a size_t, but changing it would break
84   - // a lot of code.
85   - return QIntC::to_int(this->elements.size());
  124 + if (sparse) {
  125 + // This should really return a size_t, but changing it would break
  126 + // a lot of code.
  127 + return QIntC::to_int(sp_elements.size());
  128 + } else {
  129 + return QIntC::to_int(elements.size());
  130 + }
86 131 }
87 132  
88 133 QPDFObjectHandle
89 134 QPDF_Array::getItem(int n) const
90 135 {
91   - if ((n < 0) || (n >= QIntC::to_int(elements.size()))) {
92   - throw std::logic_error(
93   - "INTERNAL ERROR: bounds error accessing QPDF_Array element");
  136 + if (sparse) {
  137 + if ((n < 0) || (n >= QIntC::to_int(sp_elements.size()))) {
  138 + throw std::logic_error(
  139 + "INTERNAL ERROR: bounds error accessing QPDF_Array element");
  140 + }
  141 + return sp_elements.at(QIntC::to_size(n));
  142 + } else {
  143 + if ((n < 0) || (n >= QIntC::to_int(elements.size()))) {
  144 + throw std::logic_error(
  145 + "INTERNAL ERROR: bounds error accessing QPDF_Array element");
  146 + }
  147 + return elements.at(QIntC::to_size(n));
94 148 }
95   - return this->elements.at(QIntC::to_size(n));
96 149 }
97 150  
98 151 void
99 152 QPDF_Array::getAsVector(std::vector<QPDFObjectHandle>& v) const
100 153 {
101   - size_t size = this->elements.size();
102   - for (size_t i = 0; i < size; ++i) {
103   - v.push_back(this->elements.at(i));
  154 + if (sparse) {
  155 + size_t size = sp_elements.size();
  156 + for (size_t i = 0; i < size; ++i) {
  157 + v.push_back(sp_elements.at(i));
  158 + }
  159 + } else {
  160 + size_t size = elements.size();
  161 + for (size_t i = 0; i < size; ++i) {
  162 + v.push_back(elements.at(i));
  163 + }
104 164 }
105 165 }
106 166  
107 167 void
108 168 QPDF_Array::setItem(int n, QPDFObjectHandle const& oh)
109 169 {
110   - this->elements.setAt(QIntC::to_size(n), oh);
  170 + if (sparse) {
  171 + sp_elements.setAt(QIntC::to_size(n), oh);
  172 + } else {
  173 + elements.setAt(QIntC::to_size(n), oh);
  174 + }
111 175 }
112 176  
113 177 void
114 178 QPDF_Array::setFromVector(std::vector<QPDFObjectHandle> const& v)
115 179 {
116   - this->elements = SparseOHArray();
117   - for (auto const& iter: v) {
118   - this->elements.append(iter);
  180 + if (sparse) {
  181 + sp_elements = SparseOHArray();
  182 + for (auto const& iter: v) {
  183 + sp_elements.append(iter);
  184 + }
  185 + } else {
  186 + elements = OHArray();
  187 + for (auto const& iter: v) {
  188 + elements.append(iter);
  189 + }
119 190 }
120 191 }
121 192  
122 193 void
123 194 QPDF_Array::setFromVector(std::vector<std::shared_ptr<QPDFObject>>&& v)
124 195 {
125   - this->elements = SparseOHArray();
126   - for (auto&& item: v) {
127   - if (item) {
128   - this->elements.append(item);
129   - } else {
130   - ++this->elements.n_elements;
  196 + if (sparse) {
  197 + sp_elements = SparseOHArray();
  198 + for (auto&& item: v) {
  199 + if (item) {
  200 + sp_elements.append(item);
  201 + } else {
  202 + ++sp_elements.n_elements;
  203 + }
  204 + }
  205 + } else {
  206 + elements = OHArray();
  207 + for (auto&& item: v) {
  208 + if (item) {
  209 + elements.append(item);
  210 + } else {
  211 + ++elements.n_elements;
  212 + }
131 213 }
132 214 }
133 215 }
... ... @@ -135,22 +217,39 @@ QPDF_Array::setFromVector(std::vector&lt;std::shared_ptr&lt;QPDFObject&gt;&gt;&amp;&amp; v)
135 217 void
136 218 QPDF_Array::insertItem(int at, QPDFObjectHandle const& item)
137 219 {
138   - // As special case, also allow insert beyond the end
139   - if ((at < 0) || (at > QIntC::to_int(this->elements.size()))) {
140   - throw std::logic_error(
141   - "INTERNAL ERROR: bounds error accessing QPDF_Array element");
  220 + if (sparse) {
  221 + // As special case, also allow insert beyond the end
  222 + if ((at < 0) || (at > QIntC::to_int(sp_elements.size()))) {
  223 + throw std::logic_error(
  224 + "INTERNAL ERROR: bounds error accessing QPDF_Array element");
  225 + }
  226 + sp_elements.insert(QIntC::to_size(at), item);
  227 + } else {
  228 + // As special case, also allow insert beyond the end
  229 + if ((at < 0) || (at > QIntC::to_int(elements.size()))) {
  230 + throw std::logic_error(
  231 + "INTERNAL ERROR: bounds error accessing QPDF_Array element");
  232 + }
  233 + elements.insert(QIntC::to_size(at), item);
142 234 }
143   - this->elements.insert(QIntC::to_size(at), item);
144 235 }
145 236  
146 237 void
147 238 QPDF_Array::appendItem(QPDFObjectHandle const& item)
148 239 {
149   - this->elements.append(item);
  240 + if (sparse) {
  241 + sp_elements.append(item);
  242 + } else {
  243 + elements.append(item);
  244 + }
150 245 }
151 246  
152 247 void
153 248 QPDF_Array::eraseItem(int at)
154 249 {
155   - this->elements.erase(QIntC::to_size(at));
  250 + if (sparse) {
  251 + sp_elements.erase(QIntC::to_size(at));
  252 + } else {
  253 + elements.erase(QIntC::to_size(at));
  254 + }
156 255 }
... ...
libqpdf/qpdf/OHArray.hh 0 → 100644
  1 +#ifndef QPDF_OHARRAY_HH
  2 +#define QPDF_OHARRAY_HH
  3 +
  4 +#include <qpdf/QPDFObjectHandle.hh>
  5 +#include <unordered_map>
  6 +
  7 +class QPDF_Array;
  8 +
  9 +class OHArray
  10 +{
  11 + public:
  12 + OHArray();
  13 + size_t size() const;
  14 + void append(QPDFObjectHandle oh);
  15 + void append(std::shared_ptr<QPDFObject>&& obj);
  16 + QPDFObjectHandle at(size_t idx) const;
  17 + void remove_last();
  18 + void setAt(size_t idx, QPDFObjectHandle oh);
  19 + void erase(size_t idx);
  20 + void insert(size_t idx, QPDFObjectHandle oh);
  21 + OHArray copy();
  22 + void disconnect();
  23 +
  24 + typedef std::unordered_map<size_t, QPDFObjectHandle>::const_iterator
  25 + const_iterator;
  26 + const_iterator begin() const;
  27 + const_iterator end() const;
  28 +
  29 + private:
  30 + friend class QPDF_Array;
  31 + std::unordered_map<size_t, QPDFObjectHandle> elements;
  32 + size_t n_elements;
  33 +};
  34 +
  35 +#endif // QPDF_OHARRAY_HH
... ...
libqpdf/qpdf/QPDF_Array.hh
... ... @@ -3,6 +3,7 @@
3 3  
4 4 #include <qpdf/QPDFValue.hh>
5 5  
  6 +#include <qpdf/OHArray.hh>
6 7 #include <qpdf/SparseOHArray.hh>
7 8 #include <list>
8 9 #include <vector>
... ... @@ -16,6 +17,7 @@ class QPDF_Array: public QPDFValue
16 17 static std::shared_ptr<QPDFObject>
17 18 create(std::vector<std::shared_ptr<QPDFObject>>&& items);
18 19 static std::shared_ptr<QPDFObject> create(SparseOHArray const& items);
  20 + static std::shared_ptr<QPDFObject> create(OHArray const& items);
19 21 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false);
20 22 virtual std::string unparse();
21 23 virtual JSON getJSON(int json_version);
... ... @@ -36,7 +38,10 @@ class QPDF_Array: public QPDFValue
36 38 QPDF_Array(std::vector<QPDFObjectHandle> const& items);
37 39 QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items);
38 40 QPDF_Array(SparseOHArray const& items);
39   - SparseOHArray elements;
  41 + QPDF_Array(OHArray const& items);
  42 + bool sparse{false};
  43 + SparseOHArray sp_elements;
  44 + OHArray elements;
40 45 };
41 46  
42 47 #endif // QPDF_ARRAY_HH
... ...