You need to sign in before continuing.

Commit 8d7ed7644e4ac27ccdf456ad779540f73612bd6a

Authored by m-holger
1 parent 3b90f899

Refactor QPDFObject to use std::variant instead of std::shared_pointer

include/qpdf/Constants.h
... ... @@ -126,6 +126,7 @@ enum qpdf_object_type_e {
126 126 /* Object types internal to qpdf */
127 127 ot_unresolved,
128 128 ot_destroyed,
  129 + ot_reference,
129 130 };
130 131  
131 132 /* Write Parameters. See QPDFWriter.hh for details. */
... ...
include/qpdf/QPDF.hh
... ... @@ -1087,7 +1087,8 @@ class QPDF
1087 1087 QPDFObjGen og,
1088 1088 std::shared_ptr<QPDFObject> const& object,
1089 1089 qpdf_offset_t end_before_space,
1090   - qpdf_offset_t end_after_space);
  1090 + qpdf_offset_t end_after_space,
  1091 + bool destroy = true);
1091 1092 static QPDFExc damagedPDF(
1092 1093 InputSource& input,
1093 1094 std::string const& object,
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -1254,8 +1254,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle
1254 1254 // Provide access to specific classes for recursive disconnected().
1255 1255 class DisconnectAccess
1256 1256 {
1257   - friend class QPDF_Dictionary;
1258   - friend class QPDF_Stream;
  1257 + friend class QPDFObject;
1259 1258  
1260 1259 private:
1261 1260 static void
... ...
include/qpdf/QPDFObjectHandle_future.hh deleted
libqpdf/CMakeLists.txt
... ... @@ -86,23 +86,12 @@ set(libqpdf_SOURCES
86 86 QPDFSystemError.cc
87 87 QPDFTokenizer.cc
88 88 QPDFUsage.cc
89   - QPDFValue.cc
90 89 QPDFWriter.cc
91 90 QPDFXRefEntry.cc
92 91 QPDF_Array.cc
93   - QPDF_Bool.cc
94   - QPDF_Destroyed.cc
95 92 QPDF_Dictionary.cc
96   - QPDF_InlineImage.cc
97   - QPDF_Integer.cc
98   - QPDF_Name.cc
99   - QPDF_Null.cc
100   - QPDF_Operator.cc
101   - QPDF_Real.cc
102   - QPDF_Reserved.cc
103 93 QPDF_Stream.cc
104 94 QPDF_String.cc
105   - QPDF_Unresolved.cc
106 95 QPDF_encryption.cc
107 96 QPDF_json.cc
108 97 QPDF_linearization.cc
... ...
libqpdf/QPDF.cc
... ... @@ -20,11 +20,6 @@
20 20 #include <qpdf/QPDFObjectHandle_private.hh>
21 21 #include <qpdf/QPDFObject_private.hh>
22 22 #include <qpdf/QPDFParser.hh>
23   -#include <qpdf/QPDF_Dictionary.hh>
24   -#include <qpdf/QPDF_Null.hh>
25   -#include <qpdf/QPDF_Reserved.hh>
26   -#include <qpdf/QPDF_Stream.hh>
27   -#include <qpdf/QPDF_Unresolved.hh>
28 23 #include <qpdf/QTC.hh>
29 24 #include <qpdf/QUtil.hh>
30 25  
... ... @@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle&amp; object, QPDFObjGen og, qpdf_offset_t offset)
1565 1560 throw;
1566 1561 }
1567 1562 }
1568   - object = {QPDF_Stream::create(this, og, object, stream_offset, length)};
  1563 + object = QPDFObjectHandle(qpdf::Stream(*this, og, object, stream_offset, length));
1569 1564 }
1570 1565  
1571 1566 void
... ... @@ -1884,7 +1879,7 @@ QPDF::resolve(QPDFObjGen og)
1884 1879 // has to be resolved during object parsing, such as stream length.
1885 1880 QTC::TC("qpdf", "QPDF recursion loop in resolve");
1886 1881 warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
1887   - updateCache(og, QPDF_Null::create(), -1, -1);
  1882 + updateCache(og, QPDFObject::create<QPDF_Null>(), -1, -1);
1888 1883 return m->obj_cache[og].object.get();
1889 1884 }
1890 1885 ResolveRecorder rr(this, og);
... ... @@ -1921,7 +1916,7 @@ QPDF::resolve(QPDFObjGen og)
1921 1916 if (isUnresolved(og)) {
1922 1917 // PDF spec says unknown objects resolve to the null object.
1923 1918 QTC::TC("qpdf", "QPDF resolve failure to null");
1924   - updateCache(og, QPDF_Null::create(), -1, -1);
  1919 + updateCache(og, QPDFObject::create<QPDF_Null>(), -1, -1);
1925 1920 }
1926 1921  
1927 1922 auto result(m->obj_cache[og].object);
... ... @@ -2034,12 +2029,13 @@ QPDF::updateCache(
2034 2029 QPDFObjGen og,
2035 2030 std::shared_ptr<QPDFObject> const& object,
2036 2031 qpdf_offset_t end_before_space,
2037   - qpdf_offset_t end_after_space)
  2032 + qpdf_offset_t end_after_space,
  2033 + bool destroy)
2038 2034 {
2039 2035 object->setObjGen(this, og);
2040 2036 if (isCached(og)) {
2041 2037 auto& cache = m->obj_cache[og];
2042   - cache.object->assign(object);
  2038 + object->move_to(cache.object, destroy);
2043 2039 cache.end_before_space = end_before_space;
2044 2040 cache.end_after_space = end_after_space;
2045 2041 } else {
... ... @@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh)
2089 2085 QPDFObjectHandle
2090 2086 QPDF::newReserved()
2091 2087 {
2092   - return makeIndirectFromQPDFObject(QPDF_Reserved::create());
  2088 + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Reserved>());
2093 2089 }
2094 2090  
2095 2091 QPDFObjectHandle
2096 2092 QPDF::newIndirectNull()
2097 2093 {
2098   - return makeIndirectFromQPDFObject(QPDF_Null::create());
  2094 + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Null>());
2099 2095 }
2100 2096  
2101 2097 QPDFObjectHandle
2102 2098 QPDF::newStream()
2103 2099 {
2104   - return makeIndirectFromQPDFObject(
2105   - QPDF_Stream::create(this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0));
  2100 + return makeIndirectObject(
  2101 + qpdf::Stream(*this, nextObjGen(), QPDFObjectHandle::newDictionary(), 0, 0));
2106 2102 }
2107 2103  
2108 2104 QPDFObjectHandle
... ... @@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
2130 2126 return iter->second.object;
2131 2127 }
2132 2128 if (m->xref_table.count(og) || !m->parsed) {
2133   - return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object;
  2129 + return m->obj_cache.insert({og, QPDFObject::create<QPDF_Unresolved>(this, og)})
  2130 + .first->second.object;
2134 2131 }
2135 2132 if (parse_pdf) {
2136   - return QPDF_Null::create();
  2133 + return QPDFObject::create<QPDF_Null>();
2137 2134 }
2138   - return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object;
  2135 + return m->obj_cache.insert({og, QPDFObject::create<QPDF_Null>(this, og)}).first->second.object;
2139 2136 }
2140 2137  
2141 2138 std::shared_ptr<QPDFObject>
... ... @@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen)
2145 2142 auto [it, inserted] = m->obj_cache.try_emplace(og);
2146 2143 auto& obj = it->second.object;
2147 2144 if (inserted) {
2148   - obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og)
2149   - : QPDF_Unresolved::create(this, og);
  2145 + obj = (m->parsed && !m->xref_table.count(og))
  2146 + ? QPDFObject::create<QPDF_Null>(this, og)
  2147 + : QPDFObject::create<QPDF_Unresolved>(this, og);
2150 2148 }
2151 2149 return obj;
2152 2150 }
... ... @@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og)
2157 2155 if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
2158 2156 return {it->second.object};
2159 2157 } else if (m->parsed && !m->xref_table.count(og)) {
2160   - return QPDF_Null::create();
  2158 + return QPDFObject::create<QPDF_Null>();
2161 2159 } else {
2162   - auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1);
  2160 + auto result =
  2161 + m->obj_cache.try_emplace(og, QPDFObject::create<QPDF_Unresolved>(this, og), -1, -1);
2163 2162 return {result.first->second.object};
2164 2163 }
2165 2164 }
... ... @@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh)
2195 2194 QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
2196 2195 throw std::logic_error("QPDF::replaceObject called with indirect object handle");
2197 2196 }
2198   - updateCache(og, oh.getObj(), -1, -1);
  2197 + updateCache(og, oh.getObj(), -1, -1, false);
2199 2198 }
2200 2199  
2201 2200 void
... ... @@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og)
2204 2203 m->xref_table.erase(og);
2205 2204 if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) {
2206 2205 // Take care of any object handles that may be floating around.
2207   - cached->second.object->assign(QPDF_Null::create());
  2206 + cached->second.object->assign_null();
2208 2207 cached->second.object->setObjGen(nullptr, QPDFObjGen());
2209 2208 m->obj_cache.erase(cached);
2210 2209 }
... ...
libqpdf/QPDFObject.cc
1 1 #include <qpdf/QPDFObject_private.hh>
2 2  
3   -#include <qpdf/QPDF.hh>
4   -#include <qpdf/QPDF_Destroyed.hh>
5   -
6   -void
7   -QPDFObject::destroy()
  3 +std::string
  4 +QPDFObject::getDescription()
8 5 {
9   - value = QPDF_Destroyed::getInstance();
  6 + if (object_description) {
  7 + switch (object_description->index()) {
  8 + case 0:
  9 + {
  10 + // Simple template string
  11 + auto description = std::get<0>(*object_description);
  12 +
  13 + if (auto pos = description.find("$OG"); pos != std::string::npos) {
  14 + description.replace(pos, 3, og.unparse(' '));
  15 + }
  16 + if (auto pos = description.find("$PO"); pos != std::string::npos) {
  17 + qpdf_offset_t shift = (getTypeCode() == ::ot_dictionary) ? 2
  18 + : (getTypeCode() == ::ot_array) ? 1
  19 + : 0;
  20 +
  21 + description.replace(pos, 3, std::to_string(parsed_offset + shift));
  22 + }
  23 + return description;
  24 + }
  25 + case 1:
  26 + {
  27 + // QPDF::JSONReactor generated description
  28 + auto j_descr = std::get<1>(*object_description);
  29 + return (
  30 + *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) +
  31 + " at offset " + std::to_string(parsed_offset));
  32 + }
  33 + case 2:
  34 + {
  35 + // Child object description
  36 + auto j_descr = std::get<2>(*object_description);
  37 + std::string result;
  38 + if (auto p = j_descr.parent.lock()) {
  39 + result = p->getDescription();
  40 + }
  41 + result += j_descr.static_descr;
  42 + if (auto pos = result.find("$VD"); pos != std::string::npos) {
  43 + result.replace(pos, 3, j_descr.var_descr);
  44 + }
  45 + return result;
  46 + }
  47 + }
  48 + } else if (og.isIndirect()) {
  49 + return "object " + og.unparse(' ');
  50 + }
  51 + return {};
10 52 }
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -11,19 +11,6 @@
11 11 #include <qpdf/QPDFObject_private.hh>
12 12 #include <qpdf/QPDFPageObjectHelper.hh>
13 13 #include <qpdf/QPDFParser.hh>
14   -#include <qpdf/QPDF_Array.hh>
15   -#include <qpdf/QPDF_Bool.hh>
16   -#include <qpdf/QPDF_Dictionary.hh>
17   -#include <qpdf/QPDF_InlineImage.hh>
18   -#include <qpdf/QPDF_Integer.hh>
19   -#include <qpdf/QPDF_Name.hh>
20   -#include <qpdf/QPDF_Null.hh>
21   -#include <qpdf/QPDF_Operator.hh>
22   -#include <qpdf/QPDF_Real.hh>
23   -#include <qpdf/QPDF_Reserved.hh>
24   -#include <qpdf/QPDF_Stream.hh>
25   -#include <qpdf/QPDF_String.hh>
26   -#include <qpdf/QPDF_Unresolved.hh>
27 14  
28 15 #include <qpdf/QIntC.hh>
29 16 #include <qpdf/QTC.hh>
... ... @@ -228,6 +215,443 @@ LastChar::getLastChar()
228 215 return this->last_char;
229 216 }
230 217  
  218 +std::pair<bool, bool>
  219 +Name::analyzeJSONEncoding(const std::string& name)
  220 +{
  221 + int tail = 0; // Number of continuation characters expected.
  222 + bool tail2 = false; // Potential overlong 3 octet utf-8.
  223 + bool tail3 = false; // potential overlong 4 octet
  224 + bool needs_escaping = false;
  225 + for (auto const& it: name) {
  226 + auto c = static_cast<unsigned char>(it);
  227 + if (tail) {
  228 + if ((c & 0xc0) != 0x80) {
  229 + return {false, false};
  230 + }
  231 + if (tail2) {
  232 + if ((c & 0xe0) == 0x80) {
  233 + return {false, false};
  234 + }
  235 + tail2 = false;
  236 + } else if (tail3) {
  237 + if ((c & 0xf0) == 0x80) {
  238 + return {false, false};
  239 + }
  240 + tail3 = false;
  241 + }
  242 + tail--;
  243 + } else if (c < 0x80) {
  244 + if (!needs_escaping) {
  245 + needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33);
  246 + }
  247 + } else if ((c & 0xe0) == 0xc0) {
  248 + if ((c & 0xfe) == 0xc0) {
  249 + return {false, false};
  250 + }
  251 + tail = 1;
  252 + } else if ((c & 0xf0) == 0xe0) {
  253 + tail2 = (c == 0xe0);
  254 + tail = 2;
  255 + } else if ((c & 0xf8) == 0xf0) {
  256 + tail3 = (c == 0xf0);
  257 + tail = 3;
  258 + } else {
  259 + return {false, false};
  260 + }
  261 + }
  262 + return {tail == 0, !needs_escaping};
  263 +}
  264 +
  265 +std::string
  266 +Name::normalize(std::string const& name)
  267 +{
  268 + if (name.empty()) {
  269 + return name;
  270 + }
  271 + std::string result;
  272 + result += name.at(0);
  273 + for (size_t i = 1; i < name.length(); ++i) {
  274 + char ch = name.at(i);
  275 + // Don't use locale/ctype here; follow PDF spec guidelines.
  276 + if (ch == '\0') {
  277 + // QPDFTokenizer embeds a null character to encode an invalid #.
  278 + result += "#";
  279 + } else if (
  280 + ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
  281 + ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) {
  282 + result += QUtil::hex_encode_char(ch);
  283 + } else {
  284 + result += ch;
  285 + }
  286 + }
  287 + return result;
  288 +}
  289 +
  290 +std::shared_ptr<QPDFObject>
  291 +QPDFObject::copy(bool shallow)
  292 +{
  293 + switch (getResolvedTypeCode()) {
  294 + case ::ot_uninitialized:
  295 + throw std::logic_error("QPDFObjectHandle: attempting to copy an uninitialized object");
  296 + return {}; // does not return
  297 + case ::ot_reserved:
  298 + return create<QPDF_Reserved>();
  299 + case ::ot_null:
  300 + return create<QPDF_Null>();
  301 + case ::ot_boolean:
  302 + return create<QPDF_Bool>(std::get<QPDF_Bool>(value).val);
  303 + case ::ot_integer:
  304 + return create<QPDF_Integer>(std::get<QPDF_Integer>(value).val);
  305 + case ::ot_real:
  306 + return create<QPDF_Real>(std::get<QPDF_Real>(value).val);
  307 + case ::ot_string:
  308 + return create<QPDF_String>(std::get<QPDF_String>(value).val);
  309 + case ::ot_name:
  310 + return create<QPDF_Name>(std::get<QPDF_Name>(value).name);
  311 + case ::ot_array:
  312 + {
  313 + auto const& a = std::get<QPDF_Array>(value);
  314 + if (shallow) {
  315 + return QPDFObject::create<QPDF_Array>(a);
  316 + } else {
  317 + QTC::TC("qpdf", "QPDF_Array copy", a.sp ? 0 : 1);
  318 + if (a.sp) {
  319 + QPDF_Array result;
  320 + result.sp = std::make_unique<QPDF_Array::Sparse>();
  321 + result.sp->size = a.sp->size;
  322 + for (auto const& element: a.sp->elements) {
  323 + auto const& obj = element.second;
  324 + result.sp->elements[element.first] =
  325 + obj->getObjGen().isIndirect() ? obj : obj->copy();
  326 + }
  327 + return QPDFObject::create<QPDF_Array>(std::move(result));
  328 + } else {
  329 + std::vector<std::shared_ptr<QPDFObject>> result;
  330 + result.reserve(a.elements.size());
  331 + for (auto const& element: a.elements) {
  332 + result.push_back(
  333 + element
  334 + ? (element->getObjGen().isIndirect() ? element : element->copy())
  335 + : element);
  336 + }
  337 + return QPDFObject::create<QPDF_Array>(std::move(result), false);
  338 + }
  339 + }
  340 + }
  341 + case ::ot_dictionary:
  342 + {
  343 + auto const& d = std::get<QPDF_Dictionary>(value);
  344 + if (shallow) {
  345 + return QPDFObject::create<QPDF_Dictionary>(d.items);
  346 + } else {
  347 + std::map<std::string, QPDFObjectHandle> new_items;
  348 + for (auto const& [key, val]: d.items) {
  349 + new_items[key] = val.isIndirect() ? val : val.getObj()->copy();
  350 + }
  351 + return QPDFObject::create<QPDF_Dictionary>(new_items);
  352 + }
  353 + }
  354 + case ::ot_stream:
  355 + QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream");
  356 + throw std::runtime_error("stream objects cannot be cloned");
  357 + return {}; // does not return
  358 + case ::ot_operator:
  359 + return create<QPDF_Operator>(std::get<QPDF_Operator>(value).val);
  360 + case ::ot_inlineimage:
  361 + return create<QPDF_InlineImage>(std::get<QPDF_InlineImage>(value).val);
  362 + case ::ot_unresolved:
  363 + throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object");
  364 + return {}; // does not return
  365 + case ::ot_destroyed:
  366 + throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF");
  367 + return {}; // does not return
  368 + case ::ot_reference:
  369 + return qpdf->getObject(og).getObj();
  370 + }
  371 + return {}; // does not return
  372 +}
  373 +
  374 +std::string
  375 +QPDFObject::unparse()
  376 +{
  377 + switch (getResolvedTypeCode()) {
  378 + case ::ot_uninitialized:
  379 + throw std::logic_error("QPDFObjectHandle: attempting to unparse an uninitialized object");
  380 + return ""; // does not return
  381 + case ::ot_reserved:
  382 + throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object");
  383 + return ""; // does not return
  384 + case ::ot_null:
  385 + return "null";
  386 + case ::ot_boolean:
  387 + return std::get<QPDF_Bool>(value).val ? "true" : "false";
  388 + case ::ot_integer:
  389 + return std::to_string(std::get<QPDF_Integer>(value).val);
  390 + case ::ot_real:
  391 + return std::get<QPDF_Real>(value).val;
  392 + case ::ot_string:
  393 + return std::get<QPDF_String>(value).unparse(false);
  394 + case ::ot_name:
  395 + return Name::normalize(std::get<QPDF_Name>(value).name);
  396 + case ::ot_array:
  397 + {
  398 + auto const& a = std::get<QPDF_Array>(value);
  399 + std::string result = "[ ";
  400 + if (a.sp) {
  401 + int next = 0;
  402 + for (auto& item: a.sp->elements) {
  403 + int key = item.first;
  404 + for (int j = next; j < key; ++j) {
  405 + result += "null ";
  406 + }
  407 + auto item_og = item.second->resolved_object()->getObjGen();
  408 + result += item_og.isIndirect() ? item_og.unparse(' ') + " R "
  409 + : item.second->unparse() + " ";
  410 + next = ++key;
  411 + }
  412 + for (int j = next; j < a.sp->size; ++j) {
  413 + result += "null ";
  414 + }
  415 + } else {
  416 + for (auto const& item: a.elements) {
  417 + auto item_og = item->resolved_object()->getObjGen();
  418 + result +=
  419 + item_og.isIndirect() ? item_og.unparse(' ') + " R " : item->unparse() + " ";
  420 + }
  421 + }
  422 + result += "]";
  423 + return result;
  424 + }
  425 + case ::ot_dictionary:
  426 + {
  427 + auto const& items = std::get<QPDF_Dictionary>(value).items;
  428 + std::string result = "<< ";
  429 + for (auto& iter: items) {
  430 + if (!iter.second.isNull()) {
  431 + result += Name::normalize(iter.first) + " " + iter.second.unparse() + " ";
  432 + }
  433 + }
  434 + result += ">>";
  435 + return result;
  436 + }
  437 + case ::ot_stream:
  438 + return og.unparse(' ') + " R";
  439 + case ::ot_operator:
  440 + return std::get<QPDF_Operator>(value).val;
  441 + case ::ot_inlineimage:
  442 + return std::get<QPDF_InlineImage>(value).val;
  443 + case ::ot_unresolved:
  444 + throw std::logic_error("QPDFObjectHandle: attempting to unparse a unresolved object");
  445 + return ""; // does not return
  446 + case ::ot_destroyed:
  447 + throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF");
  448 + return ""; // does not return
  449 + case ::ot_reference:
  450 + return og.unparse(' ') + " R";
  451 + }
  452 + return {}; // does not return
  453 +}
  454 +
  455 +void
  456 +QPDFObject::write_json(int json_version, JSON::Writer& p)
  457 +{
  458 + switch (getResolvedTypeCode()) {
  459 + case ::ot_uninitialized:
  460 + throw std::logic_error(
  461 + "QPDFObjectHandle: attempting to get JSON from a uninitialized object");
  462 + break; // unreachable
  463 + case ::ot_null:
  464 + case ::ot_operator:
  465 + case ::ot_inlineimage:
  466 + p << "null";
  467 + break;
  468 + case ::ot_boolean:
  469 + p << std::get<QPDF_Bool>(value).val;
  470 + break;
  471 + case ::ot_integer:
  472 + p << std::to_string(std::get<QPDF_Integer>(value).val);
  473 + break;
  474 + case ::ot_real:
  475 + {
  476 + auto const& val = std::get<QPDF_Real>(value).val;
  477 + if (val.length() == 0) {
  478 + // Can't really happen...
  479 + p << "0";
  480 + } else if (val.at(0) == '.') {
  481 + p << "0" << val;
  482 + } else if (val.length() >= 2 && val.at(0) == '-' && val.at(1) == '.') {
  483 + p << "-0." << val.substr(2);
  484 + } else {
  485 + p << val;
  486 + }
  487 + if (val.back() == '.') {
  488 + p << "0";
  489 + }
  490 + }
  491 + break;
  492 + case ::ot_string:
  493 + std::get<QPDF_String>(value).writeJSON(json_version, p);
  494 + break;
  495 + case ::ot_name:
  496 + {
  497 + auto const& n = std::get<QPDF_Name>(value);
  498 + // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When
  499 + // updating this method make sure QPDF_Dictionary is also update.
  500 + if (json_version == 1) {
  501 + p << "\"" << JSON::Writer::encode_string(Name::normalize(n.name)) << "\"";
  502 + } else {
  503 + if (auto res = Name::analyzeJSONEncoding(n.name); res.first) {
  504 + if (res.second) {
  505 + p << "\"" << n.name << "\"";
  506 + } else {
  507 + p << "\"" << JSON::Writer::encode_string(n.name) << "\"";
  508 + }
  509 + } else {
  510 + p << "\"n:" << JSON::Writer::encode_string(Name::normalize(n.name)) << "\"";
  511 + }
  512 + }
  513 + }
  514 + break;
  515 + case ::ot_array:
  516 + {
  517 + auto const& a = std::get<QPDF_Array>(value);
  518 + p.writeStart('[');
  519 + if (a.sp) {
  520 + int next = 0;
  521 + for (auto& item: a.sp->elements) {
  522 + int key = item.first;
  523 + for (int j = next; j < key; ++j) {
  524 + p.writeNext() << "null";
  525 + }
  526 + p.writeNext();
  527 + auto item_og = item.second->getObjGen();
  528 + if (item_og.isIndirect()) {
  529 + p << "\"" << item_og.unparse(' ') << " R\"";
  530 + } else {
  531 + item.second->write_json(json_version, p);
  532 + }
  533 + next = ++key;
  534 + }
  535 + for (int j = next; j < a.sp->size; ++j) {
  536 + p.writeNext() << "null";
  537 + }
  538 + } else {
  539 + for (auto const& item: a.elements) {
  540 + p.writeNext();
  541 + auto item_og = item->getObjGen();
  542 + if (item_og.isIndirect()) {
  543 + p << "\"" << item_og.unparse(' ') << " R\"";
  544 + } else {
  545 + item->write_json(json_version, p);
  546 + }
  547 + }
  548 + }
  549 + p.writeEnd(']');
  550 + }
  551 + break;
  552 + case ::ot_dictionary:
  553 + {
  554 + auto const& d = std::get<QPDF_Dictionary>(value);
  555 + p.writeStart('{');
  556 + for (auto& iter: d.items) {
  557 + if (!iter.second.isNull()) {
  558 + p.writeNext();
  559 + if (json_version == 1) {
  560 + p << "\"" << JSON::Writer::encode_string(Name::normalize(iter.first))
  561 + << "\": ";
  562 + } else if (auto res = Name::analyzeJSONEncoding(iter.first); res.first) {
  563 + if (res.second) {
  564 + p << "\"" << iter.first << "\": ";
  565 + } else {
  566 + p << "\"" << JSON::Writer::encode_string(iter.first) << "\": ";
  567 + }
  568 + } else {
  569 + p << "\"n:" << JSON::Writer::encode_string(Name::normalize(iter.first))
  570 + << "\": ";
  571 + }
  572 + iter.second.writeJSON(json_version, p);
  573 + }
  574 + }
  575 + p.writeEnd('}');
  576 + }
  577 + break;
  578 + case ::ot_stream:
  579 + std::get<QPDF_Stream>(value).m->stream_dict.writeJSON(json_version, p);
  580 + break;
  581 + case ::ot_reference:
  582 + p << "\"" << getObjGen().unparse(' ') << " R\"";
  583 + break;
  584 + default:
  585 + throw std::logic_error("attempted to write an unsuitable object as JSON");
  586 + }
  587 +}
  588 +
  589 +void
  590 +QPDFObject::disconnect()
  591 +{
  592 + // Disconnect an object from its owning QPDF. This is called by QPDF's destructor.
  593 +
  594 + switch (getTypeCode()) {
  595 + case ::ot_array:
  596 + {
  597 + auto& a = std::get<QPDF_Array>(value);
  598 + if (a.sp) {
  599 + for (auto& item: a.sp->elements) {
  600 + auto& obj = item.second;
  601 + if (!obj->getObjGen().isIndirect()) {
  602 + obj->disconnect();
  603 + }
  604 + }
  605 + } else {
  606 + for (auto& obj: a.elements) {
  607 + if (!obj->getObjGen().isIndirect()) {
  608 + obj->disconnect();
  609 + }
  610 + }
  611 + }
  612 + }
  613 + break;
  614 + case ::ot_dictionary:
  615 + for (auto& iter: std::get<QPDF_Dictionary>(value).items) {
  616 + QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
  617 + }
  618 + break;
  619 + case ::ot_stream:
  620 + {
  621 + auto& s = std::get<QPDF_Stream>(value);
  622 + s.m->stream_provider = nullptr;
  623 + QPDFObjectHandle::DisconnectAccess::disconnect(s.m->stream_dict);
  624 + }
  625 + break;
  626 + default:
  627 + break;
  628 + }
  629 + qpdf = nullptr;
  630 + og = QPDFObjGen();
  631 +}
  632 +std::string
  633 +QPDFObject::getStringValue() const
  634 +{
  635 + switch (getResolvedTypeCode()) {
  636 + case ::ot_real:
  637 + return std::get<QPDF_Real>(value).val;
  638 + case ::ot_string:
  639 + return std::get<QPDF_String>(value).val;
  640 + case ::ot_name:
  641 + return std::get<QPDF_Name>(value).name;
  642 + case ::ot_operator:
  643 + return std::get<QPDF_Operator>(value).val;
  644 + case ::ot_inlineimage:
  645 + return std::get<QPDF_InlineImage>(value).val;
  646 + case ::ot_reference:
  647 + return std::get<QPDF_Reference>(value).obj->getStringValue();
  648 + default:
  649 + throw std::logic_error("Internal error in QPDFObject::getStringValue");
  650 + return ""; // does not return
  651 + }
  652 + return {}; // does not return
  653 +}
  654 +
231 655 bool
232 656 QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const
233 657 {
... ... @@ -253,7 +677,7 @@ QPDFObjectHandle::getTypeCode() const
253 677 char const*
254 678 QPDFObjectHandle::getTypeName() const
255 679 {
256   - static constexpr std::array<char const*, 15> tn{
  680 + static constexpr std::array<char const*, 16> tn{
257 681 "uninitialized",
258 682 "reserved",
259 683 "null",
... ... @@ -268,84 +692,23 @@ QPDFObjectHandle::getTypeName() const
268 692 "operator",
269 693 "inline-image",
270 694 "unresolved",
271   - "destroyed"};
  695 + "destroyed",
  696 + "reference"};
272 697 return obj ? tn[getTypeCode()] : "uninitialized";
273 698 }
274 699  
275   -QPDF_Array*
276   -QPDFObjectHandle::asArray() const
277   -{
278   - return obj ? obj->as<QPDF_Array>() : nullptr;
279   -}
280   -
281 700 QPDF_Bool*
282 701 QPDFObjectHandle::asBool() const
283 702 {
284 703 return obj ? obj->as<QPDF_Bool>() : nullptr;
285 704 }
286 705  
287   -QPDF_Dictionary*
288   -QPDFObjectHandle::asDictionary() const
289   -{
290   - return obj ? obj->as<QPDF_Dictionary>() : nullptr;
291   -}
292   -
293   -QPDF_InlineImage*
294   -QPDFObjectHandle::asInlineImage() const
295   -{
296   - return obj ? obj->as<QPDF_InlineImage>() : nullptr;
297   -}
298   -
299 706 QPDF_Integer*
300 707 QPDFObjectHandle::asInteger() const
301 708 {
302 709 return obj ? obj->as<QPDF_Integer>() : nullptr;
303 710 }
304 711  
305   -QPDF_Name*
306   -QPDFObjectHandle::asName() const
307   -{
308   - return obj ? obj->as<QPDF_Name>() : nullptr;
309   -}
310   -
311   -QPDF_Null*
312   -QPDFObjectHandle::asNull() const
313   -{
314   - return obj ? obj->as<QPDF_Null>() : nullptr;
315   -}
316   -
317   -QPDF_Operator*
318   -QPDFObjectHandle::asOperator() const
319   -{
320   - return obj ? obj->as<QPDF_Operator>() : nullptr;
321   -}
322   -
323   -QPDF_Real*
324   -QPDFObjectHandle::asReal() const
325   -{
326   - return obj ? obj->as<QPDF_Real>() : nullptr;
327   -}
328   -
329   -QPDF_Reserved*
330   -QPDFObjectHandle::asReserved() const
331   -{
332   - return obj ? obj->as<QPDF_Reserved>() : nullptr;
333   -}
334   -
335   -QPDF_Stream*
336   -QPDFObjectHandle::asStream() const
337   -{
338   - return obj ? obj->as<QPDF_Stream>() : nullptr;
339   -}
340   -
341   -QPDF_Stream*
342   -QPDFObjectHandle::asStreamWithAssert() const
343   -{
344   - auto stream = asStream();
345   - assertType("stream", stream);
346   - return stream;
347   -}
348   -
349 712 QPDF_String*
350 713 QPDFObjectHandle::asString() const
351 714 {
... ... @@ -500,7 +863,7 @@ QPDFObjectHandle::getBoolValue() const
500 863 {
501 864 auto boolean = asBool();
502 865 if (boolean) {
503   - return boolean->getVal();
  866 + return boolean->val;
504 867 } else {
505 868 typeWarning("boolean", "returning false");
506 869 QTC::TC("qpdf", "QPDFObjectHandle boolean returning false");
... ... @@ -515,7 +878,7 @@ QPDFObjectHandle::getValueAsBool(bool&amp; value) const
515 878 if (boolean == nullptr) {
516 879 return false;
517 880 }
518   - value = boolean->getVal();
  881 + value = boolean->val;
519 882 return true;
520 883 }
521 884  
... ... @@ -526,7 +889,7 @@ QPDFObjectHandle::getIntValue() const
526 889 {
527 890 auto integer = asInteger();
528 891 if (integer) {
529   - return integer->getVal();
  892 + return integer->val;
530 893 } else {
531 894 typeWarning("integer", "returning 0");
532 895 QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
... ... @@ -541,7 +904,7 @@ QPDFObjectHandle::getValueAsInt(long long&amp; value) const
541 904 if (integer == nullptr) {
542 905 return false;
543 906 }
544   - value = integer->getVal();
  907 + value = integer->val;
545 908 return true;
546 909 }
547 910  
... ... @@ -1155,7 +1518,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer&amp; p, bool dereference_
1155 1518 } else if (!obj) {
1156 1519 throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
1157 1520 } else {
1158   - obj->writeJSON(json_version, p);
  1521 + obj->write_json(json_version, p);
1159 1522 }
1160 1523 }
1161 1524  
... ... @@ -1392,43 +1755,43 @@ QPDFObjectHandle::getParsedOffset() const
1392 1755 QPDFObjectHandle
1393 1756 QPDFObjectHandle::newBool(bool value)
1394 1757 {
1395   - return {QPDF_Bool::create(value)};
  1758 + return {QPDFObject::create<QPDF_Bool>(value)};
1396 1759 }
1397 1760  
1398 1761 QPDFObjectHandle
1399 1762 QPDFObjectHandle::newNull()
1400 1763 {
1401   - return {QPDF_Null::create()};
  1764 + return {QPDFObject::create<QPDF_Null>()};
1402 1765 }
1403 1766  
1404 1767 QPDFObjectHandle
1405 1768 QPDFObjectHandle::newInteger(long long value)
1406 1769 {
1407   - return {QPDF_Integer::create(value)};
  1770 + return {QPDFObject::create<QPDF_Integer>(value)};
1408 1771 }
1409 1772  
1410 1773 QPDFObjectHandle
1411 1774 QPDFObjectHandle::newReal(std::string const& value)
1412 1775 {
1413   - return {QPDF_Real::create(value)};
  1776 + return {QPDFObject::create<QPDF_Real>(value)};
1414 1777 }
1415 1778  
1416 1779 QPDFObjectHandle
1417 1780 QPDFObjectHandle::newReal(double value, int decimal_places, bool trim_trailing_zeroes)
1418 1781 {
1419   - return {QPDF_Real::create(value, decimal_places, trim_trailing_zeroes)};
  1782 + return {QPDFObject::create<QPDF_Real>(value, decimal_places, trim_trailing_zeroes)};
1420 1783 }
1421 1784  
1422 1785 QPDFObjectHandle
1423 1786 QPDFObjectHandle::newName(std::string const& name)
1424 1787 {
1425   - return {QPDF_Name::create(name)};
  1788 + return {QPDFObject::create<QPDF_Name>(name)};
1426 1789 }
1427 1790  
1428 1791 QPDFObjectHandle
1429 1792 QPDFObjectHandle::newString(std::string const& str)
1430 1793 {
1431   - return {QPDF_String::create(str)};
  1794 + return {QPDFObject::create<QPDF_String>(str)};
1432 1795 }
1433 1796  
1434 1797 QPDFObjectHandle
... ... @@ -1440,13 +1803,13 @@ QPDFObjectHandle::newUnicodeString(std::string const&amp; utf8_str)
1440 1803 QPDFObjectHandle
1441 1804 QPDFObjectHandle::newOperator(std::string const& value)
1442 1805 {
1443   - return {QPDF_Operator::create(value)};
  1806 + return {QPDFObject::create<QPDF_Operator>(value)};
1444 1807 }
1445 1808  
1446 1809 QPDFObjectHandle
1447 1810 QPDFObjectHandle::newInlineImage(std::string const& value)
1448 1811 {
1449   - return {QPDF_InlineImage::create(value)};
  1812 + return {QPDFObject::create<QPDF_InlineImage>(value)};
1450 1813 }
1451 1814  
1452 1815 QPDFObjectHandle
... ... @@ -1458,7 +1821,7 @@ QPDFObjectHandle::newArray()
1458 1821 QPDFObjectHandle
1459 1822 QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items)
1460 1823 {
1461   - return {QPDF_Array::create(items)};
  1824 + return {QPDFObject::create<QPDF_Array>(items)};
1462 1825 }
1463 1826  
1464 1827 QPDFObjectHandle
... ... @@ -1518,7 +1881,7 @@ QPDFObjectHandle::newDictionary()
1518 1881 QPDFObjectHandle
1519 1882 QPDFObjectHandle::newDictionary(std::map<std::string, QPDFObjectHandle> const& items)
1520 1883 {
1521   - return {QPDF_Dictionary::create(items)};
  1884 + return {QPDFObject::create<QPDF_Dictionary>(items)};
1522 1885 }
1523 1886  
1524 1887 QPDFObjectHandle
... ... @@ -1564,7 +1927,7 @@ void
1564 1927 QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description)
1565 1928 {
1566 1929 if (obj) {
1567   - auto descr = std::make_shared<QPDFValue::Description>(object_description);
  1930 + auto descr = std::make_shared<QPDFObject::Description>(object_description);
1568 1931 obj->setDescription(owning_qpdf, descr);
1569 1932 }
1570 1933 }
... ... @@ -1614,7 +1977,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1614 1977 items.emplace_back(array.at(i).second);
1615 1978 items.back().makeDirect(visited, stop_at_streams);
1616 1979 }
1617   - this->obj = QPDF_Array::create(items);
  1980 + this->obj = QPDFObject::create<QPDF_Array>(items);
1618 1981 } else if (isDictionary()) {
1619 1982 std::map<std::string, QPDFObjectHandle> items;
1620 1983 auto dict = as_dictionary(strict);
... ... @@ -1622,7 +1985,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1622 1985 items[key] = dict.getKey(key);
1623 1986 items[key].makeDirect(visited, stop_at_streams);
1624 1987 }
1625   - this->obj = QPDF_Dictionary::create(items);
  1988 + this->obj = QPDFObject::create<QPDF_Dictionary>(items);
1626 1989 } else if (isStream()) {
1627 1990 QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1);
1628 1991 if (!stop_at_streams) {
... ...
libqpdf/QPDFParser.cc
... ... @@ -4,18 +4,6 @@
4 4 #include <qpdf/QPDFObjGen.hh>
5 5 #include <qpdf/QPDFObjectHandle.hh>
6 6 #include <qpdf/QPDFObject_private.hh>
7   -#include <qpdf/QPDF_Array.hh>
8   -#include <qpdf/QPDF_Bool.hh>
9   -#include <qpdf/QPDF_Dictionary.hh>
10   -#include <qpdf/QPDF_InlineImage.hh>
11   -#include <qpdf/QPDF_Integer.hh>
12   -#include <qpdf/QPDF_Name.hh>
13   -#include <qpdf/QPDF_Null.hh>
14   -#include <qpdf/QPDF_Operator.hh>
15   -#include <qpdf/QPDF_Real.hh>
16   -#include <qpdf/QPDF_Reserved.hh>
17   -#include <qpdf/QPDF_Stream.hh>
18   -#include <qpdf/QPDF_String.hh>
19 7 #include <qpdf/QTC.hh>
20 8 #include <qpdf/QUtil.hh>
21 9  
... ... @@ -47,27 +35,27 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
47 35 }
48 36 QTC::TC("qpdf", "QPDFParser eof in parse");
49 37 warn("unexpected EOF");
50   - return {QPDF_Null::create()};
  38 + return {QPDFObject::create<QPDF_Null>()};
51 39  
52 40 case QPDFTokenizer::tt_bad:
53 41 QTC::TC("qpdf", "QPDFParser bad token in parse");
54   - return {QPDF_Null::create()};
  42 + return {QPDFObject::create<QPDF_Null>()};
55 43  
56 44 case QPDFTokenizer::tt_brace_open:
57 45 case QPDFTokenizer::tt_brace_close:
58 46 QTC::TC("qpdf", "QPDFParser bad brace");
59 47 warn("treating unexpected brace token as null");
60   - return {QPDF_Null::create()};
  48 + return {QPDFObject::create<QPDF_Null>()};
61 49  
62 50 case QPDFTokenizer::tt_array_close:
63 51 QTC::TC("qpdf", "QPDFParser bad array close");
64 52 warn("treating unexpected array close token as null");
65   - return {QPDF_Null::create()};
  53 + return {QPDFObject::create<QPDF_Null>()};
66 54  
67 55 case QPDFTokenizer::tt_dict_close:
68 56 QTC::TC("qpdf", "QPDFParser bad dictionary close");
69 57 warn("unexpected dictionary close token");
70   - return {QPDF_Null::create()};
  58 + return {QPDFObject::create<QPDF_Null>()};
71 59  
72 60 case QPDFTokenizer::tt_array_open:
73 61 case QPDFTokenizer::tt_dict_open:
... ... @@ -82,7 +70,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
82 70 return withDescription<QPDF_Bool>(tokenizer.getValue() == "true");
83 71  
84 72 case QPDFTokenizer::tt_null:
85   - return {QPDF_Null::create()};
  73 + return {QPDFObject::create<QPDF_Null>()};
86 74  
87 75 case QPDFTokenizer::tt_integer:
88 76 return withDescription<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str()));
... ... @@ -103,7 +91,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
103 91 // not move the input source's offset.
104 92 input.seek(input.getLastOffset(), SEEK_SET);
105 93 empty = true;
106   - return {QPDF_Null::create()};
  94 + return {QPDFObject::create<QPDF_Null>()};
107 95 } else {
108 96 QTC::TC("qpdf", "QPDFParser treat word as string");
109 97 warn("unknown token while reading object; treating as string");
... ... @@ -122,7 +110,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
122 110  
123 111 default:
124 112 warn("treating unknown token type as null while reading object");
125   - return {QPDF_Null::create()};
  113 + return {QPDFObject::create<QPDF_Null>()};
126 114 }
127 115 }
128 116  
... ... @@ -194,12 +182,12 @@ QPDFParser::parseRemainder(bool content_stream)
194 182 }
195 183 QTC::TC("qpdf", "QPDFParser eof in parseRemainder");
196 184 warn("unexpected EOF");
197   - return {QPDF_Null::create()};
  185 + return {QPDFObject::create<QPDF_Null>()};
198 186  
199 187 case QPDFTokenizer::tt_bad:
200 188 QTC::TC("qpdf", "QPDFParser bad token in parseRemainder");
201 189 if (tooManyBadTokens()) {
202   - return {QPDF_Null::create()};
  190 + return {QPDFObject::create<QPDF_Null>()};
203 191 }
204 192 addNull();
205 193 continue;
... ... @@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream)
209 197 QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder");
210 198 warn("treating unexpected brace token as null");
211 199 if (tooManyBadTokens()) {
212   - return {QPDF_Null::create()};
  200 + return {QPDFObject::create<QPDF_Null>()};
213 201 }
214 202 addNull();
215 203 continue;
... ... @@ -218,10 +206,11 @@ QPDFParser::parseRemainder(bool content_stream)
218 206 if (bad_count && !max_bad_count) {
219 207 // Trigger warning.
220 208 (void)tooManyBadTokens();
221   - return {QPDF_Null::create()};
  209 + return {QPDFObject::create<QPDF_Null>()};
222 210 }
223 211 if (frame->state == st_array) {
224   - auto object = QPDF_Array::create(std::move(frame->olist), frame->null_count > 100);
  212 + auto object = QPDFObject::create<QPDF_Array>(
  213 + std::move(frame->olist), frame->null_count > 100);
225 214 setDescription(object, frame->offset - 1);
226 215 // The `offset` points to the next of "[". Set the rewind offset to point to the
227 216 // beginning of "[". This has been explicitly tested with whitespace surrounding the
... ... @@ -237,7 +226,7 @@ QPDFParser::parseRemainder(bool content_stream)
237 226 QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder");
238 227 warn("treating unexpected array close token as null");
239 228 if (tooManyBadTokens()) {
240   - return {QPDF_Null::create()};
  229 + return {QPDFObject::create<QPDF_Null>()};
241 230 }
242 231 addNull();
243 232 }
... ... @@ -247,7 +236,7 @@ QPDFParser::parseRemainder(bool content_stream)
247 236 if (bad_count && !max_bad_count) {
248 237 // Trigger warning.
249 238 (void)tooManyBadTokens();
250   - return {QPDF_Null::create()};
  239 + return {QPDFObject::create<QPDF_Null>()};
251 240 }
252 241 if (frame->state <= st_dictionary_value) {
253 242 // Attempt to recover more or less gracefully from invalid dictionaries.
... ... @@ -258,7 +247,7 @@ QPDFParser::parseRemainder(bool content_stream)
258 247 warn(
259 248 frame->offset,
260 249 "dictionary ended prematurely; using null as value for last key");
261   - dict[frame->key] = QPDF_Null::create();
  250 + dict[frame->key] = QPDFObject::create<QPDF_Null>();
262 251 }
263 252  
264 253 if (!frame->olist.empty()) {
... ... @@ -271,7 +260,7 @@ QPDFParser::parseRemainder(bool content_stream)
271 260 dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string);
272 261 dict["/Contents"].setParsedOffset(frame->contents_offset);
273 262 }
274   - auto object = QPDF_Dictionary::create(std::move(dict));
  263 + auto object = QPDFObject::create<QPDF_Dictionary>(std::move(dict));
275 264 setDescription(object, frame->offset - 2);
276 265 // The `offset` points to the next of "<<". Set the rewind offset to point to the
277 266 // beginning of "<<". This has been explicitly tested with whitespace surrounding
... ... @@ -287,7 +276,7 @@ QPDFParser::parseRemainder(bool content_stream)
287 276 QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder");
288 277 warn("unexpected dictionary close token");
289 278 if (tooManyBadTokens()) {
290   - return {QPDF_Null::create()};
  279 + return {QPDFObject::create<QPDF_Null>()};
291 280 }
292 281 addNull();
293 282 }
... ... @@ -298,7 +287,7 @@ QPDFParser::parseRemainder(bool content_stream)
298 287 if (stack.size() > 499) {
299 288 QTC::TC("qpdf", "QPDFParser too deep");
300 289 warn("ignoring excessively deeply nested data structure");
301   - return {QPDF_Null::create()};
  290 + return {QPDFObject::create<QPDF_Null>()};
302 291 } else {
303 292 b_contents = false;
304 293 stack.emplace_back(
... ... @@ -350,7 +339,7 @@ QPDFParser::parseRemainder(bool content_stream)
350 339 QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder");
351 340 warn("unknown token while reading object; treating as string");
352 341 if (tooManyBadTokens()) {
353   - return {QPDF_Null::create()};
  342 + return {QPDFObject::create<QPDF_Null>()};
354 343 }
355 344 addScalar<QPDF_String>(tokenizer.getValue());
356 345 }
... ... @@ -377,7 +366,7 @@ QPDFParser::parseRemainder(bool content_stream)
377 366 default:
378 367 warn("treating unknown token type as null while reading object");
379 368 if (tooManyBadTokens()) {
380   - return {QPDF_Null::create()};
  369 + return {QPDFObject::create<QPDF_Null>()};
381 370 }
382 371 addNull();
383 372 }
... ... @@ -402,7 +391,7 @@ QPDFParser::add(std::shared_ptr&lt;QPDFObject&gt;&amp;&amp; obj)
402 391 void
403 392 QPDFParser::addNull()
404 393 {
405   - const static ObjectPtr null_obj = QPDF_Null::create();
  394 + const static ObjectPtr null_obj = QPDFObject::create<QPDF_Null>();
406 395  
407 396 if (frame->state != st_dictionary_value) {
408 397 // If state is st_dictionary_key then there is a missing key. Push onto olist for
... ... @@ -420,7 +409,7 @@ QPDFParser::addNull()
420 409 void
421 410 QPDFParser::addInt(int count)
422 411 {
423   - auto obj = QPDF_Integer::create(int_buffer[count % 2]);
  412 + auto obj = QPDFObject::create<QPDF_Integer>(int_buffer[count % 2]);
424 413 obj->setDescription(context, description, last_offset_buffer[count % 2]);
425 414 add(std::move(obj));
426 415 }
... ... @@ -435,7 +424,7 @@ QPDFParser::addScalar(Args&amp;&amp;... args)
435 424 max_bad_count = 0;
436 425 return;
437 426 }
438   - auto obj = T::create(args...);
  427 + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...);
439 428 obj->setDescription(context, description, input.getLastOffset());
440 429 add(std::move(obj));
441 430 }
... ... @@ -444,7 +433,7 @@ template &lt;typename T, typename... Args&gt;
444 433 QPDFObjectHandle
445 434 QPDFParser::withDescription(Args&&... args)
446 435 {
447   - auto obj = T::create(args...);
  436 + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...);
448 437 obj->setDescription(context, description, start);
449 438 return {obj};
450 439 }
... ...
libqpdf/QPDFValue.cc deleted
1   -#include <qpdf/QPDFValue.hh>
2   -
3   -#include <qpdf/QPDFObject_private.hh>
4   -
5   -std::shared_ptr<QPDFObject>
6   -QPDFValue::do_create(QPDFValue* object)
7   -{
8   - std::shared_ptr<QPDFObject> obj(new QPDFObject());
9   - obj->value = std::shared_ptr<QPDFValue>(object);
10   - return obj;
11   -}
12   -
13   -std::string
14   -QPDFValue::getDescription()
15   -{
16   - if (object_description) {
17   - switch (object_description->index()) {
18   - case 0:
19   - {
20   - // Simple template string
21   - auto description = std::get<0>(*object_description);
22   -
23   - if (auto pos = description.find("$OG"); pos != std::string::npos) {
24   - description.replace(pos, 3, og.unparse(' '));
25   - }
26   - if (auto pos = description.find("$PO"); pos != std::string::npos) {
27   - qpdf_offset_t shift = (type_code == ::ot_dictionary) ? 2
28   - : (type_code == ::ot_array) ? 1
29   - : 0;
30   -
31   - description.replace(pos, 3, std::to_string(parsed_offset + shift));
32   - }
33   - return description;
34   - }
35   - case 1:
36   - {
37   - // QPDF::JSONReactor generated description
38   - auto j_descr = std::get<1>(*object_description);
39   - return (
40   - *j_descr.input + (j_descr.object.empty() ? "" : ", " + j_descr.object) +
41   - " at offset " + std::to_string(parsed_offset));
42   - }
43   - case 2:
44   - {
45   - // Child object description
46   - auto j_descr = std::get<2>(*object_description);
47   - std::string result;
48   - if (auto p = j_descr.parent.lock()) {
49   - result = p->getDescription();
50   - }
51   - result += j_descr.static_descr;
52   - if (auto pos = result.find("$VD"); pos != std::string::npos) {
53   - result.replace(pos, 3, j_descr.var_descr);
54   - }
55   - return result;
56   - }
57   - }
58   - } else if (og.isIndirect()) {
59   - return "object " + og.unparse(' ');
60   - }
61   - return {};
62   -}
libqpdf/QPDFWriter.cc
... ... @@ -16,8 +16,7 @@
16 16 #include <qpdf/QIntC.hh>
17 17 #include <qpdf/QPDF.hh>
18 18 #include <qpdf/QPDFObjectHandle_private.hh>
19   -#include <qpdf/QPDF_Name.hh>
20   -#include <qpdf/QPDF_String.hh>
  19 +#include <qpdf/QPDFObject_private.hh>
21 20 #include <qpdf/QTC.hh>
22 21 #include <qpdf/QUtil.hh>
23 22 #include <qpdf/RC4.hh>
... ...
libqpdf/QPDF_Array.cc
1   -#include <qpdf/QPDF_Array.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4 1 #include <qpdf/QPDFObjectHandle_private.hh>
5   -#include <qpdf/QPDFObject_private.hh>
6   -#include <qpdf/QPDF_Null.hh>
  2 +
7 3 #include <qpdf/QTC.hh>
8 4  
9 5 using namespace std::literals;
... ... @@ -40,25 +36,12 @@ Array::checkOwnership(QPDFObjectHandle const&amp; item) const
40 36 }
41 37 }
42 38  
43   -QPDF_Array::QPDF_Array() :
44   - QPDFValue(::ot_array)
45   -{
46   -}
47   -
48   -QPDF_Array::QPDF_Array(QPDF_Array const& other) :
49   - QPDFValue(::ot_array),
50   - sp(other.sp ? std::make_unique<Sparse>(*other.sp) : nullptr)
51   -{
52   -}
53   -
54   -QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) :
55   - QPDFValue(::ot_array)
  39 +QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v)
56 40 {
57 41 setFromVector(v);
58 42 }
59 43  
60   -QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse) :
61   - QPDFValue(::ot_array)
  44 +QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse)
62 45 {
63 46 if (sparse) {
64 47 sp = std::make_unique<Sparse>();
... ... @@ -73,132 +56,6 @@ QPDF_Array::QPDF_Array(std::vector&lt;std::shared_ptr&lt;QPDFObject&gt;&gt;&amp;&amp; v, bool sparse
73 56 }
74 57 }
75 58  
76   -std::shared_ptr<QPDFObject>
77   -QPDF_Array::create(std::vector<QPDFObjectHandle> const& items)
78   -{
79   - return do_create(new QPDF_Array(items));
80   -}
81   -
82   -std::shared_ptr<QPDFObject>
83   -QPDF_Array::create(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse)
84   -{
85   - return do_create(new QPDF_Array(std::move(items), sparse));
86   -}
87   -
88   -std::shared_ptr<QPDFObject>
89   -QPDF_Array::copy(bool shallow)
90   -{
91   - if (shallow) {
92   - return do_create(new QPDF_Array(*this));
93   - } else {
94   - QTC::TC("qpdf", "QPDF_Array copy", sp ? 0 : 1);
95   - if (sp) {
96   - auto* result = new QPDF_Array();
97   - result->sp = std::make_unique<Sparse>();
98   - result->sp->size = sp->size;
99   - for (auto const& element: sp->elements) {
100   - auto const& obj = element.second;
101   - result->sp->elements[element.first] =
102   - obj->getObjGen().isIndirect() ? obj : obj->copy();
103   - }
104   - return do_create(result);
105   - } else {
106   - std::vector<std::shared_ptr<QPDFObject>> result;
107   - result.reserve(elements.size());
108   - for (auto const& element: elements) {
109   - result.push_back(
110   - element ? (element->getObjGen().isIndirect() ? element : element->copy())
111   - : element);
112   - }
113   - return create(std::move(result), false);
114   - }
115   - }
116   -}
117   -
118   -void
119   -QPDF_Array::disconnect()
120   -{
121   - if (sp) {
122   - for (auto& item: sp->elements) {
123   - auto& obj = item.second;
124   - if (!obj->getObjGen().isIndirect()) {
125   - obj->disconnect();
126   - }
127   - }
128   - } else {
129   - for (auto& obj: elements) {
130   - if (!obj->getObjGen().isIndirect()) {
131   - obj->disconnect();
132   - }
133   - }
134   - }
135   -}
136   -
137   -std::string
138   -QPDF_Array::unparse()
139   -{
140   - std::string result = "[ ";
141   - if (sp) {
142   - int next = 0;
143   - for (auto& item: sp->elements) {
144   - int key = item.first;
145   - for (int j = next; j < key; ++j) {
146   - result += "null ";
147   - }
148   - auto og = item.second->resolved_object()->getObjGen();
149   - result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " ";
150   - next = ++key;
151   - }
152   - for (int j = next; j < sp->size; ++j) {
153   - result += "null ";
154   - }
155   - } else {
156   - for (auto const& item: elements) {
157   - auto og = item->resolved_object()->getObjGen();
158   - result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " ";
159   - }
160   - }
161   - result += "]";
162   - return result;
163   -}
164   -
165   -void
166   -QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
167   -{
168   - p.writeStart('[');
169   - if (sp) {
170   - int next = 0;
171   - for (auto& item: sp->elements) {
172   - int key = item.first;
173   - for (int j = next; j < key; ++j) {
174   - p.writeNext() << "null";
175   - }
176   - p.writeNext();
177   - auto og = item.second->getObjGen();
178   - if (og.isIndirect()) {
179   - p << "\"" << og.unparse(' ') << " R\"";
180   - } else {
181   - item.second->writeJSON(json_version, p);
182   - }
183   - next = ++key;
184   - }
185   - for (int j = next; j < sp->size; ++j) {
186   - p.writeNext() << "null";
187   - }
188   - } else {
189   - for (auto const& item: elements) {
190   - p.writeNext();
191   - auto og = item->getObjGen();
192   - if (og.isIndirect()) {
193   - p << "\"" << og.unparse(' ') << " R\"";
194   - } else {
195   - item->writeJSON(json_version, p);
196   - }
197   - }
198   - }
199   - p.writeEnd(']');
200   -}
201   -
202 59 QPDF_Array*
203 60 Array::array() const
204 61 {
... ...
libqpdf/QPDF_Bool.cc deleted
1   -#include <qpdf/QPDF_Bool.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -
5   -QPDF_Bool::QPDF_Bool(bool val) :
6   - QPDFValue(::ot_boolean),
7   - val(val)
8   -{
9   -}
10   -
11   -std::shared_ptr<QPDFObject>
12   -QPDF_Bool::create(bool value)
13   -{
14   - return do_create(new QPDF_Bool(value));
15   -}
16   -
17   -std::shared_ptr<QPDFObject>
18   -QPDF_Bool::copy(bool shallow)
19   -{
20   - return create(val);
21   -}
22   -
23   -std::string
24   -QPDF_Bool::unparse()
25   -{
26   - return (val ? "true" : "false");
27   -}
28   -
29   -void
30   -QPDF_Bool::writeJSON(int json_version, JSON::Writer& p)
31   -{
32   - p << val;
33   -}
34   -
35   -bool
36   -QPDF_Bool::getVal() const
37   -{
38   - return this->val;
39   -}
libqpdf/QPDF_Destroyed.cc deleted
1   -#include <qpdf/QPDF_Destroyed.hh>
2   -
3   -#include <stdexcept>
4   -
5   -QPDF_Destroyed::QPDF_Destroyed() :
6   - QPDFValue(::ot_destroyed)
7   -{
8   -}
9   -
10   -std::shared_ptr<QPDFValue>
11   -QPDF_Destroyed::getInstance()
12   -{
13   - static std::shared_ptr<QPDFValue> instance(new QPDF_Destroyed());
14   - return instance;
15   -}
16   -
17   -std::shared_ptr<QPDFObject>
18   -QPDF_Destroyed::copy(bool shallow)
19   -{
20   - throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF");
21   - return nullptr;
22   -}
23   -
24   -std::string
25   -QPDF_Destroyed::unparse()
26   -{
27   - throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF");
28   - return "";
29   -}
30   -
31   -void
32   -QPDF_Destroyed::writeJSON(int json_version, JSON::Writer& p)
33   -{
34   - throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF");
35   -}
36 0 \ No newline at end of file
libqpdf/QPDF_Dictionary.cc
1   -#include <qpdf/QPDF_Dictionary.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4 1 #include <qpdf/QPDFObjectHandle_private.hh>
  2 +
5 3 #include <qpdf/QPDFObject_private.hh>
6   -#include <qpdf/QPDF_Name.hh>
7 4 #include <qpdf/QTC.hh>
8   -#include <qpdf/QUtil.hh>
9 5  
10 6 using namespace std::literals;
11 7 using namespace qpdf;
12 8  
13   -QPDF_Dictionary::QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items) :
14   - QPDFValue(::ot_dictionary),
15   - items(items)
16   -{
17   -}
18   -
19   -QPDF_Dictionary::QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items) :
20   - QPDFValue(::ot_dictionary),
21   - items(items)
22   -{
23   -}
24   -
25   -std::shared_ptr<QPDFObject>
26   -QPDF_Dictionary::create(std::map<std::string, QPDFObjectHandle> const& items)
27   -{
28   - return do_create(new QPDF_Dictionary(items));
29   -}
30   -
31   -std::shared_ptr<QPDFObject>
32   -QPDF_Dictionary::create(std::map<std::string, QPDFObjectHandle>&& items)
33   -{
34   - return do_create(new QPDF_Dictionary(items));
35   -}
36   -
37   -std::shared_ptr<QPDFObject>
38   -QPDF_Dictionary::copy(bool shallow)
39   -{
40   - if (shallow) {
41   - return create(items);
42   - } else {
43   - std::map<std::string, QPDFObjectHandle> new_items;
44   - for (auto const& item: this->items) {
45   - auto value = item.second;
46   - new_items[item.first] = value.isIndirect() ? value : value.shallowCopy();
47   - }
48   - return create(new_items);
49   - }
50   -}
51   -
52   -void
53   -QPDF_Dictionary::disconnect()
54   -{
55   - for (auto& iter: this->items) {
56   - QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
57   - }
58   -}
59   -
60   -std::string
61   -QPDF_Dictionary::unparse()
62   -{
63   - std::string result = "<< ";
64   - for (auto& iter: this->items) {
65   - if (!iter.second.isNull()) {
66   - result += Name::normalize(iter.first) + " " + iter.second.unparse() + " ";
67   - }
68   - }
69   - result += ">>";
70   - return result;
71   -}
72   -
73   -void
74   -QPDF_Dictionary::writeJSON(int json_version, JSON::Writer& p)
75   -{
76   - p.writeStart('{');
77   - for (auto& iter: this->items) {
78   - if (!iter.second.isNull()) {
79   - p.writeNext();
80   - if (json_version == 1) {
81   - p << "\"" << JSON::Writer::encode_string(Name::normalize(iter.first)) << "\": ";
82   - } else if (auto res = Name::analyzeJSONEncoding(iter.first); res.first) {
83   - if (res.second) {
84   - p << "\"" << iter.first << "\": ";
85   - } else {
86   - p << "\"" << JSON::Writer::encode_string(iter.first) << "\": ";
87   - }
88   - } else {
89   - p << "\"n:" << JSON::Writer::encode_string(Name::normalize(iter.first)) << "\": ";
90   - }
91   - iter.second.writeJSON(json_version, p);
92   - }
93   - }
94   - p.writeEnd('}');
95   -}
96   -
97 9 QPDF_Dictionary*
98 10 BaseDictionary::dict() const
99 11 {
... ...
libqpdf/QPDF_InlineImage.cc deleted
1   -#include <qpdf/QPDF_InlineImage.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -
5   -QPDF_InlineImage::QPDF_InlineImage(std::string const& val) :
6   - QPDFValue(::ot_inlineimage),
7   - val(val)
8   -{
9   -}
10   -
11   -std::shared_ptr<QPDFObject>
12   -QPDF_InlineImage::create(std::string const& val)
13   -{
14   - return do_create(new QPDF_InlineImage(val));
15   -}
16   -
17   -std::shared_ptr<QPDFObject>
18   -QPDF_InlineImage::copy(bool shallow)
19   -{
20   - return create(val);
21   -}
22   -
23   -std::string
24   -QPDF_InlineImage::unparse()
25   -{
26   - return this->val;
27   -}
28   -
29   -void
30   -QPDF_InlineImage::writeJSON(int json_version, JSON::Writer& p)
31   -{
32   - p << "null";
33   -}
libqpdf/QPDF_Integer.cc deleted
1   -#include <qpdf/QPDF_Integer.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -#include <qpdf/QUtil.hh>
5   -
6   -QPDF_Integer::QPDF_Integer(long long val) :
7   - QPDFValue(::ot_integer),
8   - val(val)
9   -{
10   -}
11   -
12   -std::shared_ptr<QPDFObject>
13   -QPDF_Integer::create(long long value)
14   -{
15   - return do_create(new QPDF_Integer(value));
16   -}
17   -
18   -std::shared_ptr<QPDFObject>
19   -QPDF_Integer::copy(bool shallow)
20   -{
21   - return create(val);
22   -}
23   -
24   -std::string
25   -QPDF_Integer::unparse()
26   -{
27   - return std::to_string(this->val);
28   -}
29   -
30   -void
31   -QPDF_Integer::writeJSON(int json_version, JSON::Writer& p)
32   -{
33   - p << std::to_string(this->val);
34   -}
35   -
36   -long long
37   -QPDF_Integer::getVal() const
38   -{
39   - return this->val;
40   -}
libqpdf/QPDF_Name.cc
1   -#include <qpdf/QPDF_Name.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -#include <qpdf/QPDFObjectHandle_private.hh>
5   -#include <qpdf/QUtil.hh>
6   -
7   -using namespace qpdf;
8   -
9   -QPDF_Name::QPDF_Name(std::string const& name) :
10   - QPDFValue(::ot_name),
11   - name(name)
12   -{
13   -}
14   -
15   -std::shared_ptr<QPDFObject>
16   -QPDF_Name::create(std::string const& name)
17   -{
18   - return do_create(new QPDF_Name(name));
19   -}
20   -
21   -std::shared_ptr<QPDFObject>
22   -QPDF_Name::copy(bool shallow)
23   -{
24   - return create(name);
25   -}
26   -
27   -std::string
28   -Name::normalize(std::string const& name)
29   -{
30   - if (name.empty()) {
31   - return name;
32   - }
33   - std::string result;
34   - result += name.at(0);
35   - for (size_t i = 1; i < name.length(); ++i) {
36   - char ch = name.at(i);
37   - // Don't use locale/ctype here; follow PDF spec guidelines.
38   - if (ch == '\0') {
39   - // QPDFTokenizer embeds a null character to encode an invalid #.
40   - result += "#";
41   - } else if (
42   - ch < 33 || ch == '#' || ch == '/' || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
43   - ch == '<' || ch == '>' || ch == '[' || ch == ']' || ch == '%' || ch > 126) {
44   - result += QUtil::hex_encode_char(ch);
45   - } else {
46   - result += ch;
47   - }
48   - }
49   - return result;
50   -}
51   -
52   -std::string
53   -QPDF_Name::unparse()
54   -{
55   - return Name::normalize(name);
56   -}
57   -
58   -std::pair<bool, bool>
59   -Name::analyzeJSONEncoding(const std::string& name)
60   -{
61   - int tail = 0; // Number of continuation characters expected.
62   - bool tail2 = false; // Potential overlong 3 octet utf-8.
63   - bool tail3 = false; // potential overlong 4 octet
64   - bool needs_escaping = false;
65   - for (auto const& it: name) {
66   - auto c = static_cast<unsigned char>(it);
67   - if (tail) {
68   - if ((c & 0xc0) != 0x80) {
69   - return {false, false};
70   - }
71   - if (tail2) {
72   - if ((c & 0xe0) == 0x80) {
73   - return {false, false};
74   - }
75   - tail2 = false;
76   - } else if (tail3) {
77   - if ((c & 0xf0) == 0x80) {
78   - return {false, false};
79   - }
80   - tail3 = false;
81   - }
82   - tail--;
83   - } else if (c < 0x80) {
84   - if (!needs_escaping) {
85   - needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33);
86   - }
87   - } else if ((c & 0xe0) == 0xc0) {
88   - if ((c & 0xfe) == 0xc0) {
89   - return {false, false};
90   - }
91   - tail = 1;
92   - } else if ((c & 0xf0) == 0xe0) {
93   - tail2 = (c == 0xe0);
94   - tail = 2;
95   - } else if ((c & 0xf8) == 0xf0) {
96   - tail3 = (c == 0xf0);
97   - tail = 3;
98   - } else {
99   - return {false, false};
100   - }
101   - }
102   - return {tail == 0, !needs_escaping};
103   -}
104   -
105   -void
106   -QPDF_Name::writeJSON(int json_version, JSON::Writer& p)
107   -{
108   - // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When updating
109   - // this method make sure QPDF_Dictionary is also update.
110   - if (json_version == 1) {
111   - p << "\"" << JSON::Writer::encode_string(Name::normalize(name)) << "\"";
112   - } else {
113   - if (auto res = Name::analyzeJSONEncoding(name); res.first) {
114   - if (res.second) {
115   - p << "\"" << name << "\"";
116   - } else {
117   - p << "\"" << JSON::Writer::encode_string(name) << "\"";
118   - }
119   - } else {
120   - p << "\"n:" << JSON::Writer::encode_string(Name::normalize(name)) << "\"";
121   - }
122   - }
123   -}
libqpdf/QPDF_Null.cc deleted
1   -#include <qpdf/QPDF_Null.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -#include <qpdf/QPDFObject_private.hh>
5   -
6   -QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) :
7   - QPDFValue(::ot_null, qpdf, og)
8   -{
9   -}
10   -
11   -std::shared_ptr<QPDFObject>
12   -QPDF_Null::create(QPDF* qpdf, QPDFObjGen og)
13   -{
14   - return do_create(new QPDF_Null(qpdf, og));
15   -}
16   -
17   -std::shared_ptr<QPDFObject>
18   -QPDF_Null::create(
19   - std::shared_ptr<QPDFObject> parent, std::string_view const& static_descr, std::string var_descr)
20   -{
21   - auto n = do_create(new QPDF_Null());
22   - n->setChildDescription(parent, static_descr, var_descr);
23   - return n;
24   -}
25   -
26   -std::shared_ptr<QPDFObject>
27   -QPDF_Null::create(
28   - std::shared_ptr<QPDFValue> parent, std::string_view const& static_descr, std::string var_descr)
29   -{
30   - auto n = do_create(new QPDF_Null());
31   - n->setChildDescription(parent, static_descr, var_descr);
32   - return n;
33   -}
34   -
35   -std::shared_ptr<QPDFObject>
36   -QPDF_Null::copy(bool shallow)
37   -{
38   - return create();
39   -}
40   -
41   -std::string
42   -QPDF_Null::unparse()
43   -{
44   - return "null";
45   -}
46   -
47   -void
48   -QPDF_Null::writeJSON(int json_version, JSON::Writer& p)
49   -{
50   - p << "null";
51   -}
libqpdf/QPDF_Operator.cc deleted
1   -#include <qpdf/QPDF_Operator.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -
5   -QPDF_Operator::QPDF_Operator(std::string const& val) :
6   - QPDFValue(::ot_operator),
7   - val(val)
8   -{
9   -}
10   -
11   -std::shared_ptr<QPDFObject>
12   -QPDF_Operator::create(std::string const& val)
13   -{
14   - return do_create(new QPDF_Operator(val));
15   -}
16   -
17   -std::shared_ptr<QPDFObject>
18   -QPDF_Operator::copy(bool shallow)
19   -{
20   - return create(val);
21   -}
22   -
23   -std::string
24   -QPDF_Operator::unparse()
25   -{
26   - return val;
27   -}
28   -
29   -void
30   -QPDF_Operator::writeJSON(int json_version, JSON::Writer& p)
31   -{
32   - p << "null";
33   -}
libqpdf/QPDF_Real.cc deleted
1   -#include <qpdf/QPDF_Real.hh>
2   -
3   -#include <qpdf/JSON_writer.hh>
4   -#include <qpdf/QUtil.hh>
5   -
6   -QPDF_Real::QPDF_Real(std::string const& val) :
7   - QPDFValue(::ot_real),
8   - val(val)
9   -{
10   -}
11   -
12   -QPDF_Real::QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes) :
13   - QPDFValue(::ot_real),
14   - val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes))
15   -{
16   -}
17   -
18   -std::shared_ptr<QPDFObject>
19   -QPDF_Real::create(std::string const& val)
20   -{
21   - return do_create(new QPDF_Real(val));
22   -}
23   -
24   -std::shared_ptr<QPDFObject>
25   -QPDF_Real::create(double value, int decimal_places, bool trim_trailing_zeroes)
26   -{
27   - return do_create(new QPDF_Real(value, decimal_places, trim_trailing_zeroes));
28   -}
29   -
30   -std::shared_ptr<QPDFObject>
31   -QPDF_Real::copy(bool shallow)
32   -{
33   - return create(val);
34   -}
35   -
36   -std::string
37   -QPDF_Real::unparse()
38   -{
39   - return this->val;
40   -}
41   -
42   -void
43   -QPDF_Real::writeJSON(int json_version, JSON::Writer& p)
44   -{
45   - if (this->val.length() == 0) {
46   - // Can't really happen...
47   - p << "0";
48   - } else if (this->val.at(0) == '.') {
49   - p << "0" << this->val;
50   - } else if (this->val.length() >= 2 && this->val.at(0) == '-' && this->val.at(1) == '.') {
51   - p << "-0." << this->val.substr(2);
52   - } else {
53   - p << this->val;
54   - }
55   - if (val.back() == '.') {
56   - p << "0";
57   - }
58   -}
libqpdf/QPDF_Reserved.cc deleted
1   -#include <qpdf/QPDF_Reserved.hh>
2   -
3   -#include <stdexcept>
4   -
5   -QPDF_Reserved::QPDF_Reserved() :
6   - QPDFValue(::ot_reserved)
7   -{
8   -}
9   -
10   -std::shared_ptr<QPDFObject>
11   -QPDF_Reserved::create()
12   -{
13   - return do_create(new QPDF_Reserved());
14   -}
15   -
16   -std::shared_ptr<QPDFObject>
17   -QPDF_Reserved::copy(bool shallow)
18   -{
19   - return create();
20   -}
21   -
22   -std::string
23   -QPDF_Reserved::unparse()
24   -{
25   - throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object");
26   - return "";
27   -}
28   -
29   -void
30   -QPDF_Reserved::writeJSON(int json_version, JSON::Writer& p)
31   -{
32   - throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object");
33   -}
libqpdf/QPDF_Stream.cc
1   -#include <qpdf/QPDF_Stream.hh>
  1 +#include <qpdf/QPDFObjectHandle_private.hh>
2 2  
3 3 #include <qpdf/ContentNormalizer.hh>
4 4 #include <qpdf/JSON_writer.hh>
... ... @@ -12,7 +12,6 @@
12 12 #include <qpdf/QIntC.hh>
13 13 #include <qpdf/QPDF.hh>
14 14 #include <qpdf/QPDFExc.hh>
15   -#include <qpdf/QPDFObjectHandle_private.hh>
16 15 #include <qpdf/QTC.hh>
17 16 #include <qpdf/QUtil.hh>
18 17 #include <qpdf/SF_ASCII85Decode.hh>
... ... @@ -105,34 +104,14 @@ std::map&lt;std::string, std::function&lt;std::shared_ptr&lt;QPDFStreamFilter&gt;()&gt;&gt; Stream
105 104 {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory},
106 105 };
107 106  
108   -QPDF_Stream::QPDF_Stream(
109   - QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) :
110   - QPDFValue(::ot_stream, qpdf, og),
111   - filter_on_write(true),
112   - stream_dict(stream_dict),
113   - length(length)
114   -{
115   - if (!stream_dict.isDictionary()) {
116   - throw std::logic_error(
117   - "stream object instantiated with non-dictionary object for dictionary");
118   - }
119   - auto descr = std::make_shared<QPDFValue::Description>(
120   - qpdf->getFilename() + ", stream object " + og.unparse(' '));
121   - setDescription(qpdf, descr, offset);
122   -}
123   -
124   -std::shared_ptr<QPDFObject>
125   -QPDF_Stream::create(
126   - QPDF* qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length)
  107 +Stream::Stream(
  108 + QPDF& qpdf, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length) :
  109 + BaseHandle(QPDFObject::create<QPDF_Stream>(&qpdf, og, std::move(stream_dict), length))
127 110 {
128   - return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length));
129   -}
130   -
131   -std::shared_ptr<QPDFObject>
132   -QPDF_Stream::copy(bool shallow)
133   -{
134   - QTC::TC("qpdf", "QPDF_Stream ERR shallow copy stream");
135   - throw std::runtime_error("stream objects cannot be cloned");
  111 + auto descr = std::make_shared<QPDFObject::Description>(
  112 + qpdf.getFilename() + ", stream object " + og.unparse(' '));
  113 + obj->setDescription(&qpdf, descr, offset);
  114 + setDictDescription();
136 115 }
137 116  
138 117 void
... ... @@ -142,26 +121,6 @@ Stream::registerStreamFilter(
142 121 filter_factories[filter_name] = factory;
143 122 }
144 123  
145   -void
146   -QPDF_Stream::disconnect()
147   -{
148   - this->stream_provider = nullptr;
149   - QPDFObjectHandle::DisconnectAccess::disconnect(this->stream_dict);
150   -}
151   -
152   -std::string
153   -QPDF_Stream::unparse()
154   -{
155   - // Unparse stream objects as indirect references
156   - return og.unparse(' ') + " R";
157   -}
158   -
159   -void
160   -QPDF_Stream::writeJSON(int json_version, JSON::Writer& jw)
161   -{
162   - stream_dict.writeJSON(json_version, jw);
163   -}
164   -
165 124 JSON
166 125 Stream::getStreamJSON(
167 126 int json_version,
... ... @@ -278,34 +237,27 @@ Stream::writeStreamJSON(
278 237 }
279 238  
280 239 void
281   -QPDF_Stream::setDescription(
282   - QPDF* qpdf, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset)
  240 +qpdf::Stream::setDictDescription()
283 241 {
284   - this->QPDFValue::setDescription(qpdf, description, offset);
285   - setDictDescription();
286   -}
287   -
288   -void
289   -QPDF_Stream::setDictDescription()
290   -{
291   - if (!this->stream_dict.hasObjectDescription()) {
292   - this->stream_dict.setObjectDescription(qpdf, getDescription() + " -> stream dictionary");
  242 + auto s = stream();
  243 + if (!s->stream_dict.hasObjectDescription()) {
  244 + s->stream_dict.setObjectDescription(
  245 + obj->getQPDF(), obj->getDescription() + " -> stream dictionary");
293 246 }
294 247 }
295 248  
296 249 std::shared_ptr<Buffer>
297 250 Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
298 251 {
299   - auto s = stream();
300 252 Pl_Buffer buf("stream data buffer");
301 253 bool filtered;
302 254 pipeStreamData(&buf, &filtered, 0, decode_level, false, false);
303 255 if (!filtered) {
304 256 throw QPDFExc(
305 257 qpdf_e_unsupported,
306   - s->qpdf->getFilename(),
  258 + obj->getQPDF()->getFilename(),
307 259 "",
308   - s->parsed_offset,
  260 + obj->getParsedOffset(),
309 261 "getStreamData called on unfilterable stream");
310 262 }
311 263 QTC::TC("qpdf", "QPDF_Stream getStreamData");
... ... @@ -315,14 +267,13 @@ Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
315 267 std::shared_ptr<Buffer>
316 268 Stream::getRawStreamData()
317 269 {
318   - auto s = stream();
319 270 Pl_Buffer buf("stream data buffer");
320 271 if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) {
321 272 throw QPDFExc(
322 273 qpdf_e_unsupported,
323   - s->qpdf->getFilename(),
  274 + obj->getQPDF()->getFilename(),
324 275 "",
325   - s->parsed_offset,
  276 + obj->getParsedOffset(),
326 277 "error getting raw stream data");
327 278 }
328 279 QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
... ... @@ -532,12 +483,12 @@ Stream::pipeStreamData(
532 483 Pl_Count count("stream provider count", pipeline);
533 484 if (s->stream_provider->supportsRetry()) {
534 485 if (!s->stream_provider->provideStreamData(
535   - s->og, &count, suppress_warnings, will_retry)) {
  486 + obj->getObjGen(), &count, suppress_warnings, will_retry)) {
536 487 filter = false;
537 488 success = false;
538 489 }
539 490 } else {
540   - s->stream_provider->provideStreamData(s->og, &count);
  491 + s->stream_provider->provideStreamData(obj->getObjGen(), &count);
541 492 }
542 493 qpdf_offset_t actual_length = count.getCount();
543 494 qpdf_offset_t desired_length = 0;
... ... @@ -550,7 +501,7 @@ Stream::pipeStreamData(
550 501 // This would be caused by programmer error on the part of a library user, not by
551 502 // invalid input data.
552 503 throw std::runtime_error(
553   - "stream data provider for " + s->og.unparse(' ') + " provided " +
  504 + "stream data provider for " + obj->getObjGen().unparse(' ') + " provided " +
554 505 std::to_string(actual_length) + " bytes instead of expected " +
555 506 std::to_string(desired_length) + " bytes");
556 507 }
... ... @@ -558,15 +509,15 @@ Stream::pipeStreamData(
558 509 QTC::TC("qpdf", "QPDF_Stream provider length not provided");
559 510 s->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length));
560 511 }
561   - } else if (s->parsed_offset == 0) {
  512 + } else if (obj->getParsedOffset() == 0) {
562 513 QTC::TC("qpdf", "QPDF_Stream pipe no stream data");
563 514 throw std::logic_error("pipeStreamData called for stream with no data");
564 515 } else {
565 516 QTC::TC("qpdf", "QPDF_Stream pipe original stream data");
566 517 if (!QPDF::Pipe::pipeStreamData(
567   - s->qpdf,
568   - s->og,
569   - s->parsed_offset,
  518 + obj->getQPDF(),
  519 + obj->getObjGen(),
  520 + obj->getParsedOffset(),
570 521 s->length,
571 522 s->stream_dict,
572 523 pipeline,
... ... @@ -642,8 +593,7 @@ Stream::replaceFilterData(
642 593 void
643 594 Stream::warn(std::string const& message)
644 595 {
645   - auto s = stream();
646   - s->qpdf->warn(qpdf_e_damaged_pdf, "", s->parsed_offset, message);
  596 + obj->getQPDF()->warn(qpdf_e_damaged_pdf, "", obj->getParsedOffset(), message);
647 597 }
648 598  
649 599 QPDFObjectHandle
... ...
libqpdf/QPDF_String.cc
1   -#include <qpdf/QPDF_String.hh>
  1 +#include <qpdf/QPDFObject_private.hh>
2 2  
3   -#include <qpdf/JSON_writer.hh>
  3 +#include <qpdf/QPDFObjectHandle_private.hh>
4 4 #include <qpdf/QUtil.hh>
5 5  
6 6 // DO NOT USE ctype -- it is locale dependent for some things, and it's not worth the risk of
... ... @@ -12,18 +12,6 @@ is_iso_latin1_printable(char ch)
12 12 return (((ch >= 32) && (ch <= 126)) || (static_cast<unsigned char>(ch) >= 160));
13 13 }
14 14  
15   -QPDF_String::QPDF_String(std::string const& val) :
16   - QPDFValue(::ot_string),
17   - val(val)
18   -{
19   -}
20   -
21   -std::shared_ptr<QPDFObject>
22   -QPDF_String::create(std::string const& val)
23   -{
24   - return do_create(new QPDF_String(val));
25   -}
26   -
27 15 std::shared_ptr<QPDFObject>
28 16 QPDF_String::create_utf16(std::string const& utf8_val)
29 17 {
... ... @@ -31,19 +19,7 @@ QPDF_String::create_utf16(std::string const&amp; utf8_val)
31 19 if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) {
32 20 result = QUtil::utf8_to_utf16(utf8_val);
33 21 }
34   - return do_create(new QPDF_String(result));
35   -}
36   -
37   -std::shared_ptr<QPDFObject>
38   -QPDF_String::copy(bool shallow)
39   -{
40   - return create(val);
41   -}
42   -
43   -std::string
44   -QPDF_String::unparse()
45   -{
46   - return unparse(false);
  22 + return QPDFObject::create<QPDF_String>(result);
47 23 }
48 24  
49 25 void
... ...
libqpdf/QPDF_Unresolved.cc deleted
1   -#include <qpdf/QPDF_Unresolved.hh>
2   -
3   -#include <qpdf/QPDF.hh>
4   -#include <qpdf/QPDFObject_private.hh>
5   -
6   -QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og) :
7   - QPDFValue(::ot_unresolved, qpdf, og)
8   -{
9   -}
10   -
11   -std::shared_ptr<QPDFObject>
12   -QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen og)
13   -{
14   - return do_create(new QPDF_Unresolved(qpdf, og));
15   -}
16   -
17   -std::shared_ptr<QPDFObject>
18   -QPDF_Unresolved::copy(bool shallow)
19   -{
20   - return QPDF::Resolver::resolved(qpdf, og)->copy(shallow);
21   -}
22   -
23   -std::string
24   -QPDF_Unresolved::unparse()
25   -{
26   - return QPDF::Resolver::resolved(qpdf, og)->unparse();
27   -}
28   -
29   -void
30   -QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p)
31   -{
32   - QPDF::Resolver::resolved(qpdf, og)->writeJSON(json_version, p);
33   -}
34   -
35   -std::string
36   -QPDF_Unresolved::getStringValue() const
37   -{
38   - return QPDF::Resolver::resolved(qpdf, og)->getStringValue();
39   -}
libqpdf/QPDF_json.cc
... ... @@ -7,9 +7,6 @@
7 7 #include <qpdf/QIntC.hh>
8 8 #include <qpdf/QPDFObjectHandle_private.hh>
9 9 #include <qpdf/QPDFObject_private.hh>
10   -#include <qpdf/QPDFValue.hh>
11   -#include <qpdf/QPDF_Null.hh>
12   -#include <qpdf/QPDF_Stream.hh>
13 10 #include <qpdf/QTC.hh>
14 11 #include <qpdf/QUtil.hh>
15 12 #include <algorithm>
... ... @@ -239,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor
239 236 is(is),
240 237 must_be_complete(must_be_complete),
241 238 descr(
242   - std::make_shared<QPDFValue::Description>(
243   - QPDFValue::JSON_Descr(std::make_shared<std::string>(is->getName()), "")))
  239 + std::make_shared<QPDFObject::Description>(
  240 + QPDFObject::JSON_Descr(std::make_shared<std::string>(is->getName()), "")))
244 241 {
245 242 }
246 243 ~JSONReactor() override = default;
... ... @@ -287,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor
287 284 QPDF& pdf;
288 285 std::shared_ptr<InputSource> is;
289 286 bool must_be_complete{true};
290   - std::shared_ptr<QPDFValue::Description> descr;
  287 + std::shared_ptr<QPDFObject::Description> descr;
291 288 bool errors{false};
292 289 bool saw_qpdf{false};
293 290 bool saw_qpdf_meta{false};
... ... @@ -577,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
577 574 } else {
578 575 this_stream_needs_data = true;
579 576 replaceObject(
580   - QPDF_Stream::create(
581   - &pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0),
  577 + qpdf::Stream(
  578 + pdf, tos.object.getObjGen(), QPDFObjectHandle::newDictionary(), 0, 0),
582 579 value);
583 580 }
584 581 next_obj = tos.object;
... ... @@ -707,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const&amp; value)
707 704 void
708 705 QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value)
709 706 {
710   - auto j_descr = std::get<QPDFValue::JSON_Descr>(*descr);
  707 + auto j_descr = std::get<QPDFObject::JSON_Descr>(*descr);
711 708 if (j_descr.object != cur_object) {
712   - descr = std::make_shared<QPDFValue::Description>(
713   - QPDFValue::JSON_Descr(j_descr.input, cur_object));
  709 + descr = std::make_shared<QPDFObject::Description>(
  710 + QPDFObject::JSON_Descr(j_descr.input, cur_object));
714 711 }
715 712  
716 713 oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart());
... ...
libqpdf/QPDF_optimization.cc
... ... @@ -5,9 +5,8 @@
5 5 #include <qpdf/QPDF.hh>
6 6  
7 7 #include <qpdf/QPDFExc.hh>
  8 +#include <qpdf/QPDFObjectHandle_private.hh>
8 9 #include <qpdf/QPDFWriter_private.hh>
9   -#include <qpdf/QPDF_Array.hh>
10   -#include <qpdf/QPDF_Dictionary.hh>
11 10 #include <qpdf/QTC.hh>
12 11  
13 12 QPDF::ObjUser::ObjUser() :
... ...
libqpdf/qpdf/QPDFObjectHandle_private.hh
... ... @@ -4,9 +4,7 @@
4 4 #include <qpdf/QPDFObjectHandle.hh>
5 5  
6 6 #include <qpdf/QPDFObject_private.hh>
7   -#include <qpdf/QPDF_Array.hh>
8   -#include <qpdf/QPDF_Dictionary.hh>
9   -#include <qpdf/QPDF_Stream.hh>
  7 +#include <qpdf/QUtil.hh>
10 8  
11 9 namespace qpdf
12 10 {
... ... @@ -106,6 +104,13 @@ namespace qpdf
106 104 {
107 105 }
108 106  
  107 + Stream(
  108 + QPDF& qpdf,
  109 + QPDFObjGen og,
  110 + QPDFObjectHandle stream_dict,
  111 + qpdf_offset_t offset,
  112 + size_t length);
  113 +
109 114 QPDFObjectHandle
110 115 getDict() const
111 116 {
... ... @@ -186,20 +191,22 @@ namespace qpdf
186 191 {
187 192 auto s = stream();
188 193 s->stream_dict = new_dict;
189   - s->setDictDescription();
  194 + setDictDescription();
190 195 }
191 196  
  197 + void setDictDescription();
  198 +
192 199 static void registerStreamFilter(
193 200 std::string const& filter_name,
194 201 std::function<std::shared_ptr<QPDFStreamFilter>()> factory);
195 202  
196 203 private:
197   - QPDF_Stream*
  204 + QPDF_Stream::Members*
198 205 stream() const
199 206 {
200 207 if (obj) {
201 208 if (auto s = obj->as<QPDF_Stream>()) {
202   - return s;
  209 + return s->m.get();
203 210 }
204 211 }
205 212 throw std::runtime_error("operation for stream attempted on object of type dictionary");
... ... @@ -227,6 +234,32 @@ namespace qpdf
227 234  
228 235 } // namespace qpdf
229 236  
  237 +inline QPDF_Dictionary::QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items) :
  238 + items(std::move(items))
  239 +{
  240 +}
  241 +
  242 +inline std::shared_ptr<QPDFObject>
  243 +QPDF_Null::create(
  244 + std::shared_ptr<QPDFObject> parent, std::string_view const& static_descr, std::string var_descr)
  245 +{
  246 + auto n = QPDFObject::create<QPDF_Null>();
  247 + n->setChildDescription(parent->getQPDF(), parent, static_descr, var_descr);
  248 + return n;
  249 +}
  250 +
  251 +inline QPDF_Real::QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes) :
  252 + val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes))
  253 +{
  254 +}
  255 +
  256 +template <typename T, typename... Args>
  257 +inline std::shared_ptr<QPDFObject>
  258 +QPDFObject::create(Args&&... args)
  259 +{
  260 + return std::make_shared<QPDFObject>(std::forward<T>(T(std::forward<Args>(args)...)));
  261 +}
  262 +
230 263 inline qpdf::Array
231 264 QPDFObjectHandle::as_array(qpdf::typed options) const
232 265 {
... ...
libqpdf/qpdf/QPDFObject_private.hh
... ... @@ -6,182 +6,508 @@
6 6  
7 7 #include <qpdf/Constants.h>
8 8 #include <qpdf/JSON.hh>
  9 +#include <qpdf/JSON_writer.hh>
9 10 #include <qpdf/QPDF.hh>
10   -#include <qpdf/QPDFValue.hh>
  11 +#include <qpdf/QPDFObjGen.hh>
11 12 #include <qpdf/Types.h>
12 13  
  14 +#include <map>
  15 +#include <memory>
13 16 #include <string>
14 17 #include <string_view>
  18 +#include <variant>
  19 +#include <vector>
15 20  
16   -class QPDF;
  21 +class QPDFObject;
17 22 class QPDFObjectHandle;
18 23  
19   -class QPDFObject
  24 +namespace qpdf
  25 +{
  26 + class Array;
  27 + class BaseDictionary;
  28 + class Dictionary;
  29 + class Stream;
  30 +} // namespace qpdf
  31 +
  32 +class QPDF_Array final
20 33 {
21   - friend class QPDFValue;
  34 + private:
  35 + struct Sparse
  36 + {
  37 + int size{0};
  38 + std::map<int, std::shared_ptr<QPDFObject>> elements;
  39 + };
22 40  
23 41 public:
24   - QPDFObject() = default;
  42 + QPDF_Array() = default;
  43 + QPDF_Array(QPDF_Array const& other) :
  44 + sp(other.sp ? std::make_unique<Sparse>(*other.sp) : nullptr)
  45 + {
  46 + }
  47 +
  48 + QPDF_Array(QPDF_Array&&) = default;
  49 + QPDF_Array& operator=(QPDF_Array&&) = default;
  50 +
  51 + private:
  52 + friend class QPDFObject;
  53 + friend class qpdf::Array;
  54 + QPDF_Array(std::vector<QPDFObjectHandle> const& items);
  55 + QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse);
25 56  
26   - std::shared_ptr<QPDFObject>
27   - copy(bool shallow = false)
  57 + int
  58 + size() const
28 59 {
29   - return value->copy(shallow);
  60 + return sp ? sp->size : int(elements.size());
30 61 }
31   - std::string
32   - unparse()
  62 + void setFromVector(std::vector<QPDFObjectHandle> const& items);
  63 + void checkOwnership(QPDFObjectHandle const& item) const;
  64 +
  65 + std::unique_ptr<Sparse> sp;
  66 + std::vector<std::shared_ptr<QPDFObject>> elements;
  67 +};
  68 +
  69 +class QPDF_Bool final
  70 +{
  71 + friend class QPDFObject;
  72 + friend class QPDFObjectHandle;
  73 +
  74 + explicit QPDF_Bool(bool val) :
  75 + val(val)
33 76 {
34   - return value->unparse();
35 77 }
36   - void
37   - writeJSON(int json_version, JSON::Writer& p)
  78 + bool val;
  79 +};
  80 +
  81 +class QPDF_Destroyed final
  82 +{
  83 +};
  84 +
  85 +class QPDF_Dictionary final
  86 +{
  87 + friend class QPDFObject;
  88 + friend class qpdf::BaseDictionary;
  89 +
  90 + QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items) :
  91 + items(items)
38 92 {
39   - return value->writeJSON(json_version, p);
40 93 }
41   - std::string
42   - getStringValue() const
  94 + inline QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items);
  95 +
  96 + std::map<std::string, QPDFObjectHandle> items;
  97 +};
  98 +
  99 +class QPDF_InlineImage final
  100 +{
  101 + friend class QPDFObject;
  102 +
  103 + explicit QPDF_InlineImage(std::string val) :
  104 + val(std::move(val))
  105 + {
  106 + }
  107 + std::string val;
  108 +};
  109 +
  110 +class QPDF_Integer final
  111 +{
  112 + friend class QPDFObject;
  113 + friend class QPDFObjectHandle;
  114 +
  115 + QPDF_Integer(long long val) :
  116 + val(val)
  117 + {
  118 + }
  119 + long long val;
  120 +};
  121 +
  122 +class QPDF_Name final
  123 +{
  124 + friend class QPDFObject;
  125 +
  126 + explicit QPDF_Name(std::string name) :
  127 + name(std::move(name))
  128 + {
  129 + }
  130 + std::string name;
  131 +};
  132 +
  133 +class QPDF_Null final
  134 +{
  135 + friend class QPDFObject;
  136 +
  137 + public:
  138 + static inline std::shared_ptr<QPDFObject> create(
  139 + std::shared_ptr<QPDFObject> parent,
  140 + std::string_view const& static_descr,
  141 + std::string var_descr);
  142 +};
  143 +
  144 +class QPDF_Operator final
  145 +{
  146 + friend class QPDFObject;
  147 +
  148 + QPDF_Operator(std::string val) :
  149 + val(std::move(val))
  150 + {
  151 + }
  152 +
  153 + std::string val;
  154 +};
  155 +
  156 +class QPDF_Real final
  157 +{
  158 + friend class QPDFObject;
  159 +
  160 + QPDF_Real(std::string val) :
  161 + val(std::move(val))
  162 + {
  163 + }
  164 + inline QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes);
  165 + // Store reals as strings to avoid roundoff errors.
  166 + std::string val;
  167 +};
  168 +
  169 +class QPDF_Reference
  170 +{
  171 + // This is a minimal implementation to support QPDF::replaceObject. Once we support parsing of
  172 + // objects that are an indirect reference we will need to support multiple levels of
  173 + // indirection, including the possibility of circular references.
  174 + friend class QPDFObject;
  175 +
  176 + QPDF_Reference(std::shared_ptr<QPDFObject> obj) :
  177 + obj(std::move(obj))
  178 + {
  179 + }
  180 +
  181 + std::shared_ptr<QPDFObject> obj;
  182 +};
  183 +
  184 +class QPDF_Reserved final
  185 +{
  186 +};
  187 +
  188 +class QPDF_Stream final
  189 +{
  190 + class Members
  191 + {
  192 + friend class QPDF_Stream;
  193 + friend class QPDFObject;
  194 + friend class qpdf::Stream;
  195 +
  196 + public:
  197 + Members(QPDFObjectHandle stream_dict, size_t length) :
  198 + stream_dict(std::move(stream_dict)),
  199 + length(length)
  200 + {
  201 + }
  202 +
  203 + private:
  204 + void replaceFilterData(
  205 + QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length);
  206 +
  207 + bool filter_on_write{true};
  208 + QPDFObjectHandle stream_dict;
  209 + size_t length{0};
  210 + std::shared_ptr<Buffer> stream_data;
  211 + std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider;
  212 + std::vector<std::shared_ptr<QPDFObjectHandle::TokenFilter>> token_filters;
  213 + };
  214 +
  215 + friend class QPDFObject;
  216 + friend class qpdf::Stream;
  217 +
  218 + QPDF_Stream(QPDFObjectHandle stream_dict, size_t length) :
  219 + m(std::make_unique<Members>(stream_dict, length))
  220 + {
  221 + if (!stream_dict.isDictionary()) {
  222 + throw std::logic_error(
  223 + "stream object instantiated with non-dictionary object for dictionary");
  224 + }
  225 + }
  226 +
  227 + std::unique_ptr<Members> m;
  228 +};
  229 +
  230 +// QPDF_Strings may included embedded null characters.
  231 +class QPDF_String final
  232 +{
  233 + friend class QPDFObject;
  234 + friend class QPDFWriter;
  235 +
  236 + public:
  237 + static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val);
  238 + std::string unparse(bool force_binary = false);
  239 + void writeJSON(int json_version, JSON::Writer& p);
  240 + std::string getUTF8Val() const;
  241 +
  242 + private:
  243 + QPDF_String(std::string val) :
  244 + val(std::move(val))
43 245 {
44   - return value->getStringValue();
45 246 }
  247 + bool useHexString() const;
  248 + std::string val;
  249 +};
  250 +
  251 +class QPDF_Unresolved final
  252 +{
  253 +};
  254 +
  255 +class QPDFObject
  256 +{
  257 + public:
  258 + template <typename T>
  259 + QPDFObject(T&& value) :
  260 + value(std::forward<T>(value))
  261 + {
  262 + }
  263 +
  264 + template <typename T>
  265 + QPDFObject(QPDF* qpdf, QPDFObjGen og, T&& value) :
  266 + value(std::forward<T>(value)),
  267 + qpdf(qpdf),
  268 + og(og)
  269 + {
  270 + }
  271 +
  272 + template <typename T, typename... Args>
  273 + inline static std::shared_ptr<QPDFObject> create(Args&&... args);
  274 +
  275 + template <typename T, typename... Args>
  276 + inline static std::shared_ptr<QPDFObject>
  277 + create(QPDF* qpdf, QPDFObjGen og, Args&&... args)
  278 + {
  279 + return std::make_shared<QPDFObject>(
  280 + qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
  281 + }
  282 +
  283 + std::shared_ptr<QPDFObject> copy(bool shallow = false);
  284 + std::string unparse();
  285 + void write_json(int json_version, JSON::Writer& p);
  286 + void disconnect();
  287 + std::string getStringValue() const;
  288 +
46 289 // Return a unique type code for the resolved object
47 290 qpdf_object_type_e
48 291 getResolvedTypeCode() const
49 292 {
50   - auto tc = value->type_code;
51   - return tc == ::ot_unresolved
52   - ? QPDF::Resolver::resolved(value->qpdf, value->og)->value->type_code
53   - : tc;
  293 + if (getTypeCode() == ::ot_unresolved) {
  294 + return QPDF::Resolver::resolved(qpdf, og)->getTypeCode();
  295 + }
  296 + if (getTypeCode() == ::ot_reference) {
  297 + return std::get<QPDF_Reference>(value).obj->getResolvedTypeCode();
  298 + }
  299 + return getTypeCode();
54 300 }
55 301 // Return a unique type code for the object
56 302 qpdf_object_type_e
57   - getTypeCode() const noexcept
  303 + getTypeCode() const
58 304 {
59   - return value->type_code;
  305 + return static_cast<qpdf_object_type_e>(value.index());
60 306 }
61 307  
62 308 QPDF*
63 309 getQPDF() const
64 310 {
65   - return value->qpdf;
  311 + return qpdf;
66 312 }
67 313 QPDFObjGen
68 314 getObjGen() const
69 315 {
70   - return value->og;
  316 + return og;
71 317 }
72 318 void
73   - setDescription(
74   - QPDF* qpdf, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset = -1)
  319 + assign_null()
75 320 {
76   - return value->setDescription(qpdf, description, offset);
  321 + value = QPDF_Null();
  322 + qpdf = nullptr;
  323 + og = QPDFObjGen();
  324 + object_description = nullptr;
  325 + parsed_offset = -1;
77 326 }
78 327 void
79   - setChildDescription(
80   - std::shared_ptr<QPDFObject> parent,
81   - std::string_view const& static_descr,
82   - std::string var_descr)
  328 + move_to(std::shared_ptr<QPDFObject>& o, bool destroy)
83 329 {
84   - auto qpdf = parent ? parent->value->qpdf : nullptr;
85   - value->setChildDescription(qpdf, parent->value, static_descr, var_descr);
  330 + o->value = std::move(value);
  331 + o->qpdf = qpdf;
  332 + o->og = og;
  333 + o->object_description = object_description;
  334 + o->parsed_offset = parsed_offset;
  335 + if (!destroy) {
  336 + value = QPDF_Reference(o);
  337 + }
86 338 }
87 339 void
88   - setChildDescription(
89   - std::shared_ptr<QPDFValue> parent,
90   - std::string_view const& static_descr,
91   - std::string var_descr)
  340 + swapWith(std::shared_ptr<QPDFObject> o)
92 341 {
93   - auto qpdf = parent ? parent->qpdf : nullptr;
94   - value->setChildDescription(qpdf, parent, static_descr, var_descr);
  342 + std::swap(value, o->value);
  343 + std::swap(qpdf, o->qpdf);
  344 + std::swap(object_description, o->object_description);
  345 + std::swap(parsed_offset, o->parsed_offset);
95 346 }
96   - bool
97   - getDescription(QPDF*& qpdf, std::string& description)
  347 +
  348 + void
  349 + setObjGen(QPDF* a_qpdf, QPDFObjGen a_og)
98 350 {
99   - qpdf = value->qpdf;
100   - description = value->getDescription();
101   - return qpdf != nullptr;
  351 + qpdf = a_qpdf;
  352 + og = a_og;
102 353 }
103   - bool
104   - hasDescription()
  354 + // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects.
  355 + void
  356 + destroy()
105 357 {
106   - return value->hasDescription();
  358 + value = QPDF_Destroyed();
107 359 }
108   - void
109   - setParsedOffset(qpdf_offset_t offset)
  360 +
  361 + bool
  362 + isUnresolved() const
110 363 {
111   - value->setParsedOffset(offset);
  364 + return getTypeCode() == ::ot_unresolved;
112 365 }
113   - qpdf_offset_t
114   - getParsedOffset()
  366 + const QPDFObject*
  367 + resolved_object() const
115 368 {
116   - return value->getParsedOffset();
  369 + return isUnresolved() ? QPDF::Resolver::resolved(qpdf, og) : this;
117 370 }
  371 +
  372 + struct JSON_Descr
  373 + {
  374 + JSON_Descr(std::shared_ptr<std::string> input, std::string const& object) :
  375 + input(input),
  376 + object(object)
  377 + {
  378 + }
  379 +
  380 + std::shared_ptr<std::string> input;
  381 + std::string object;
  382 + };
  383 +
  384 + struct ChildDescr
  385 + {
  386 + ChildDescr(
  387 + std::shared_ptr<QPDFObject> parent,
  388 + std::string_view const& static_descr,
  389 + std::string var_descr) :
  390 + parent(parent),
  391 + static_descr(static_descr),
  392 + var_descr(var_descr)
  393 + {
  394 + }
  395 +
  396 + std::weak_ptr<QPDFObject> parent;
  397 + std::string_view const& static_descr;
  398 + std::string var_descr;
  399 + };
  400 +
  401 + using Description = std::variant<std::string, JSON_Descr, ChildDescr>;
  402 +
118 403 void
119   - assign(std::shared_ptr<QPDFObject> o)
  404 + setDescription(
  405 + QPDF* qpdf_p, std::shared_ptr<Description>& description, qpdf_offset_t offset = -1)
120 406 {
121   - value = o->value;
  407 + qpdf = qpdf_p;
  408 + object_description = description;
  409 + setParsedOffset(offset);
122 410 }
123 411 void
124   - swapWith(std::shared_ptr<QPDFObject> o)
  412 + setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og)
125 413 {
126   - auto v = value;
127   - value = o->value;
128   - o->value = v;
129   - auto og = value->og;
130   - value->og = o->value->og;
131   - o->value->og = og;
  414 + qpdf = a_qpdf;
  415 + og = a_og;
132 416 }
133   -
134 417 void
135   - setDefaultDescription(QPDF* qpdf, QPDFObjGen og)
  418 + setChildDescription(
  419 + QPDF* a_qpdf,
  420 + std::shared_ptr<QPDFObject> parent,
  421 + std::string_view const& static_descr,
  422 + std::string var_descr)
136 423 {
137   - // Intended for use by the QPDF class
138   - value->setDefaultDescription(qpdf, og);
  424 + object_description =
  425 + std::make_shared<Description>(ChildDescr(parent, static_descr, var_descr));
  426 + qpdf = a_qpdf;
139 427 }
140   - void
141   - setObjGen(QPDF* qpdf, QPDFObjGen og)
  428 + std::string getDescription();
  429 + bool
  430 + hasDescription()
142 431 {
143   - value->qpdf = qpdf;
144   - value->og = og;
  432 + return object_description || og.isIndirect();
145 433 }
146 434 void
147   - disconnect()
  435 + setParsedOffset(qpdf_offset_t offset)
148 436 {
149   - // Disconnect an object from its owning QPDF. This is called by QPDF's destructor.
150   - value->disconnect();
151   - value->qpdf = nullptr;
152   - value->og = QPDFObjGen();
  437 + if (parsed_offset < 0) {
  438 + parsed_offset = offset;
  439 + }
153 440 }
154   - // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects.
155   - void destroy();
156   -
157 441 bool
158   - isUnresolved() const
  442 + getDescription(QPDF*& a_qpdf, std::string& description)
159 443 {
160   - return value->type_code == ::ot_unresolved;
  444 + a_qpdf = qpdf;
  445 + description = getDescription();
  446 + return qpdf != nullptr;
161 447 }
162   - const QPDFObject*
163   - resolved_object() const
  448 + qpdf_offset_t
  449 + getParsedOffset()
164 450 {
165   - return isUnresolved() ? QPDF::Resolver::resolved(value->qpdf, value->og) : this;
  451 + return parsed_offset;
  452 + }
  453 + QPDF*
  454 + getQPDF()
  455 + {
  456 + return qpdf;
  457 + }
  458 + QPDFObjGen
  459 + getObjGen()
  460 + {
  461 + return og;
166 462 }
167 463  
168 464 template <typename T>
169 465 T*
170   - as() const
171   - {
172   - if (auto result = dynamic_cast<T*>(value.get())) {
173   - return result;
174   - } else {
175   - return isUnresolved()
176   - ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get())
177   - : nullptr;
  466 + as()
  467 + {
  468 + if (std::holds_alternative<T>(value)) {
  469 + return &std::get<T>(value);
178 470 }
  471 + if (std::holds_alternative<QPDF_Unresolved>(value)) {
  472 + return QPDF::Resolver::resolved(qpdf, og)->as<T>();
  473 + }
  474 + if (std::holds_alternative<QPDF_Reference>(value)) {
  475 + // see comment in QPDF_Reference.
  476 + return std::get<QPDF_Reference>(value).obj->as<T>();
  477 + }
  478 + return nullptr;
179 479 }
180 480  
181 481 private:
  482 + friend class QPDF_Stream;
  483 + typedef std::variant<
  484 + std::monostate,
  485 + QPDF_Reserved,
  486 + QPDF_Null,
  487 + QPDF_Bool,
  488 + QPDF_Integer,
  489 + QPDF_Real,
  490 + QPDF_String,
  491 + QPDF_Name,
  492 + QPDF_Array,
  493 + QPDF_Dictionary,
  494 + QPDF_Stream,
  495 + QPDF_Operator,
  496 + QPDF_InlineImage,
  497 + QPDF_Unresolved,
  498 + QPDF_Destroyed,
  499 + QPDF_Reference>
  500 + Value;
  501 + Value value;
  502 +
182 503 QPDFObject(QPDFObject const&) = delete;
183 504 QPDFObject& operator=(QPDFObject const&) = delete;
184   - std::shared_ptr<QPDFValue> value;
  505 +
  506 + std::shared_ptr<Description> object_description;
  507 +
  508 + QPDF* qpdf{nullptr};
  509 + QPDFObjGen og{};
  510 + qpdf_offset_t parsed_offset{-1};
185 511 };
186 512  
187 513 #endif // QPDFOBJECT_HH
... ...
libqpdf/qpdf/QPDFParser.hh
1 1 #ifndef QPDFPARSER_HH
2 2 #define QPDFPARSER_HH
3 3  
4   -#include <qpdf/QPDFObjectHandle.hh>
5   -#include <qpdf/QPDFValue.hh>
  4 +#include <qpdf/QPDFObjectHandle_private.hh>
  5 +#include <qpdf/QPDFObject_private.hh>
6 6  
7 7 #include <memory>
8 8 #include <string>
... ... @@ -24,7 +24,7 @@ class QPDFParser
24 24 decrypter(decrypter),
25 25 context(context),
26 26 description(
27   - std::make_shared<QPDFValue::Description>(
  27 + std::make_shared<QPDFObject::Description>(
28 28 std::string(input.getName() + ", " + object_description + " at offset $PO"))),
29 29 parse_pdf(parse_pdf)
30 30 {
... ... @@ -78,7 +78,7 @@ class QPDFParser
78 78 QPDFTokenizer& tokenizer;
79 79 QPDFObjectHandle::StringDecrypter* decrypter;
80 80 QPDF* context;
81   - std::shared_ptr<QPDFValue::Description> description;
  81 + std::shared_ptr<QPDFObject::Description> description;
82 82 bool parse_pdf;
83 83  
84 84 std::vector<StackFrame> stack;
... ...
libqpdf/qpdf/QPDFValue.hh deleted
1   -#ifndef QPDFVALUE_HH
2   -#define QPDFVALUE_HH
3   -
4   -#include <qpdf/Constants.h>
5   -#include <qpdf/DLL.h>
6   -#include <qpdf/JSON.hh>
7   -#include <qpdf/QPDFObjGen.hh>
8   -#include <qpdf/Types.h>
9   -
10   -#include <string>
11   -#include <string_view>
12   -#include <variant>
13   -
14   -class QPDF;
15   -class QPDFObjectHandle;
16   -class QPDFObject;
17   -
18   -class QPDFValue: public std::enable_shared_from_this<QPDFValue>
19   -{
20   - friend class QPDFObject;
21   -
22   - public:
23   - virtual ~QPDFValue() = default;
24   -
25   - virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0;
26   - virtual std::string unparse() = 0;
27   - virtual void writeJSON(int json_version, JSON::Writer& p) = 0;
28   -
29   - struct JSON_Descr
30   - {
31   - JSON_Descr(std::shared_ptr<std::string> input, std::string const& object) :
32   - input(input),
33   - object(object)
34   - {
35   - }
36   -
37   - std::shared_ptr<std::string> input;
38   - std::string object;
39   - };
40   -
41   - struct ChildDescr
42   - {
43   - ChildDescr(
44   - std::shared_ptr<QPDFValue> parent,
45   - std::string_view const& static_descr,
46   - std::string var_descr) :
47   - parent(parent),
48   - static_descr(static_descr),
49   - var_descr(var_descr)
50   - {
51   - }
52   -
53   - std::weak_ptr<QPDFValue> parent;
54   - std::string_view const& static_descr;
55   - std::string var_descr;
56   - };
57   -
58   - using Description = std::variant<std::string, JSON_Descr, ChildDescr>;
59   -
60   - virtual void
61   - setDescription(QPDF* qpdf_p, std::shared_ptr<Description>& description, qpdf_offset_t offset)
62   - {
63   - qpdf = qpdf_p;
64   - object_description = description;
65   - setParsedOffset(offset);
66   - }
67   - void
68   - setDefaultDescription(QPDF* a_qpdf, QPDFObjGen a_og)
69   - {
70   - qpdf = a_qpdf;
71   - og = a_og;
72   - }
73   - void
74   - setChildDescription(
75   - QPDF* a_qpdf,
76   - std::shared_ptr<QPDFValue> parent,
77   - std::string_view const& static_descr,
78   - std::string var_descr)
79   - {
80   - object_description =
81   - std::make_shared<Description>(ChildDescr(parent, static_descr, var_descr));
82   - qpdf = a_qpdf;
83   - }
84   - std::string getDescription();
85   - bool
86   - hasDescription()
87   - {
88   - return object_description || og.isIndirect();
89   - }
90   - void
91   - setParsedOffset(qpdf_offset_t offset)
92   - {
93   - if (parsed_offset < 0) {
94   - parsed_offset = offset;
95   - }
96   - }
97   - qpdf_offset_t
98   - getParsedOffset()
99   - {
100   - return parsed_offset;
101   - }
102   - QPDF*
103   - getQPDF()
104   - {
105   - return qpdf;
106   - }
107   - QPDFObjGen
108   - getObjGen()
109   - {
110   - return og;
111   - }
112   - virtual void
113   - disconnect()
114   - {
115   - }
116   - virtual std::string
117   - getStringValue() const
118   - {
119   - return "";
120   - }
121   -
122   - protected:
123   - QPDFValue() = default;
124   -
125   - QPDFValue(qpdf_object_type_e type_code) :
126   - type_code(type_code)
127   - {
128   - }
129   - QPDFValue(qpdf_object_type_e type_code, QPDF* qpdf, QPDFObjGen og) :
130   - type_code(type_code),
131   - qpdf(qpdf),
132   - og(og)
133   - {
134   - }
135   -
136   - static std::shared_ptr<QPDFObject> do_create(QPDFValue*);
137   -
138   - private:
139   - QPDFValue(QPDFValue const&) = delete;
140   - QPDFValue& operator=(QPDFValue const&) = delete;
141   - std::shared_ptr<Description> object_description;
142   -
143   - const qpdf_object_type_e type_code{::ot_uninitialized};
144   -
145   - protected:
146   - QPDF* qpdf{nullptr};
147   - QPDFObjGen og{};
148   - qpdf_offset_t parsed_offset{-1};
149   -};
150   -
151   -#endif // QPDFVALUE_HH
libqpdf/qpdf/QPDF_Array.hh deleted
1   -#ifndef QPDF_ARRAY_HH
2   -#define QPDF_ARRAY_HH
3   -
4   -#include <qpdf/QPDFObjectHandle.hh>
5   -#include <qpdf/QPDFObject_private.hh>
6   -#include <qpdf/QPDFValue.hh>
7   -
8   -#include <map>
9   -#include <vector>
10   -
11   -class QPDF_Array: public QPDFValue
12   -{
13   - private:
14   - struct Sparse
15   - {
16   - int size{0};
17   - std::map<int, std::shared_ptr<QPDFObject>> elements;
18   - };
19   -
20   - public:
21   - ~QPDF_Array() override = default;
22   - static std::shared_ptr<QPDFObject> create(std::vector<QPDFObjectHandle> const& items);
23   - static std::shared_ptr<QPDFObject>
24   - create(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse);
25   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
26   - std::string unparse() override;
27   - void writeJSON(int json_version, JSON::Writer& p) override;
28   - void disconnect() override;
29   -
30   - private:
31   - friend class qpdf::Array;
32   - QPDF_Array();
33   - QPDF_Array(QPDF_Array const&);
34   - QPDF_Array(std::vector<QPDFObjectHandle> const& items);
35   - QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& items, bool sparse);
36   -
37   - int
38   - size() const
39   - {
40   - return sp ? sp->size : int(elements.size());
41   - }
42   - void setFromVector(std::vector<QPDFObjectHandle> const& items);
43   -
44   - void checkOwnership(QPDFObjectHandle const& item) const;
45   -
46   - std::unique_ptr<Sparse> sp;
47   - std::vector<std::shared_ptr<QPDFObject>> elements;
48   -};
49   -
50   -#endif // QPDF_ARRAY_HH
libqpdf/qpdf/QPDF_Bool.hh deleted
1   -#ifndef QPDF_BOOL_HH
2   -#define QPDF_BOOL_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Bool: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Bool() override = default;
10   - static std::shared_ptr<QPDFObject> create(bool val);
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   -
15   - bool getVal() const;
16   -
17   - private:
18   - QPDF_Bool(bool val);
19   - bool val;
20   -};
21   -
22   -#endif // QPDF_BOOL_HH
libqpdf/qpdf/QPDF_Destroyed.hh deleted
1   -#ifndef QPDF_DESTROYED_HH
2   -#define QPDF_DESTROYED_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Destroyed: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Destroyed() override = default;
10   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
11   - std::string unparse() override;
12   - void writeJSON(int json_version, JSON::Writer& p) override;
13   - static std::shared_ptr<QPDFValue> getInstance();
14   -
15   - private:
16   - QPDF_Destroyed();
17   -};
18   -
19   -#endif // QPDF_DESTROYED_HH
libqpdf/qpdf/QPDF_Dictionary.hh deleted
1   -#ifndef QPDF_DICTIONARY_HH
2   -#define QPDF_DICTIONARY_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -#include <map>
7   -#include <set>
8   -
9   -#include <qpdf/QPDFExc.hh>
10   -#include <qpdf/QPDFObjectHandle.hh>
11   -#include <qpdf/QPDFObject_private.hh>
12   -#include <qpdf/QPDF_Null.hh>
13   -
14   -class QPDF_Dictionary: public QPDFValue
15   -{
16   - public:
17   - ~QPDF_Dictionary() override = default;
18   - static std::shared_ptr<QPDFObject> create(std::map<std::string, QPDFObjectHandle> const& items);
19   - static std::shared_ptr<QPDFObject> create(std::map<std::string, QPDFObjectHandle>&& items);
20   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
21   - std::string unparse() override;
22   - void writeJSON(int json_version, JSON::Writer& p) override;
23   - void disconnect() override;
24   -
25   - private:
26   - friend class qpdf::BaseDictionary;
27   -
28   - QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items);
29   - QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items);
30   -
31   - std::map<std::string, QPDFObjectHandle> items;
32   -};
33   -
34   -#endif // QPDF_DICTIONARY_HH
libqpdf/qpdf/QPDF_InlineImage.hh deleted
1   -#ifndef QPDF_INLINEIMAGE_HH
2   -#define QPDF_INLINEIMAGE_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_InlineImage: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_InlineImage() override = default;
10   - static std::shared_ptr<QPDFObject> create(std::string const& val);
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   - std::string
15   - getStringValue() const override
16   - {
17   - return val;
18   - }
19   -
20   - private:
21   - QPDF_InlineImage(std::string const& val);
22   - std::string val;
23   -};
24   -
25   -#endif // QPDF_INLINEIMAGE_HH
libqpdf/qpdf/QPDF_Integer.hh deleted
1   -#ifndef QPDF_INTEGER_HH
2   -#define QPDF_INTEGER_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Integer: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Integer() override = default;
10   - static std::shared_ptr<QPDFObject> create(long long value);
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   - long long getVal() const;
15   -
16   - private:
17   - QPDF_Integer(long long val);
18   - long long val;
19   -};
20   -
21   -#endif // QPDF_INTEGER_HH
libqpdf/qpdf/QPDF_Name.hh
1   -#ifndef QPDF_NAME_HH
2   -#define QPDF_NAME_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Name: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Name() override = default;
10   - static std::shared_ptr<QPDFObject> create(std::string const& name);
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   - std::string
15   - getStringValue() const override
16   - {
17   - return name;
18   - }
19   -
20   - private:
21   - QPDF_Name(std::string const& name);
22   - std::string name;
23   -};
24   -
25   -#endif // QPDF_NAME_HH
libqpdf/qpdf/QPDF_Null.hh deleted
1   -#ifndef QPDF_NULL_HH
2   -#define QPDF_NULL_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Null: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Null() override = default;
10   - static std::shared_ptr<QPDFObject> create(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen());
11   - static std::shared_ptr<QPDFObject> create(
12   - std::shared_ptr<QPDFObject> parent,
13   - std::string_view const& static_descr,
14   - std::string var_descr);
15   - static std::shared_ptr<QPDFObject> create(
16   - std::shared_ptr<QPDFValue> parent,
17   - std::string_view const& static_descr,
18   - std::string var_descr);
19   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
20   - std::string unparse() override;
21   - void writeJSON(int json_version, JSON::Writer& p) override;
22   -
23   - private:
24   - QPDF_Null(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen());
25   -};
26   -
27   -#endif // QPDF_NULL_HH
libqpdf/qpdf/QPDF_Operator.hh deleted
1   -#ifndef QPDF_OPERATOR_HH
2   -#define QPDF_OPERATOR_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Operator: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Operator() override = default;
10   - static std::shared_ptr<QPDFObject> create(std::string const& val);
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   - std::string
15   - getStringValue() const override
16   - {
17   - return val;
18   - }
19   -
20   - private:
21   - QPDF_Operator(std::string const& val);
22   - std::string val;
23   -};
24   -
25   -#endif // QPDF_OPERATOR_HH
libqpdf/qpdf/QPDF_Real.hh deleted
1   -#ifndef QPDF_REAL_HH
2   -#define QPDF_REAL_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Real: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Real() override = default;
10   - static std::shared_ptr<QPDFObject> create(std::string const& val);
11   - static std::shared_ptr<QPDFObject>
12   - create(double value, int decimal_places, bool trim_trailing_zeroes);
13   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
14   - std::string unparse() override;
15   - void writeJSON(int json_version, JSON::Writer& p) override;
16   - std::string
17   - getStringValue() const override
18   - {
19   - return val;
20   - }
21   -
22   - private:
23   - QPDF_Real(std::string const& val);
24   - QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes);
25   - // Store reals as strings to avoid roundoff errors.
26   - std::string val;
27   -};
28   -
29   -#endif // QPDF_REAL_HH
libqpdf/qpdf/QPDF_Reserved.hh deleted
1   -#ifndef QPDF_RESERVED_HH
2   -#define QPDF_RESERVED_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Reserved: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Reserved() override = default;
10   - static std::shared_ptr<QPDFObject> create();
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   -
15   - private:
16   - QPDF_Reserved();
17   -};
18   -
19   -#endif // QPDF_RESERVED_HH
libqpdf/qpdf/QPDF_Stream.hh deleted
1   -#ifndef QPDF_STREAM_HH
2   -#define QPDF_STREAM_HH
3   -
4   -#include <qpdf/Types.h>
5   -
6   -#include <qpdf/QPDFObjectHandle.hh>
7   -#include <qpdf/QPDFObject_private.hh>
8   -#include <qpdf/QPDFStreamFilter.hh>
9   -#include <qpdf/QPDFValue.hh>
10   -
11   -#include <functional>
12   -#include <memory>
13   -
14   -class Pipeline;
15   -class QPDF;
16   -
17   -class QPDF_Stream final: public QPDFValue
18   -{
19   - public:
20   - ~QPDF_Stream() final = default;
21   - static std::shared_ptr<QPDFObject>
22   - create(QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length);
23   - std::shared_ptr<QPDFObject> copy(bool shallow = false) final;
24   - std::string unparse() final;
25   - void writeJSON(int json_version, JSON::Writer& p) final;
26   - void setDescription(
27   - QPDF*, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) final;
28   - void disconnect() final;
29   -
30   - private:
31   - friend class qpdf::Stream;
32   -
33   - QPDF_Stream(
34   - QPDF*, QPDFObjGen og, QPDFObjectHandle stream_dict, qpdf_offset_t offset, size_t length);
35   -
36   - void replaceFilterData(
37   - QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms, size_t length);
38   - void setDictDescription();
39   -
40   - bool filter_on_write;
41   - QPDFObjectHandle stream_dict;
42   - size_t length;
43   - std::shared_ptr<Buffer> stream_data;
44   - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider;
45   - std::vector<std::shared_ptr<QPDFObjectHandle::TokenFilter>> token_filters;
46   -};
47   -
48   -#endif // QPDF_STREAM_HH
libqpdf/qpdf/QPDF_String.hh deleted
1   -#ifndef QPDF_STRING_HH
2   -#define QPDF_STRING_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -// QPDF_Strings may included embedded null characters.
7   -
8   -class QPDF_String: public QPDFValue
9   -{
10   - friend class QPDFWriter;
11   -
12   - public:
13   - ~QPDF_String() override = default;
14   - static std::shared_ptr<QPDFObject> create(std::string const& val);
15   - static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val);
16   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
17   - std::string unparse() override;
18   - std::string unparse(bool force_binary);
19   - void writeJSON(int json_version, JSON::Writer& p) override;
20   - std::string getUTF8Val() const;
21   - std::string
22   - getStringValue() const override
23   - {
24   - return val;
25   - }
26   -
27   - private:
28   - QPDF_String(std::string const& val);
29   - bool useHexString() const;
30   - std::string val;
31   -};
32   -
33   -#endif // QPDF_STRING_HH
libqpdf/qpdf/QPDF_Unresolved.hh deleted
1   -#ifndef QPDF_UNRESOLVED_HH
2   -#define QPDF_UNRESOLVED_HH
3   -
4   -#include <qpdf/QPDFValue.hh>
5   -
6   -class QPDF_Unresolved: public QPDFValue
7   -{
8   - public:
9   - ~QPDF_Unresolved() override = default;
10   - static std::shared_ptr<QPDFObject> create(QPDF* qpdf, QPDFObjGen og);
11   - std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12   - std::string unparse() override;
13   - void writeJSON(int json_version, JSON::Writer& p) override;
14   - std::string getStringValue() const override;
15   -
16   - private:
17   - QPDF_Unresolved(QPDF* qpdf, QPDFObjGen og);
18   -};
19   -
20   -#endif // QPDF_UNRESOLVED_HH
libtests/sparse_array.cc
... ... @@ -3,14 +3,13 @@
3 3 #include <qpdf/QPDF.hh>
4 4 #include <qpdf/QPDFObjectHandle_private.hh>
5 5 #include <qpdf/QPDFObject_private.hh>
6   -#include <qpdf/QPDF_Array.hh>
7 6  
8 7 #include <iostream>
9 8  
10 9 int
11 10 main()
12 11 {
13   - auto obj = QPDF_Array::create({}, true);
  12 + auto obj = QPDFObject::create<QPDF_Array>(std::vector<std::shared_ptr<QPDFObject>>(), true);
14 13 auto a = qpdf::Array(obj);
15 14  
16 15 assert(a.size() == 0);
... ... @@ -88,7 +87,8 @@ main()
88 87 QPDF pdf;
89 88 pdf.emptyPDF();
90 89  
91   - obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true);
  90 + obj = QPDFObject::create<QPDF_Array>(
  91 + std::vector<std::shared_ptr<QPDFObject>>{10, "null"_qpdf.getObj()}, true);
92 92 auto b = qpdf::Array(obj);
93 93 b.setAt(5, pdf.newIndirectNull());
94 94 b.setAt(7, "[0 1 2 3]"_qpdf);
... ...