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,6 +1497,7 @@ class QPDFObjectHandle
1497 friend class QPDF_Dictionary; 1497 friend class QPDF_Dictionary;
1498 friend class QPDF_Stream; 1498 friend class QPDF_Stream;
1499 friend class SparseOHArray; 1499 friend class SparseOHArray;
  1500 + friend class OHArray;
1500 1501
1501 private: 1502 private:
1502 static void 1503 static void
libqpdf/CMakeLists.txt
@@ -116,6 +116,7 @@ set(libqpdf_SOURCES @@ -116,6 +116,7 @@ set(libqpdf_SOURCES
116 SecureRandomDataProvider.cc 116 SecureRandomDataProvider.cc
117 SF_FlateLzwDecode.cc 117 SF_FlateLzwDecode.cc
118 SparseOHArray.cc 118 SparseOHArray.cc
  119 + OHArray.cc
119 qpdf-c.cc 120 qpdf-c.cc
120 qpdfjob-c.cc 121 qpdfjob-c.cc
121 qpdflogger-c.cc) 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,6 +19,13 @@ QPDF_Array::QPDF_Array(std::vector&lt;std::shared_ptr&lt;QPDFObject&gt;&gt;&amp;&amp; v) :
19 19
20 QPDF_Array::QPDF_Array(SparseOHArray const& items) : 20 QPDF_Array::QPDF_Array(SparseOHArray const& items) :
21 QPDFValue(::ot_array, "array"), 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 elements(items) 29 elements(items)
23 { 30 {
24 } 31 }
@@ -42,92 +49,167 @@ QPDF_Array::create(SparseOHArray const&amp; items) @@ -42,92 +49,167 @@ QPDF_Array::create(SparseOHArray const&amp; items)
42 } 49 }
43 50
44 std::shared_ptr<QPDFObject> 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 QPDF_Array::copy(bool shallow) 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 void 67 void
51 QPDF_Array::disconnect() 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 std::string 77 std::string
57 QPDF_Array::unparse() 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 JSON 101 JSON
70 QPDF_Array::getJSON(int json_version) 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 int 121 int
81 QPDF_Array::getNItems() const 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 QPDFObjectHandle 133 QPDFObjectHandle
89 QPDF_Array::getItem(int n) const 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 void 151 void
99 QPDF_Array::getAsVector(std::vector<QPDFObjectHandle>& v) const 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 void 167 void
108 QPDF_Array::setItem(int n, QPDFObjectHandle const& oh) 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 void 177 void
114 QPDF_Array::setFromVector(std::vector<QPDFObjectHandle> const& v) 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 void 193 void
123 QPDF_Array::setFromVector(std::vector<std::shared_ptr<QPDFObject>>&& v) 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,22 +217,39 @@ QPDF_Array::setFromVector(std::vector&lt;std::shared_ptr&lt;QPDFObject&gt;&gt;&amp;&amp; v)
135 void 217 void
136 QPDF_Array::insertItem(int at, QPDFObjectHandle const& item) 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 void 237 void
147 QPDF_Array::appendItem(QPDFObjectHandle const& item) 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 void 247 void
153 QPDF_Array::eraseItem(int at) 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,6 +3,7 @@
3 3
4 #include <qpdf/QPDFValue.hh> 4 #include <qpdf/QPDFValue.hh>
5 5
  6 +#include <qpdf/OHArray.hh>
6 #include <qpdf/SparseOHArray.hh> 7 #include <qpdf/SparseOHArray.hh>
7 #include <list> 8 #include <list>
8 #include <vector> 9 #include <vector>
@@ -16,6 +17,7 @@ class QPDF_Array: public QPDFValue @@ -16,6 +17,7 @@ class QPDF_Array: public QPDFValue
16 static std::shared_ptr<QPDFObject> 17 static std::shared_ptr<QPDFObject>
17 create(std::vector<std::shared_ptr<QPDFObject>>&& items); 18 create(std::vector<std::shared_ptr<QPDFObject>>&& items);
18 static std::shared_ptr<QPDFObject> create(SparseOHArray const& items); 19 static std::shared_ptr<QPDFObject> create(SparseOHArray const& items);
  20 + static std::shared_ptr<QPDFObject> create(OHArray const& items);
19 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false); 21 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false);
20 virtual std::string unparse(); 22 virtual std::string unparse();
21 virtual JSON getJSON(int json_version); 23 virtual JSON getJSON(int json_version);
@@ -36,7 +38,10 @@ class QPDF_Array: public QPDFValue @@ -36,7 +38,10 @@ class QPDF_Array: public QPDFValue
36 QPDF_Array(std::vector<QPDFObjectHandle> const& items); 38 QPDF_Array(std::vector<QPDFObjectHandle> const& items);
37 QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items); 39 QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items);
38 QPDF_Array(SparseOHArray const& items); 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 #endif // QPDF_ARRAY_HH 47 #endif // QPDF_ARRAY_HH