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,6 +126,7 @@ enum qpdf_object_type_e {
126 /* Object types internal to qpdf */ 126 /* Object types internal to qpdf */
127 ot_unresolved, 127 ot_unresolved,
128 ot_destroyed, 128 ot_destroyed,
  129 + ot_reference,
129 }; 130 };
130 131
131 /* Write Parameters. See QPDFWriter.hh for details. */ 132 /* Write Parameters. See QPDFWriter.hh for details. */
include/qpdf/QPDF.hh
@@ -1087,7 +1087,8 @@ class QPDF @@ -1087,7 +1087,8 @@ class QPDF
1087 QPDFObjGen og, 1087 QPDFObjGen og,
1088 std::shared_ptr<QPDFObject> const& object, 1088 std::shared_ptr<QPDFObject> const& object,
1089 qpdf_offset_t end_before_space, 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 static QPDFExc damagedPDF( 1092 static QPDFExc damagedPDF(
1092 InputSource& input, 1093 InputSource& input,
1093 std::string const& object, 1094 std::string const& object,
include/qpdf/QPDFObjectHandle.hh
@@ -1254,8 +1254,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle @@ -1254,8 +1254,7 @@ class QPDFObjectHandle final: public qpdf::BaseHandle
1254 // Provide access to specific classes for recursive disconnected(). 1254 // Provide access to specific classes for recursive disconnected().
1255 class DisconnectAccess 1255 class DisconnectAccess
1256 { 1256 {
1257 - friend class QPDF_Dictionary;  
1258 - friend class QPDF_Stream; 1257 + friend class QPDFObject;
1259 1258
1260 private: 1259 private:
1261 static void 1260 static void
include/qpdf/QPDFObjectHandle_future.hh deleted
libqpdf/CMakeLists.txt
@@ -86,23 +86,12 @@ set(libqpdf_SOURCES @@ -86,23 +86,12 @@ set(libqpdf_SOURCES
86 QPDFSystemError.cc 86 QPDFSystemError.cc
87 QPDFTokenizer.cc 87 QPDFTokenizer.cc
88 QPDFUsage.cc 88 QPDFUsage.cc
89 - QPDFValue.cc  
90 QPDFWriter.cc 89 QPDFWriter.cc
91 QPDFXRefEntry.cc 90 QPDFXRefEntry.cc
92 QPDF_Array.cc 91 QPDF_Array.cc
93 - QPDF_Bool.cc  
94 - QPDF_Destroyed.cc  
95 QPDF_Dictionary.cc 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 QPDF_Stream.cc 93 QPDF_Stream.cc
104 QPDF_String.cc 94 QPDF_String.cc
105 - QPDF_Unresolved.cc  
106 QPDF_encryption.cc 95 QPDF_encryption.cc
107 QPDF_json.cc 96 QPDF_json.cc
108 QPDF_linearization.cc 97 QPDF_linearization.cc
libqpdf/QPDF.cc
@@ -20,11 +20,6 @@ @@ -20,11 +20,6 @@
20 #include <qpdf/QPDFObjectHandle_private.hh> 20 #include <qpdf/QPDFObjectHandle_private.hh>
21 #include <qpdf/QPDFObject_private.hh> 21 #include <qpdf/QPDFObject_private.hh>
22 #include <qpdf/QPDFParser.hh> 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 #include <qpdf/QTC.hh> 23 #include <qpdf/QTC.hh>
29 #include <qpdf/QUtil.hh> 24 #include <qpdf/QUtil.hh>
30 25
@@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle&amp; object, QPDFObjGen og, qpdf_offset_t offset) @@ -1565,7 +1560,7 @@ QPDF::readStream(QPDFObjectHandle&amp; object, QPDFObjGen og, qpdf_offset_t offset)
1565 throw; 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 void 1566 void
@@ -1884,7 +1879,7 @@ QPDF::resolve(QPDFObjGen og) @@ -1884,7 +1879,7 @@ QPDF::resolve(QPDFObjGen og)
1884 // has to be resolved during object parsing, such as stream length. 1879 // has to be resolved during object parsing, such as stream length.
1885 QTC::TC("qpdf", "QPDF recursion loop in resolve"); 1880 QTC::TC("qpdf", "QPDF recursion loop in resolve");
1886 warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); 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 return m->obj_cache[og].object.get(); 1883 return m->obj_cache[og].object.get();
1889 } 1884 }
1890 ResolveRecorder rr(this, og); 1885 ResolveRecorder rr(this, og);
@@ -1921,7 +1916,7 @@ QPDF::resolve(QPDFObjGen og) @@ -1921,7 +1916,7 @@ QPDF::resolve(QPDFObjGen og)
1921 if (isUnresolved(og)) { 1916 if (isUnresolved(og)) {
1922 // PDF spec says unknown objects resolve to the null object. 1917 // PDF spec says unknown objects resolve to the null object.
1923 QTC::TC("qpdf", "QPDF resolve failure to null"); 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 auto result(m->obj_cache[og].object); 1922 auto result(m->obj_cache[og].object);
@@ -2034,12 +2029,13 @@ QPDF::updateCache( @@ -2034,12 +2029,13 @@ QPDF::updateCache(
2034 QPDFObjGen og, 2029 QPDFObjGen og,
2035 std::shared_ptr<QPDFObject> const& object, 2030 std::shared_ptr<QPDFObject> const& object,
2036 qpdf_offset_t end_before_space, 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 object->setObjGen(this, og); 2035 object->setObjGen(this, og);
2040 if (isCached(og)) { 2036 if (isCached(og)) {
2041 auto& cache = m->obj_cache[og]; 2037 auto& cache = m->obj_cache[og];
2042 - cache.object->assign(object); 2038 + object->move_to(cache.object, destroy);
2043 cache.end_before_space = end_before_space; 2039 cache.end_before_space = end_before_space;
2044 cache.end_after_space = end_after_space; 2040 cache.end_after_space = end_after_space;
2045 } else { 2041 } else {
@@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) @@ -2089,20 +2085,20 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh)
2089 QPDFObjectHandle 2085 QPDFObjectHandle
2090 QPDF::newReserved() 2086 QPDF::newReserved()
2091 { 2087 {
2092 - return makeIndirectFromQPDFObject(QPDF_Reserved::create()); 2088 + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Reserved>());
2093 } 2089 }
2094 2090
2095 QPDFObjectHandle 2091 QPDFObjectHandle
2096 QPDF::newIndirectNull() 2092 QPDF::newIndirectNull()
2097 { 2093 {
2098 - return makeIndirectFromQPDFObject(QPDF_Null::create()); 2094 + return makeIndirectFromQPDFObject(QPDFObject::create<QPDF_Null>());
2099 } 2095 }
2100 2096
2101 QPDFObjectHandle 2097 QPDFObjectHandle
2102 QPDF::newStream() 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 QPDFObjectHandle 2104 QPDFObjectHandle
@@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf) @@ -2130,12 +2126,13 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
2130 return iter->second.object; 2126 return iter->second.object;
2131 } 2127 }
2132 if (m->xref_table.count(og) || !m->parsed) { 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 if (parse_pdf) { 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 std::shared_ptr<QPDFObject> 2138 std::shared_ptr<QPDFObject>
@@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen) @@ -2145,8 +2142,9 @@ QPDF::getObjectForJSON(int id, int gen)
2145 auto [it, inserted] = m->obj_cache.try_emplace(og); 2142 auto [it, inserted] = m->obj_cache.try_emplace(og);
2146 auto& obj = it->second.object; 2143 auto& obj = it->second.object;
2147 if (inserted) { 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 return obj; 2149 return obj;
2152 } 2150 }
@@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og) @@ -2157,9 +2155,10 @@ QPDF::getObject(QPDFObjGen og)
2157 if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { 2155 if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
2158 return {it->second.object}; 2156 return {it->second.object};
2159 } else if (m->parsed && !m->xref_table.count(og)) { 2157 } else if (m->parsed && !m->xref_table.count(og)) {
2160 - return QPDF_Null::create(); 2158 + return QPDFObject::create<QPDF_Null>();
2161 } else { 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 return {result.first->second.object}; 2162 return {result.first->second.object};
2164 } 2163 }
2165 } 2164 }
@@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh) @@ -2195,7 +2194,7 @@ QPDF::replaceObject(QPDFObjGen og, QPDFObjectHandle oh)
2195 QTC::TC("qpdf", "QPDF replaceObject called with indirect object"); 2194 QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
2196 throw std::logic_error("QPDF::replaceObject called with indirect object handle"); 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 void 2200 void
@@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og) @@ -2204,7 +2203,7 @@ QPDF::removeObject(QPDFObjGen og)
2204 m->xref_table.erase(og); 2203 m->xref_table.erase(og);
2205 if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) { 2204 if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) {
2206 // Take care of any object handles that may be floating around. 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 cached->second.object->setObjGen(nullptr, QPDFObjGen()); 2207 cached->second.object->setObjGen(nullptr, QPDFObjGen());
2209 m->obj_cache.erase(cached); 2208 m->obj_cache.erase(cached);
2210 } 2209 }
libqpdf/QPDFObject.cc
1 #include <qpdf/QPDFObject_private.hh> 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,19 +11,6 @@
11 #include <qpdf/QPDFObject_private.hh> 11 #include <qpdf/QPDFObject_private.hh>
12 #include <qpdf/QPDFPageObjectHelper.hh> 12 #include <qpdf/QPDFPageObjectHelper.hh>
13 #include <qpdf/QPDFParser.hh> 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 #include <qpdf/QIntC.hh> 15 #include <qpdf/QIntC.hh>
29 #include <qpdf/QTC.hh> 16 #include <qpdf/QTC.hh>
@@ -228,6 +215,443 @@ LastChar::getLastChar() @@ -228,6 +215,443 @@ LastChar::getLastChar()
228 return this->last_char; 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 bool 655 bool
232 QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const 656 QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const& rhs) const
233 { 657 {
@@ -253,7 +677,7 @@ QPDFObjectHandle::getTypeCode() const @@ -253,7 +677,7 @@ QPDFObjectHandle::getTypeCode() const
253 char const* 677 char const*
254 QPDFObjectHandle::getTypeName() const 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 "uninitialized", 681 "uninitialized",
258 "reserved", 682 "reserved",
259 "null", 683 "null",
@@ -268,84 +692,23 @@ QPDFObjectHandle::getTypeName() const @@ -268,84 +692,23 @@ QPDFObjectHandle::getTypeName() const
268 "operator", 692 "operator",
269 "inline-image", 693 "inline-image",
270 "unresolved", 694 "unresolved",
271 - "destroyed"}; 695 + "destroyed",
  696 + "reference"};
272 return obj ? tn[getTypeCode()] : "uninitialized"; 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 QPDF_Bool* 700 QPDF_Bool*
282 QPDFObjectHandle::asBool() const 701 QPDFObjectHandle::asBool() const
283 { 702 {
284 return obj ? obj->as<QPDF_Bool>() : nullptr; 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 QPDF_Integer* 706 QPDF_Integer*
300 QPDFObjectHandle::asInteger() const 707 QPDFObjectHandle::asInteger() const
301 { 708 {
302 return obj ? obj->as<QPDF_Integer>() : nullptr; 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 QPDF_String* 712 QPDF_String*
350 QPDFObjectHandle::asString() const 713 QPDFObjectHandle::asString() const
351 { 714 {
@@ -500,7 +863,7 @@ QPDFObjectHandle::getBoolValue() const @@ -500,7 +863,7 @@ QPDFObjectHandle::getBoolValue() const
500 { 863 {
501 auto boolean = asBool(); 864 auto boolean = asBool();
502 if (boolean) { 865 if (boolean) {
503 - return boolean->getVal(); 866 + return boolean->val;
504 } else { 867 } else {
505 typeWarning("boolean", "returning false"); 868 typeWarning("boolean", "returning false");
506 QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); 869 QTC::TC("qpdf", "QPDFObjectHandle boolean returning false");
@@ -515,7 +878,7 @@ QPDFObjectHandle::getValueAsBool(bool&amp; value) const @@ -515,7 +878,7 @@ QPDFObjectHandle::getValueAsBool(bool&amp; value) const
515 if (boolean == nullptr) { 878 if (boolean == nullptr) {
516 return false; 879 return false;
517 } 880 }
518 - value = boolean->getVal(); 881 + value = boolean->val;
519 return true; 882 return true;
520 } 883 }
521 884
@@ -526,7 +889,7 @@ QPDFObjectHandle::getIntValue() const @@ -526,7 +889,7 @@ QPDFObjectHandle::getIntValue() const
526 { 889 {
527 auto integer = asInteger(); 890 auto integer = asInteger();
528 if (integer) { 891 if (integer) {
529 - return integer->getVal(); 892 + return integer->val;
530 } else { 893 } else {
531 typeWarning("integer", "returning 0"); 894 typeWarning("integer", "returning 0");
532 QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); 895 QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
@@ -541,7 +904,7 @@ QPDFObjectHandle::getValueAsInt(long long&amp; value) const @@ -541,7 +904,7 @@ QPDFObjectHandle::getValueAsInt(long long&amp; value) const
541 if (integer == nullptr) { 904 if (integer == nullptr) {
542 return false; 905 return false;
543 } 906 }
544 - value = integer->getVal(); 907 + value = integer->val;
545 return true; 908 return true;
546 } 909 }
547 910
@@ -1155,7 +1518,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer&amp; p, bool dereference_ @@ -1155,7 +1518,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer&amp; p, bool dereference_
1155 } else if (!obj) { 1518 } else if (!obj) {
1156 throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); 1519 throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
1157 } else { 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,43 +1755,43 @@ QPDFObjectHandle::getParsedOffset() const
1392 QPDFObjectHandle 1755 QPDFObjectHandle
1393 QPDFObjectHandle::newBool(bool value) 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 QPDFObjectHandle 1761 QPDFObjectHandle
1399 QPDFObjectHandle::newNull() 1762 QPDFObjectHandle::newNull()
1400 { 1763 {
1401 - return {QPDF_Null::create()}; 1764 + return {QPDFObject::create<QPDF_Null>()};
1402 } 1765 }
1403 1766
1404 QPDFObjectHandle 1767 QPDFObjectHandle
1405 QPDFObjectHandle::newInteger(long long value) 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 QPDFObjectHandle 1773 QPDFObjectHandle
1411 QPDFObjectHandle::newReal(std::string const& value) 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 QPDFObjectHandle 1779 QPDFObjectHandle
1417 QPDFObjectHandle::newReal(double value, int decimal_places, bool trim_trailing_zeroes) 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 QPDFObjectHandle 1785 QPDFObjectHandle
1423 QPDFObjectHandle::newName(std::string const& name) 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 QPDFObjectHandle 1791 QPDFObjectHandle
1429 QPDFObjectHandle::newString(std::string const& str) 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 QPDFObjectHandle 1797 QPDFObjectHandle
@@ -1440,13 +1803,13 @@ QPDFObjectHandle::newUnicodeString(std::string const&amp; utf8_str) @@ -1440,13 +1803,13 @@ QPDFObjectHandle::newUnicodeString(std::string const&amp; utf8_str)
1440 QPDFObjectHandle 1803 QPDFObjectHandle
1441 QPDFObjectHandle::newOperator(std::string const& value) 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 QPDFObjectHandle 1809 QPDFObjectHandle
1447 QPDFObjectHandle::newInlineImage(std::string const& value) 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 QPDFObjectHandle 1815 QPDFObjectHandle
@@ -1458,7 +1821,7 @@ QPDFObjectHandle::newArray() @@ -1458,7 +1821,7 @@ QPDFObjectHandle::newArray()
1458 QPDFObjectHandle 1821 QPDFObjectHandle
1459 QPDFObjectHandle::newArray(std::vector<QPDFObjectHandle> const& items) 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 QPDFObjectHandle 1827 QPDFObjectHandle
@@ -1518,7 +1881,7 @@ QPDFObjectHandle::newDictionary() @@ -1518,7 +1881,7 @@ QPDFObjectHandle::newDictionary()
1518 QPDFObjectHandle 1881 QPDFObjectHandle
1519 QPDFObjectHandle::newDictionary(std::map<std::string, QPDFObjectHandle> const& items) 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 QPDFObjectHandle 1887 QPDFObjectHandle
@@ -1564,7 +1927,7 @@ void @@ -1564,7 +1927,7 @@ void
1564 QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) 1927 QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description)
1565 { 1928 {
1566 if (obj) { 1929 if (obj) {
1567 - auto descr = std::make_shared<QPDFValue::Description>(object_description); 1930 + auto descr = std::make_shared<QPDFObject::Description>(object_description);
1568 obj->setDescription(owning_qpdf, descr); 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,7 +1977,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1614 items.emplace_back(array.at(i).second); 1977 items.emplace_back(array.at(i).second);
1615 items.back().makeDirect(visited, stop_at_streams); 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 } else if (isDictionary()) { 1981 } else if (isDictionary()) {
1619 std::map<std::string, QPDFObjectHandle> items; 1982 std::map<std::string, QPDFObjectHandle> items;
1620 auto dict = as_dictionary(strict); 1983 auto dict = as_dictionary(strict);
@@ -1622,7 +1985,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams) @@ -1622,7 +1985,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1622 items[key] = dict.getKey(key); 1985 items[key] = dict.getKey(key);
1623 items[key].makeDirect(visited, stop_at_streams); 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 } else if (isStream()) { 1989 } else if (isStream()) {
1627 QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1); 1990 QTC::TC("qpdf", "QPDFObjectHandle copy stream", stop_at_streams ? 0 : 1);
1628 if (!stop_at_streams) { 1991 if (!stop_at_streams) {
libqpdf/QPDFParser.cc
@@ -4,18 +4,6 @@ @@ -4,18 +4,6 @@
4 #include <qpdf/QPDFObjGen.hh> 4 #include <qpdf/QPDFObjGen.hh>
5 #include <qpdf/QPDFObjectHandle.hh> 5 #include <qpdf/QPDFObjectHandle.hh>
6 #include <qpdf/QPDFObject_private.hh> 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 #include <qpdf/QTC.hh> 7 #include <qpdf/QTC.hh>
20 #include <qpdf/QUtil.hh> 8 #include <qpdf/QUtil.hh>
21 9
@@ -47,27 +35,27 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -47,27 +35,27 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
47 } 35 }
48 QTC::TC("qpdf", "QPDFParser eof in parse"); 36 QTC::TC("qpdf", "QPDFParser eof in parse");
49 warn("unexpected EOF"); 37 warn("unexpected EOF");
50 - return {QPDF_Null::create()}; 38 + return {QPDFObject::create<QPDF_Null>()};
51 39
52 case QPDFTokenizer::tt_bad: 40 case QPDFTokenizer::tt_bad:
53 QTC::TC("qpdf", "QPDFParser bad token in parse"); 41 QTC::TC("qpdf", "QPDFParser bad token in parse");
54 - return {QPDF_Null::create()}; 42 + return {QPDFObject::create<QPDF_Null>()};
55 43
56 case QPDFTokenizer::tt_brace_open: 44 case QPDFTokenizer::tt_brace_open:
57 case QPDFTokenizer::tt_brace_close: 45 case QPDFTokenizer::tt_brace_close:
58 QTC::TC("qpdf", "QPDFParser bad brace"); 46 QTC::TC("qpdf", "QPDFParser bad brace");
59 warn("treating unexpected brace token as null"); 47 warn("treating unexpected brace token as null");
60 - return {QPDF_Null::create()}; 48 + return {QPDFObject::create<QPDF_Null>()};
61 49
62 case QPDFTokenizer::tt_array_close: 50 case QPDFTokenizer::tt_array_close:
63 QTC::TC("qpdf", "QPDFParser bad array close"); 51 QTC::TC("qpdf", "QPDFParser bad array close");
64 warn("treating unexpected array close token as null"); 52 warn("treating unexpected array close token as null");
65 - return {QPDF_Null::create()}; 53 + return {QPDFObject::create<QPDF_Null>()};
66 54
67 case QPDFTokenizer::tt_dict_close: 55 case QPDFTokenizer::tt_dict_close:
68 QTC::TC("qpdf", "QPDFParser bad dictionary close"); 56 QTC::TC("qpdf", "QPDFParser bad dictionary close");
69 warn("unexpected dictionary close token"); 57 warn("unexpected dictionary close token");
70 - return {QPDF_Null::create()}; 58 + return {QPDFObject::create<QPDF_Null>()};
71 59
72 case QPDFTokenizer::tt_array_open: 60 case QPDFTokenizer::tt_array_open:
73 case QPDFTokenizer::tt_dict_open: 61 case QPDFTokenizer::tt_dict_open:
@@ -82,7 +70,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -82,7 +70,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
82 return withDescription<QPDF_Bool>(tokenizer.getValue() == "true"); 70 return withDescription<QPDF_Bool>(tokenizer.getValue() == "true");
83 71
84 case QPDFTokenizer::tt_null: 72 case QPDFTokenizer::tt_null:
85 - return {QPDF_Null::create()}; 73 + return {QPDFObject::create<QPDF_Null>()};
86 74
87 case QPDFTokenizer::tt_integer: 75 case QPDFTokenizer::tt_integer:
88 return withDescription<QPDF_Integer>(QUtil::string_to_ll(tokenizer.getValue().c_str())); 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,7 +91,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
103 // not move the input source's offset. 91 // not move the input source's offset.
104 input.seek(input.getLastOffset(), SEEK_SET); 92 input.seek(input.getLastOffset(), SEEK_SET);
105 empty = true; 93 empty = true;
106 - return {QPDF_Null::create()}; 94 + return {QPDFObject::create<QPDF_Null>()};
107 } else { 95 } else {
108 QTC::TC("qpdf", "QPDFParser treat word as string"); 96 QTC::TC("qpdf", "QPDFParser treat word as string");
109 warn("unknown token while reading object; treating as string"); 97 warn("unknown token while reading object; treating as string");
@@ -122,7 +110,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -122,7 +110,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
122 110
123 default: 111 default:
124 warn("treating unknown token type as null while reading object"); 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,12 +182,12 @@ QPDFParser::parseRemainder(bool content_stream)
194 } 182 }
195 QTC::TC("qpdf", "QPDFParser eof in parseRemainder"); 183 QTC::TC("qpdf", "QPDFParser eof in parseRemainder");
196 warn("unexpected EOF"); 184 warn("unexpected EOF");
197 - return {QPDF_Null::create()}; 185 + return {QPDFObject::create<QPDF_Null>()};
198 186
199 case QPDFTokenizer::tt_bad: 187 case QPDFTokenizer::tt_bad:
200 QTC::TC("qpdf", "QPDFParser bad token in parseRemainder"); 188 QTC::TC("qpdf", "QPDFParser bad token in parseRemainder");
201 if (tooManyBadTokens()) { 189 if (tooManyBadTokens()) {
202 - return {QPDF_Null::create()}; 190 + return {QPDFObject::create<QPDF_Null>()};
203 } 191 }
204 addNull(); 192 addNull();
205 continue; 193 continue;
@@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -209,7 +197,7 @@ QPDFParser::parseRemainder(bool content_stream)
209 QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder"); 197 QTC::TC("qpdf", "QPDFParser bad brace in parseRemainder");
210 warn("treating unexpected brace token as null"); 198 warn("treating unexpected brace token as null");
211 if (tooManyBadTokens()) { 199 if (tooManyBadTokens()) {
212 - return {QPDF_Null::create()}; 200 + return {QPDFObject::create<QPDF_Null>()};
213 } 201 }
214 addNull(); 202 addNull();
215 continue; 203 continue;
@@ -218,10 +206,11 @@ QPDFParser::parseRemainder(bool content_stream) @@ -218,10 +206,11 @@ QPDFParser::parseRemainder(bool content_stream)
218 if (bad_count && !max_bad_count) { 206 if (bad_count && !max_bad_count) {
219 // Trigger warning. 207 // Trigger warning.
220 (void)tooManyBadTokens(); 208 (void)tooManyBadTokens();
221 - return {QPDF_Null::create()}; 209 + return {QPDFObject::create<QPDF_Null>()};
222 } 210 }
223 if (frame->state == st_array) { 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 setDescription(object, frame->offset - 1); 214 setDescription(object, frame->offset - 1);
226 // The `offset` points to the next of "[". Set the rewind offset to point to the 215 // The `offset` points to the next of "[". Set the rewind offset to point to the
227 // beginning of "[". This has been explicitly tested with whitespace surrounding the 216 // beginning of "[". This has been explicitly tested with whitespace surrounding the
@@ -237,7 +226,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -237,7 +226,7 @@ QPDFParser::parseRemainder(bool content_stream)
237 QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder"); 226 QTC::TC("qpdf", "QPDFParser bad array close in parseRemainder");
238 warn("treating unexpected array close token as null"); 227 warn("treating unexpected array close token as null");
239 if (tooManyBadTokens()) { 228 if (tooManyBadTokens()) {
240 - return {QPDF_Null::create()}; 229 + return {QPDFObject::create<QPDF_Null>()};
241 } 230 }
242 addNull(); 231 addNull();
243 } 232 }
@@ -247,7 +236,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -247,7 +236,7 @@ QPDFParser::parseRemainder(bool content_stream)
247 if (bad_count && !max_bad_count) { 236 if (bad_count && !max_bad_count) {
248 // Trigger warning. 237 // Trigger warning.
249 (void)tooManyBadTokens(); 238 (void)tooManyBadTokens();
250 - return {QPDF_Null::create()}; 239 + return {QPDFObject::create<QPDF_Null>()};
251 } 240 }
252 if (frame->state <= st_dictionary_value) { 241 if (frame->state <= st_dictionary_value) {
253 // Attempt to recover more or less gracefully from invalid dictionaries. 242 // Attempt to recover more or less gracefully from invalid dictionaries.
@@ -258,7 +247,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -258,7 +247,7 @@ QPDFParser::parseRemainder(bool content_stream)
258 warn( 247 warn(
259 frame->offset, 248 frame->offset,
260 "dictionary ended prematurely; using null as value for last key"); 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 if (!frame->olist.empty()) { 253 if (!frame->olist.empty()) {
@@ -271,7 +260,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -271,7 +260,7 @@ QPDFParser::parseRemainder(bool content_stream)
271 dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string); 260 dict["/Contents"] = QPDFObjectHandle::newString(frame->contents_string);
272 dict["/Contents"].setParsedOffset(frame->contents_offset); 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 setDescription(object, frame->offset - 2); 264 setDescription(object, frame->offset - 2);
276 // The `offset` points to the next of "<<". Set the rewind offset to point to the 265 // The `offset` points to the next of "<<". Set the rewind offset to point to the
277 // beginning of "<<". This has been explicitly tested with whitespace surrounding 266 // beginning of "<<". This has been explicitly tested with whitespace surrounding
@@ -287,7 +276,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -287,7 +276,7 @@ QPDFParser::parseRemainder(bool content_stream)
287 QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder"); 276 QTC::TC("qpdf", "QPDFParser bad dictionary close in parseRemainder");
288 warn("unexpected dictionary close token"); 277 warn("unexpected dictionary close token");
289 if (tooManyBadTokens()) { 278 if (tooManyBadTokens()) {
290 - return {QPDF_Null::create()}; 279 + return {QPDFObject::create<QPDF_Null>()};
291 } 280 }
292 addNull(); 281 addNull();
293 } 282 }
@@ -298,7 +287,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -298,7 +287,7 @@ QPDFParser::parseRemainder(bool content_stream)
298 if (stack.size() > 499) { 287 if (stack.size() > 499) {
299 QTC::TC("qpdf", "QPDFParser too deep"); 288 QTC::TC("qpdf", "QPDFParser too deep");
300 warn("ignoring excessively deeply nested data structure"); 289 warn("ignoring excessively deeply nested data structure");
301 - return {QPDF_Null::create()}; 290 + return {QPDFObject::create<QPDF_Null>()};
302 } else { 291 } else {
303 b_contents = false; 292 b_contents = false;
304 stack.emplace_back( 293 stack.emplace_back(
@@ -350,7 +339,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -350,7 +339,7 @@ QPDFParser::parseRemainder(bool content_stream)
350 QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder"); 339 QTC::TC("qpdf", "QPDFParser treat word as string in parseRemainder");
351 warn("unknown token while reading object; treating as string"); 340 warn("unknown token while reading object; treating as string");
352 if (tooManyBadTokens()) { 341 if (tooManyBadTokens()) {
353 - return {QPDF_Null::create()}; 342 + return {QPDFObject::create<QPDF_Null>()};
354 } 343 }
355 addScalar<QPDF_String>(tokenizer.getValue()); 344 addScalar<QPDF_String>(tokenizer.getValue());
356 } 345 }
@@ -377,7 +366,7 @@ QPDFParser::parseRemainder(bool content_stream) @@ -377,7 +366,7 @@ QPDFParser::parseRemainder(bool content_stream)
377 default: 366 default:
378 warn("treating unknown token type as null while reading object"); 367 warn("treating unknown token type as null while reading object");
379 if (tooManyBadTokens()) { 368 if (tooManyBadTokens()) {
380 - return {QPDF_Null::create()}; 369 + return {QPDFObject::create<QPDF_Null>()};
381 } 370 }
382 addNull(); 371 addNull();
383 } 372 }
@@ -402,7 +391,7 @@ QPDFParser::add(std::shared_ptr&lt;QPDFObject&gt;&amp;&amp; obj) @@ -402,7 +391,7 @@ QPDFParser::add(std::shared_ptr&lt;QPDFObject&gt;&amp;&amp; obj)
402 void 391 void
403 QPDFParser::addNull() 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 if (frame->state != st_dictionary_value) { 396 if (frame->state != st_dictionary_value) {
408 // If state is st_dictionary_key then there is a missing key. Push onto olist for 397 // If state is st_dictionary_key then there is a missing key. Push onto olist for
@@ -420,7 +409,7 @@ QPDFParser::addNull() @@ -420,7 +409,7 @@ QPDFParser::addNull()
420 void 409 void
421 QPDFParser::addInt(int count) 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 obj->setDescription(context, description, last_offset_buffer[count % 2]); 413 obj->setDescription(context, description, last_offset_buffer[count % 2]);
425 add(std::move(obj)); 414 add(std::move(obj));
426 } 415 }
@@ -435,7 +424,7 @@ QPDFParser::addScalar(Args&amp;&amp;... args) @@ -435,7 +424,7 @@ QPDFParser::addScalar(Args&amp;&amp;... args)
435 max_bad_count = 0; 424 max_bad_count = 0;
436 return; 425 return;
437 } 426 }
438 - auto obj = T::create(args...); 427 + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...);
439 obj->setDescription(context, description, input.getLastOffset()); 428 obj->setDescription(context, description, input.getLastOffset());
440 add(std::move(obj)); 429 add(std::move(obj));
441 } 430 }
@@ -444,7 +433,7 @@ template &lt;typename T, typename... Args&gt; @@ -444,7 +433,7 @@ template &lt;typename T, typename... Args&gt;
444 QPDFObjectHandle 433 QPDFObjectHandle
445 QPDFParser::withDescription(Args&&... args) 434 QPDFParser::withDescription(Args&&... args)
446 { 435 {
447 - auto obj = T::create(args...); 436 + auto obj = QPDFObject::create<T>(std::forward<Args>(args)...);
448 obj->setDescription(context, description, start); 437 obj->setDescription(context, description, start);
449 return {obj}; 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,8 +16,7 @@
16 #include <qpdf/QIntC.hh> 16 #include <qpdf/QIntC.hh>
17 #include <qpdf/QPDF.hh> 17 #include <qpdf/QPDF.hh>
18 #include <qpdf/QPDFObjectHandle_private.hh> 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 #include <qpdf/QTC.hh> 20 #include <qpdf/QTC.hh>
22 #include <qpdf/QUtil.hh> 21 #include <qpdf/QUtil.hh>
23 #include <qpdf/RC4.hh> 22 #include <qpdf/RC4.hh>
libqpdf/QPDF_Array.cc
1 -#include <qpdf/QPDF_Array.hh>  
2 -  
3 -#include <qpdf/JSON_writer.hh>  
4 #include <qpdf/QPDFObjectHandle_private.hh> 1 #include <qpdf/QPDFObjectHandle_private.hh>
5 -#include <qpdf/QPDFObject_private.hh>  
6 -#include <qpdf/QPDF_Null.hh> 2 +
7 #include <qpdf/QTC.hh> 3 #include <qpdf/QTC.hh>
8 4
9 using namespace std::literals; 5 using namespace std::literals;
@@ -40,25 +36,12 @@ Array::checkOwnership(QPDFObjectHandle const&amp; item) const @@ -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 setFromVector(v); 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 if (sparse) { 46 if (sparse) {
64 sp = std::make_unique<Sparse>(); 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,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 QPDF_Array* 59 QPDF_Array*
203 Array::array() const 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 \ No newline at end of file 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 #include <qpdf/QPDFObjectHandle_private.hh> 1 #include <qpdf/QPDFObjectHandle_private.hh>
  2 +
5 #include <qpdf/QPDFObject_private.hh> 3 #include <qpdf/QPDFObject_private.hh>
6 -#include <qpdf/QPDF_Name.hh>  
7 #include <qpdf/QTC.hh> 4 #include <qpdf/QTC.hh>
8 -#include <qpdf/QUtil.hh>  
9 5
10 using namespace std::literals; 6 using namespace std::literals;
11 using namespace qpdf; 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 QPDF_Dictionary* 9 QPDF_Dictionary*
98 BaseDictionary::dict() const 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 #include <qpdf/ContentNormalizer.hh> 3 #include <qpdf/ContentNormalizer.hh>
4 #include <qpdf/JSON_writer.hh> 4 #include <qpdf/JSON_writer.hh>
@@ -12,7 +12,6 @@ @@ -12,7 +12,6 @@
12 #include <qpdf/QIntC.hh> 12 #include <qpdf/QIntC.hh>
13 #include <qpdf/QPDF.hh> 13 #include <qpdf/QPDF.hh>
14 #include <qpdf/QPDFExc.hh> 14 #include <qpdf/QPDFExc.hh>
15 -#include <qpdf/QPDFObjectHandle_private.hh>  
16 #include <qpdf/QTC.hh> 15 #include <qpdf/QTC.hh>
17 #include <qpdf/QUtil.hh> 16 #include <qpdf/QUtil.hh>
18 #include <qpdf/SF_ASCII85Decode.hh> 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,34 +104,14 @@ std::map&lt;std::string, std::function&lt;std::shared_ptr&lt;QPDFStreamFilter&gt;()&gt;&gt; Stream
105 {"/ASCIIHexDecode", SF_ASCIIHexDecode::factory}, 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 void 117 void
@@ -142,26 +121,6 @@ Stream::registerStreamFilter( @@ -142,26 +121,6 @@ Stream::registerStreamFilter(
142 filter_factories[filter_name] = factory; 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 JSON 124 JSON
166 Stream::getStreamJSON( 125 Stream::getStreamJSON(
167 int json_version, 126 int json_version,
@@ -278,34 +237,27 @@ Stream::writeStreamJSON( @@ -278,34 +237,27 @@ Stream::writeStreamJSON(
278 } 237 }
279 238
280 void 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 std::shared_ptr<Buffer> 249 std::shared_ptr<Buffer>
297 Stream::getStreamData(qpdf_stream_decode_level_e decode_level) 250 Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
298 { 251 {
299 - auto s = stream();  
300 Pl_Buffer buf("stream data buffer"); 252 Pl_Buffer buf("stream data buffer");
301 bool filtered; 253 bool filtered;
302 pipeStreamData(&buf, &filtered, 0, decode_level, false, false); 254 pipeStreamData(&buf, &filtered, 0, decode_level, false, false);
303 if (!filtered) { 255 if (!filtered) {
304 throw QPDFExc( 256 throw QPDFExc(
305 qpdf_e_unsupported, 257 qpdf_e_unsupported,
306 - s->qpdf->getFilename(), 258 + obj->getQPDF()->getFilename(),
307 "", 259 "",
308 - s->parsed_offset, 260 + obj->getParsedOffset(),
309 "getStreamData called on unfilterable stream"); 261 "getStreamData called on unfilterable stream");
310 } 262 }
311 QTC::TC("qpdf", "QPDF_Stream getStreamData"); 263 QTC::TC("qpdf", "QPDF_Stream getStreamData");
@@ -315,14 +267,13 @@ Stream::getStreamData(qpdf_stream_decode_level_e decode_level) @@ -315,14 +267,13 @@ Stream::getStreamData(qpdf_stream_decode_level_e decode_level)
315 std::shared_ptr<Buffer> 267 std::shared_ptr<Buffer>
316 Stream::getRawStreamData() 268 Stream::getRawStreamData()
317 { 269 {
318 - auto s = stream();  
319 Pl_Buffer buf("stream data buffer"); 270 Pl_Buffer buf("stream data buffer");
320 if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) { 271 if (!pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) {
321 throw QPDFExc( 272 throw QPDFExc(
322 qpdf_e_unsupported, 273 qpdf_e_unsupported,
323 - s->qpdf->getFilename(), 274 + obj->getQPDF()->getFilename(),
324 "", 275 "",
325 - s->parsed_offset, 276 + obj->getParsedOffset(),
326 "error getting raw stream data"); 277 "error getting raw stream data");
327 } 278 }
328 QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); 279 QTC::TC("qpdf", "QPDF_Stream getRawStreamData");
@@ -532,12 +483,12 @@ Stream::pipeStreamData( @@ -532,12 +483,12 @@ Stream::pipeStreamData(
532 Pl_Count count("stream provider count", pipeline); 483 Pl_Count count("stream provider count", pipeline);
533 if (s->stream_provider->supportsRetry()) { 484 if (s->stream_provider->supportsRetry()) {
534 if (!s->stream_provider->provideStreamData( 485 if (!s->stream_provider->provideStreamData(
535 - s->og, &count, suppress_warnings, will_retry)) { 486 + obj->getObjGen(), &count, suppress_warnings, will_retry)) {
536 filter = false; 487 filter = false;
537 success = false; 488 success = false;
538 } 489 }
539 } else { 490 } else {
540 - s->stream_provider->provideStreamData(s->og, &count); 491 + s->stream_provider->provideStreamData(obj->getObjGen(), &count);
541 } 492 }
542 qpdf_offset_t actual_length = count.getCount(); 493 qpdf_offset_t actual_length = count.getCount();
543 qpdf_offset_t desired_length = 0; 494 qpdf_offset_t desired_length = 0;
@@ -550,7 +501,7 @@ Stream::pipeStreamData( @@ -550,7 +501,7 @@ Stream::pipeStreamData(
550 // This would be caused by programmer error on the part of a library user, not by 501 // This would be caused by programmer error on the part of a library user, not by
551 // invalid input data. 502 // invalid input data.
552 throw std::runtime_error( 503 throw std::runtime_error(
553 - "stream data provider for " + s->og.unparse(' ') + " provided " + 504 + "stream data provider for " + obj->getObjGen().unparse(' ') + " provided " +
554 std::to_string(actual_length) + " bytes instead of expected " + 505 std::to_string(actual_length) + " bytes instead of expected " +
555 std::to_string(desired_length) + " bytes"); 506 std::to_string(desired_length) + " bytes");
556 } 507 }
@@ -558,15 +509,15 @@ Stream::pipeStreamData( @@ -558,15 +509,15 @@ Stream::pipeStreamData(
558 QTC::TC("qpdf", "QPDF_Stream provider length not provided"); 509 QTC::TC("qpdf", "QPDF_Stream provider length not provided");
559 s->stream_dict.replaceKey("/Length", QPDFObjectHandle::newInteger(actual_length)); 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 QTC::TC("qpdf", "QPDF_Stream pipe no stream data"); 513 QTC::TC("qpdf", "QPDF_Stream pipe no stream data");
563 throw std::logic_error("pipeStreamData called for stream with no data"); 514 throw std::logic_error("pipeStreamData called for stream with no data");
564 } else { 515 } else {
565 QTC::TC("qpdf", "QPDF_Stream pipe original stream data"); 516 QTC::TC("qpdf", "QPDF_Stream pipe original stream data");
566 if (!QPDF::Pipe::pipeStreamData( 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 s->length, 521 s->length,
571 s->stream_dict, 522 s->stream_dict,
572 pipeline, 523 pipeline,
@@ -642,8 +593,7 @@ Stream::replaceFilterData( @@ -642,8 +593,7 @@ Stream::replaceFilterData(
642 void 593 void
643 Stream::warn(std::string const& message) 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 QPDFObjectHandle 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 #include <qpdf/QUtil.hh> 4 #include <qpdf/QUtil.hh>
5 5
6 // DO NOT USE ctype -- it is locale dependent for some things, and it's not worth the risk of 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,18 +12,6 @@ is_iso_latin1_printable(char ch)
12 return (((ch >= 32) && (ch <= 126)) || (static_cast<unsigned char>(ch) >= 160)); 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 std::shared_ptr<QPDFObject> 15 std::shared_ptr<QPDFObject>
28 QPDF_String::create_utf16(std::string const& utf8_val) 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 +19,7 @@ QPDF_String::create_utf16(std::string const&amp; utf8_val)
31 if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) { 19 if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) {
32 result = QUtil::utf8_to_utf16(utf8_val); 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 void 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,9 +7,6 @@
7 #include <qpdf/QIntC.hh> 7 #include <qpdf/QIntC.hh>
8 #include <qpdf/QPDFObjectHandle_private.hh> 8 #include <qpdf/QPDFObjectHandle_private.hh>
9 #include <qpdf/QPDFObject_private.hh> 9 #include <qpdf/QPDFObject_private.hh>
10 -#include <qpdf/QPDFValue.hh>  
11 -#include <qpdf/QPDF_Null.hh>  
12 -#include <qpdf/QPDF_Stream.hh>  
13 #include <qpdf/QTC.hh> 10 #include <qpdf/QTC.hh>
14 #include <qpdf/QUtil.hh> 11 #include <qpdf/QUtil.hh>
15 #include <algorithm> 12 #include <algorithm>
@@ -239,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor @@ -239,8 +236,8 @@ class QPDF::JSONReactor: public JSON::Reactor
239 is(is), 236 is(is),
240 must_be_complete(must_be_complete), 237 must_be_complete(must_be_complete),
241 descr( 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 ~JSONReactor() override = default; 243 ~JSONReactor() override = default;
@@ -287,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor @@ -287,7 +284,7 @@ class QPDF::JSONReactor: public JSON::Reactor
287 QPDF& pdf; 284 QPDF& pdf;
288 std::shared_ptr<InputSource> is; 285 std::shared_ptr<InputSource> is;
289 bool must_be_complete{true}; 286 bool must_be_complete{true};
290 - std::shared_ptr<QPDFValue::Description> descr; 287 + std::shared_ptr<QPDFObject::Description> descr;
291 bool errors{false}; 288 bool errors{false};
292 bool saw_qpdf{false}; 289 bool saw_qpdf{false};
293 bool saw_qpdf_meta{false}; 290 bool saw_qpdf_meta{false};
@@ -577,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value) @@ -577,8 +574,8 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
577 } else { 574 } else {
578 this_stream_needs_data = true; 575 this_stream_needs_data = true;
579 replaceObject( 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 value); 579 value);
583 } 580 }
584 next_obj = tos.object; 581 next_obj = tos.object;
@@ -707,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const&amp; value) @@ -707,10 +704,10 @@ QPDF::JSONReactor::arrayItem(JSON const&amp; value)
707 void 704 void
708 QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value) 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 if (j_descr.object != cur_object) { 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 oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart()); 713 oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart());
libqpdf/QPDF_optimization.cc
@@ -5,9 +5,8 @@ @@ -5,9 +5,8 @@
5 #include <qpdf/QPDF.hh> 5 #include <qpdf/QPDF.hh>
6 6
7 #include <qpdf/QPDFExc.hh> 7 #include <qpdf/QPDFExc.hh>
  8 +#include <qpdf/QPDFObjectHandle_private.hh>
8 #include <qpdf/QPDFWriter_private.hh> 9 #include <qpdf/QPDFWriter_private.hh>
9 -#include <qpdf/QPDF_Array.hh>  
10 -#include <qpdf/QPDF_Dictionary.hh>  
11 #include <qpdf/QTC.hh> 10 #include <qpdf/QTC.hh>
12 11
13 QPDF::ObjUser::ObjUser() : 12 QPDF::ObjUser::ObjUser() :
libqpdf/qpdf/QPDFObjectHandle_private.hh
@@ -4,9 +4,7 @@ @@ -4,9 +4,7 @@
4 #include <qpdf/QPDFObjectHandle.hh> 4 #include <qpdf/QPDFObjectHandle.hh>
5 5
6 #include <qpdf/QPDFObject_private.hh> 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 namespace qpdf 9 namespace qpdf
12 { 10 {
@@ -106,6 +104,13 @@ namespace qpdf @@ -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 QPDFObjectHandle 114 QPDFObjectHandle
110 getDict() const 115 getDict() const
111 { 116 {
@@ -186,20 +191,22 @@ namespace qpdf @@ -186,20 +191,22 @@ namespace qpdf
186 { 191 {
187 auto s = stream(); 192 auto s = stream();
188 s->stream_dict = new_dict; 193 s->stream_dict = new_dict;
189 - s->setDictDescription(); 194 + setDictDescription();
190 } 195 }
191 196
  197 + void setDictDescription();
  198 +
192 static void registerStreamFilter( 199 static void registerStreamFilter(
193 std::string const& filter_name, 200 std::string const& filter_name,
194 std::function<std::shared_ptr<QPDFStreamFilter>()> factory); 201 std::function<std::shared_ptr<QPDFStreamFilter>()> factory);
195 202
196 private: 203 private:
197 - QPDF_Stream* 204 + QPDF_Stream::Members*
198 stream() const 205 stream() const
199 { 206 {
200 if (obj) { 207 if (obj) {
201 if (auto s = obj->as<QPDF_Stream>()) { 208 if (auto s = obj->as<QPDF_Stream>()) {
202 - return s; 209 + return s->m.get();
203 } 210 }
204 } 211 }
205 throw std::runtime_error("operation for stream attempted on object of type dictionary"); 212 throw std::runtime_error("operation for stream attempted on object of type dictionary");
@@ -227,6 +234,32 @@ namespace qpdf @@ -227,6 +234,32 @@ namespace qpdf
227 234
228 } // namespace qpdf 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 inline qpdf::Array 263 inline qpdf::Array
231 QPDFObjectHandle::as_array(qpdf::typed options) const 264 QPDFObjectHandle::as_array(qpdf::typed options) const
232 { 265 {
libqpdf/qpdf/QPDFObject_private.hh
@@ -6,182 +6,508 @@ @@ -6,182 +6,508 @@
6 6
7 #include <qpdf/Constants.h> 7 #include <qpdf/Constants.h>
8 #include <qpdf/JSON.hh> 8 #include <qpdf/JSON.hh>
  9 +#include <qpdf/JSON_writer.hh>
9 #include <qpdf/QPDF.hh> 10 #include <qpdf/QPDF.hh>
10 -#include <qpdf/QPDFValue.hh> 11 +#include <qpdf/QPDFObjGen.hh>
11 #include <qpdf/Types.h> 12 #include <qpdf/Types.h>
12 13
  14 +#include <map>
  15 +#include <memory>
13 #include <string> 16 #include <string>
14 #include <string_view> 17 #include <string_view>
  18 +#include <variant>
  19 +#include <vector>
15 20
16 -class QPDF; 21 +class QPDFObject;
17 class QPDFObjectHandle; 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 public: 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 // Return a unique type code for the resolved object 289 // Return a unique type code for the resolved object
47 qpdf_object_type_e 290 qpdf_object_type_e
48 getResolvedTypeCode() const 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 // Return a unique type code for the object 301 // Return a unique type code for the object
56 qpdf_object_type_e 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 QPDF* 308 QPDF*
63 getQPDF() const 309 getQPDF() const
64 { 310 {
65 - return value->qpdf; 311 + return qpdf;
66 } 312 }
67 QPDFObjGen 313 QPDFObjGen
68 getObjGen() const 314 getObjGen() const
69 { 315 {
70 - return value->og; 316 + return og;
71 } 317 }
72 void 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 void 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 void 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 void 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 void 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 void 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 void 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 bool 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 template <typename T> 464 template <typename T>
169 T* 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 private: 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 QPDFObject(QPDFObject const&) = delete; 503 QPDFObject(QPDFObject const&) = delete;
183 QPDFObject& operator=(QPDFObject const&) = delete; 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 #endif // QPDFOBJECT_HH 513 #endif // QPDFOBJECT_HH
libqpdf/qpdf/QPDFParser.hh
1 #ifndef QPDFPARSER_HH 1 #ifndef QPDFPARSER_HH
2 #define QPDFPARSER_HH 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 #include <memory> 7 #include <memory>
8 #include <string> 8 #include <string>
@@ -24,7 +24,7 @@ class QPDFParser @@ -24,7 +24,7 @@ class QPDFParser
24 decrypter(decrypter), 24 decrypter(decrypter),
25 context(context), 25 context(context),
26 description( 26 description(
27 - std::make_shared<QPDFValue::Description>( 27 + std::make_shared<QPDFObject::Description>(
28 std::string(input.getName() + ", " + object_description + " at offset $PO"))), 28 std::string(input.getName() + ", " + object_description + " at offset $PO"))),
29 parse_pdf(parse_pdf) 29 parse_pdf(parse_pdf)
30 { 30 {
@@ -78,7 +78,7 @@ class QPDFParser @@ -78,7 +78,7 @@ class QPDFParser
78 QPDFTokenizer& tokenizer; 78 QPDFTokenizer& tokenizer;
79 QPDFObjectHandle::StringDecrypter* decrypter; 79 QPDFObjectHandle::StringDecrypter* decrypter;
80 QPDF* context; 80 QPDF* context;
81 - std::shared_ptr<QPDFValue::Description> description; 81 + std::shared_ptr<QPDFObject::Description> description;
82 bool parse_pdf; 82 bool parse_pdf;
83 83
84 std::vector<StackFrame> stack; 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,14 +3,13 @@
3 #include <qpdf/QPDF.hh> 3 #include <qpdf/QPDF.hh>
4 #include <qpdf/QPDFObjectHandle_private.hh> 4 #include <qpdf/QPDFObjectHandle_private.hh>
5 #include <qpdf/QPDFObject_private.hh> 5 #include <qpdf/QPDFObject_private.hh>
6 -#include <qpdf/QPDF_Array.hh>  
7 6
8 #include <iostream> 7 #include <iostream>
9 8
10 int 9 int
11 main() 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 auto a = qpdf::Array(obj); 13 auto a = qpdf::Array(obj);
15 14
16 assert(a.size() == 0); 15 assert(a.size() == 0);
@@ -88,7 +87,8 @@ main() @@ -88,7 +87,8 @@ main()
88 QPDF pdf; 87 QPDF pdf;
89 pdf.emptyPDF(); 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 auto b = qpdf::Array(obj); 92 auto b = qpdf::Array(obj);
93 b.setAt(5, pdf.newIndirectNull()); 93 b.setAt(5, pdf.newIndirectNull());
94 b.setAt(7, "[0 1 2 3]"_qpdf); 94 b.setAt(7, "[0 1 2 3]"_qpdf);