Commit b3cfa1010f95514a13590266dd50677445f74309

Authored by Jay Berkenbilt
Committed by GitHub
2 parents e4e03e9a 07bb5c3d

Merge pull request #902 from m-holger/od

Refactor creation of object descriptions
include/qpdf/QPDF.hh
@@ -1108,71 +1108,7 @@ class QPDF @@ -1108,71 +1108,7 @@ class QPDF
1108 std::set<QPDFObjGen>::const_iterator iter; 1108 std::set<QPDFObjGen>::const_iterator iter;
1109 }; 1109 };
1110 1110
1111 - class JSONReactor: public JSON::Reactor  
1112 - {  
1113 - public:  
1114 - JSONReactor(  
1115 - QPDF&, std::shared_ptr<InputSource> is, bool must_be_complete);  
1116 - virtual ~JSONReactor() = default;  
1117 - virtual void dictionaryStart() override;  
1118 - virtual void arrayStart() override;  
1119 - virtual void containerEnd(JSON const& value) override;  
1120 - virtual void topLevelScalar() override;  
1121 - virtual bool  
1122 - dictionaryItem(std::string const& key, JSON const& value) override;  
1123 - virtual bool arrayItem(JSON const& value) override;  
1124 -  
1125 - bool anyErrors() const;  
1126 -  
1127 - private:  
1128 - enum state_e {  
1129 - st_initial,  
1130 - st_top,  
1131 - st_qpdf,  
1132 - st_qpdf_meta,  
1133 - st_objects,  
1134 - st_trailer,  
1135 - st_object_top,  
1136 - st_stream,  
1137 - st_object,  
1138 - st_ignore,  
1139 - };  
1140 -  
1141 - void containerStart();  
1142 - void nestedState(std::string const& key, JSON const& value, state_e);  
1143 - void setObjectDescription(QPDFObjectHandle& oh, JSON const& value);  
1144 - QPDFObjectHandle makeObject(JSON const& value);  
1145 - void error(qpdf_offset_t offset, std::string const& message);  
1146 - QPDFObjectHandle reserveObject(int obj, int gen);  
1147 - void replaceObject(  
1148 - QPDFObjectHandle to_replace,  
1149 - QPDFObjectHandle replacement,  
1150 - JSON const& value);  
1151 -  
1152 - QPDF& pdf;  
1153 - std::shared_ptr<InputSource> is;  
1154 - bool must_be_complete;  
1155 - bool errors;  
1156 - bool parse_error;  
1157 - bool saw_qpdf;  
1158 - bool saw_qpdf_meta;  
1159 - bool saw_objects;  
1160 - bool saw_json_version;  
1161 - bool saw_pdf_version;  
1162 - bool saw_trailer;  
1163 - state_e state;  
1164 - state_e next_state;  
1165 - std::string cur_object;  
1166 - bool saw_value;  
1167 - bool saw_stream;  
1168 - bool saw_dict;  
1169 - bool saw_data;  
1170 - bool saw_datafile;  
1171 - bool this_stream_needs_data;  
1172 - std::vector<state_e> state_stack;  
1173 - std::vector<QPDFObjectHandle> object_stack;  
1174 - std::set<QPDFObjGen> reserved;  
1175 - }; 1111 + class JSONReactor;
1176 1112
1177 void parse(char const* password); 1113 void parse(char const* password);
1178 void inParse(bool); 1114 void inParse(bool);
libqpdf/QPDFObjectHandle.cc
@@ -36,6 +36,8 @@ @@ -36,6 +36,8 @@
36 #include <stdexcept> 36 #include <stdexcept>
37 #include <stdlib.h> 37 #include <stdlib.h>
38 38
  39 +using namespace std::literals;
  40 +
39 namespace 41 namespace
40 { 42 {
41 class TerminateParsing 43 class TerminateParsing
@@ -800,12 +802,10 @@ QPDFObjectHandle::getArrayNItems() @@ -800,12 +802,10 @@ QPDFObjectHandle::getArrayNItems()
800 QPDFObjectHandle 802 QPDFObjectHandle
801 QPDFObjectHandle::getArrayItem(int n) 803 QPDFObjectHandle::getArrayItem(int n)
802 { 804 {
803 - QPDFObjectHandle result;  
804 auto array = asArray(); 805 auto array = asArray();
805 if (array && (n < array->getNItems()) && (n >= 0)) { 806 if (array && (n < array->getNItems()) && (n >= 0)) {
806 - result = array->getItem(n); 807 + return array->getItem(n);
807 } else { 808 } else {
808 - result = newNull();  
809 if (array) { 809 if (array) {
810 objectWarning("returning null for out of bounds array access"); 810 objectWarning("returning null for out of bounds array access");
811 QTC::TC("qpdf", "QPDFObjectHandle array bounds"); 811 QTC::TC("qpdf", "QPDFObjectHandle array bounds");
@@ -813,15 +813,10 @@ QPDFObjectHandle::getArrayItem(int n) @@ -813,15 +813,10 @@ QPDFObjectHandle::getArrayItem(int n)
813 typeWarning("array", "returning null"); 813 typeWarning("array", "returning null");
814 QTC::TC("qpdf", "QPDFObjectHandle array null for non-array"); 814 QTC::TC("qpdf", "QPDFObjectHandle array null for non-array");
815 } 815 }
816 - QPDF* context = nullptr;  
817 - std::string description;  
818 - if (obj->getDescription(context, description)) {  
819 - result.setObjectDescription(  
820 - context,  
821 - description + " -> null returned from invalid array access");  
822 - } 816 + static auto constexpr msg =
  817 + " -> null returned from invalid array access"sv;
  818 + return QPDF_Null::create(obj, msg, "");
823 } 819 }
824 - return result;  
825 } 820 }
826 821
827 bool 822 bool
@@ -1030,24 +1025,15 @@ QPDFObjectHandle::hasKey(std::string const&amp; key) @@ -1030,24 +1025,15 @@ QPDFObjectHandle::hasKey(std::string const&amp; key)
1030 QPDFObjectHandle 1025 QPDFObjectHandle
1031 QPDFObjectHandle::getKey(std::string const& key) 1026 QPDFObjectHandle::getKey(std::string const& key)
1032 { 1027 {
1033 - QPDFObjectHandle result;  
1034 - auto dict = asDictionary();  
1035 - if (dict) {  
1036 - result = dict->getKey(key); 1028 + if (auto dict = asDictionary()) {
  1029 + return dict->getKey(key);
1037 } else { 1030 } else {
1038 typeWarning("dictionary", "returning null for attempted key retrieval"); 1031 typeWarning("dictionary", "returning null for attempted key retrieval");
1039 QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); 1032 QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey");
1040 - result = newNull();  
1041 - QPDF* qpdf = nullptr;  
1042 - std::string description;  
1043 - if (obj->getDescription(qpdf, description)) {  
1044 - result.setObjectDescription(  
1045 - qpdf,  
1046 - (description + " -> null returned from getting key " + key +  
1047 - " from non-Dictionary"));  
1048 - } 1033 + static auto constexpr msg =
  1034 + " -> null returned from getting key $VD from non-Dictionary"sv;
  1035 + return QPDF_Null::create(obj, msg, "");
1049 } 1036 }
1050 - return result;  
1051 } 1037 }
1052 1038
1053 QPDFObjectHandle 1039 QPDFObjectHandle
@@ -2176,7 +2162,8 @@ QPDFObjectHandle::setObjectDescription( @@ -2176,7 +2162,8 @@ QPDFObjectHandle::setObjectDescription(
2176 // This is called during parsing on newly created direct objects, 2162 // This is called during parsing on newly created direct objects,
2177 // so we can't call dereference() here. 2163 // so we can't call dereference() here.
2178 if (isInitialized() && obj.get()) { 2164 if (isInitialized() && obj.get()) {
2179 - auto descr = std::make_shared<std::string>(object_description); 2165 + auto descr =
  2166 + std::make_shared<QPDFValue::Description>(object_description);
2180 obj->setDescription(owning_qpdf, descr); 2167 obj->setDescription(owning_qpdf, descr);
2181 } 2168 }
2182 } 2169 }
libqpdf/QPDFValue.cc
@@ -9,3 +9,58 @@ QPDFValue::do_create(QPDFValue* object) @@ -9,3 +9,58 @@ QPDFValue::do_create(QPDFValue* object)
9 obj->value = std::shared_ptr<QPDFValue>(object); 9 obj->value = std::shared_ptr<QPDFValue>(object);
10 return obj; 10 return obj;
11 } 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");
  24 + pos != std::string::npos) {
  25 + description.replace(pos, 3, og.unparse(' '));
  26 + }
  27 + if (auto pos = description.find("$PO");
  28 + pos != std::string::npos) {
  29 + qpdf_offset_t shift = (type_code == ::ot_dictionary) ? 2
  30 + : (type_code == ::ot_array) ? 1
  31 + : 0;
  32 +
  33 + description.replace(
  34 + pos, 3, std::to_string(parsed_offset + shift));
  35 + }
  36 + return description;
  37 + }
  38 + case 1:
  39 + {
  40 + // QPDF::JSONReactor generated description
  41 + auto j_descr = std::get<1>(*object_description);
  42 + return (
  43 + *j_descr.input +
  44 + (j_descr.object.empty() ? "" : ", " + j_descr.object) +
  45 + " at offset " + std::to_string(parsed_offset));
  46 + }
  47 + case 2:
  48 + {
  49 + // Child object description
  50 + auto j_descr = std::get<2>(*object_description);
  51 + std::string result;
  52 + if (auto p = j_descr.parent.lock()) {
  53 + result = p->getDescription();
  54 + }
  55 + result += j_descr.static_descr;
  56 + if (auto pos = result.find("$VD"); pos != std::string::npos) {
  57 + result.replace(pos, 3, j_descr.var_descr);
  58 + }
  59 + return result;
  60 + }
  61 + }
  62 + } else if (og.isIndirect()) {
  63 + return "object " + og.unparse(' ');
  64 + }
  65 + return {};
  66 +}
libqpdf/QPDF_Dictionary.cc
1 #include <qpdf/QPDF_Dictionary.hh> 1 #include <qpdf/QPDF_Dictionary.hh>
2 2
  3 +#include <qpdf/QPDFObject_private.hh>
3 #include <qpdf/QPDF_Name.hh> 4 #include <qpdf/QPDF_Name.hh>
  5 +#include <qpdf/QPDF_Null.hh>
  6 +
  7 +using namespace std::literals;
4 8
5 QPDF_Dictionary::QPDF_Dictionary( 9 QPDF_Dictionary::QPDF_Dictionary(
6 std::map<std::string, QPDFObjectHandle> const& items) : 10 std::map<std::string, QPDFObjectHandle> const& items) :
@@ -97,12 +101,8 @@ QPDF_Dictionary::getKey(std::string const&amp; key) @@ -97,12 +101,8 @@ QPDF_Dictionary::getKey(std::string const&amp; key)
97 // May be a null object 101 // May be a null object
98 return item->second; 102 return item->second;
99 } else { 103 } else {
100 - auto null = QPDFObjectHandle::newNull();  
101 - if (qpdf != nullptr) {  
102 - null.setObjectDescription(  
103 - qpdf, getDescription() + " -> dictionary key " + key);  
104 - }  
105 - return null; 104 + static auto constexpr msg = " -> dictionary key $VD"sv;
  105 + return QPDF_Null::create(shared_from_this(), msg, key);
106 } 106 }
107 } 107 }
108 108
libqpdf/QPDF_Null.cc
1 #include <qpdf/QPDF_Null.hh> 1 #include <qpdf/QPDF_Null.hh>
2 2
  3 +#include <qpdf/QPDFObject_private.hh>
  4 +
3 QPDF_Null::QPDF_Null() : 5 QPDF_Null::QPDF_Null() :
4 QPDFValue(::ot_null, "null") 6 QPDFValue(::ot_null, "null")
5 { 7 {
@@ -12,6 +14,28 @@ QPDF_Null::create() @@ -12,6 +14,28 @@ QPDF_Null::create()
12 } 14 }
13 15
14 std::shared_ptr<QPDFObject> 16 std::shared_ptr<QPDFObject>
  17 +QPDF_Null::create(
  18 + std::shared_ptr<QPDFObject> parent,
  19 + std::string_view const& static_descr,
  20 + std::string var_descr)
  21 +{
  22 + auto n = do_create(new QPDF_Null());
  23 + n->setChildDescription(parent, static_descr, var_descr);
  24 + return n;
  25 +}
  26 +
  27 +std::shared_ptr<QPDFObject>
  28 +QPDF_Null::create(
  29 + std::shared_ptr<QPDFValue> parent,
  30 + std::string_view const& static_descr,
  31 + std::string var_descr)
  32 +{
  33 + auto n = do_create(new QPDF_Null());
  34 + n->setChildDescription(parent, static_descr, var_descr);
  35 + return n;
  36 +}
  37 +
  38 +std::shared_ptr<QPDFObject>
15 QPDF_Null::copy(bool shallow) 39 QPDF_Null::copy(bool shallow)
16 { 40 {
17 return create(); 41 return create();
libqpdf/QPDF_Stream.cc
@@ -123,7 +123,7 @@ QPDF_Stream::QPDF_Stream( @@ -123,7 +123,7 @@ QPDF_Stream::QPDF_Stream(
123 throw std::logic_error("stream object instantiated with non-dictionary " 123 throw std::logic_error("stream object instantiated with non-dictionary "
124 "object for dictionary"); 124 "object for dictionary");
125 } 125 }
126 - auto descr = std::make_shared<std::string>( 126 + auto descr = std::make_shared<QPDFValue::Description>(
127 qpdf->getFilename() + ", stream object " + og.unparse(' ')); 127 qpdf->getFilename() + ", stream object " + og.unparse(' '));
128 setDescription(qpdf, descr, offset); 128 setDescription(qpdf, descr, offset);
129 } 129 }
@@ -283,7 +283,9 @@ QPDF_Stream::getStreamJSON( @@ -283,7 +283,9 @@ QPDF_Stream::getStreamJSON(
283 283
284 void 284 void
285 QPDF_Stream::setDescription( 285 QPDF_Stream::setDescription(
286 - QPDF* qpdf, std::shared_ptr<std::string>& description, qpdf_offset_t offset) 286 + QPDF* qpdf,
  287 + std::shared_ptr<QPDFValue::Description>& description,
  288 + qpdf_offset_t offset)
287 { 289 {
288 this->QPDFValue::setDescription(qpdf, description, offset); 290 this->QPDFValue::setDescription(qpdf, description, offset);
289 setDictDescription(); 291 setDictDescription();
libqpdf/QPDF_json.cc
@@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
4 #include <qpdf/Pl_Base64.hh> 4 #include <qpdf/Pl_Base64.hh>
5 #include <qpdf/Pl_StdioFile.hh> 5 #include <qpdf/Pl_StdioFile.hh>
6 #include <qpdf/QIntC.hh> 6 #include <qpdf/QIntC.hh>
  7 +#include <qpdf/QPDFObject_private.hh>
  8 +#include <qpdf/QPDFValue.hh>
7 #include <qpdf/QTC.hh> 9 #include <qpdf/QTC.hh>
8 #include <qpdf/QUtil.hh> 10 #include <qpdf/QUtil.hh>
9 #include <algorithm> 11 #include <algorithm>
@@ -221,11 +223,79 @@ provide_data( @@ -221,11 +223,79 @@ provide_data(
221 }; 223 };
222 } 224 }
223 225
  226 +class QPDF::JSONReactor: public JSON::Reactor
  227 +{
  228 + public:
  229 + JSONReactor(QPDF&, std::shared_ptr<InputSource> is, bool must_be_complete);
  230 + virtual ~JSONReactor() = default;
  231 + virtual void dictionaryStart() override;
  232 + virtual void arrayStart() override;
  233 + virtual void containerEnd(JSON const& value) override;
  234 + virtual void topLevelScalar() override;
  235 + virtual bool
  236 + dictionaryItem(std::string const& key, JSON const& value) override;
  237 + virtual bool arrayItem(JSON const& value) override;
  238 +
  239 + bool anyErrors() const;
  240 +
  241 + private:
  242 + enum state_e {
  243 + st_initial,
  244 + st_top,
  245 + st_qpdf,
  246 + st_qpdf_meta,
  247 + st_objects,
  248 + st_trailer,
  249 + st_object_top,
  250 + st_stream,
  251 + st_object,
  252 + st_ignore,
  253 + };
  254 +
  255 + void containerStart();
  256 + void nestedState(std::string const& key, JSON const& value, state_e);
  257 + void setObjectDescription(QPDFObjectHandle& oh, JSON const& value);
  258 + QPDFObjectHandle makeObject(JSON const& value);
  259 + void error(qpdf_offset_t offset, std::string const& message);
  260 + QPDFObjectHandle reserveObject(int obj, int gen);
  261 + void replaceObject(
  262 + QPDFObjectHandle to_replace,
  263 + QPDFObjectHandle replacement,
  264 + JSON const& value);
  265 +
  266 + QPDF& pdf;
  267 + std::shared_ptr<InputSource> is;
  268 + bool must_be_complete;
  269 + std::shared_ptr<QPDFValue::Description> descr;
  270 + bool errors;
  271 + bool parse_error;
  272 + bool saw_qpdf;
  273 + bool saw_qpdf_meta;
  274 + bool saw_objects;
  275 + bool saw_json_version;
  276 + bool saw_pdf_version;
  277 + bool saw_trailer;
  278 + state_e state;
  279 + state_e next_state;
  280 + std::string cur_object;
  281 + bool saw_value;
  282 + bool saw_stream;
  283 + bool saw_dict;
  284 + bool saw_data;
  285 + bool saw_datafile;
  286 + bool this_stream_needs_data;
  287 + std::vector<state_e> state_stack;
  288 + std::vector<QPDFObjectHandle> object_stack;
  289 + std::set<QPDFObjGen> reserved;
  290 +};
  291 +
224 QPDF::JSONReactor::JSONReactor( 292 QPDF::JSONReactor::JSONReactor(
225 QPDF& pdf, std::shared_ptr<InputSource> is, bool must_be_complete) : 293 QPDF& pdf, std::shared_ptr<InputSource> is, bool must_be_complete) :
226 pdf(pdf), 294 pdf(pdf),
227 is(is), 295 is(is),
228 must_be_complete(must_be_complete), 296 must_be_complete(must_be_complete),
  297 + descr(std::make_shared<QPDFValue::Description>(QPDFValue::JSON_Descr(
  298 + std::make_shared<std::string>(is->getName()), ""))),
229 errors(false), 299 errors(false),
230 parse_error(false), 300 parse_error(false),
231 saw_qpdf(false), 301 saw_qpdf(false),
@@ -675,12 +745,13 @@ QPDF::JSONReactor::arrayItem(JSON const&amp; value) @@ -675,12 +745,13 @@ QPDF::JSONReactor::arrayItem(JSON const&amp; value)
675 void 745 void
676 QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value) 746 QPDF::JSONReactor::setObjectDescription(QPDFObjectHandle& oh, JSON const& value)
677 { 747 {
678 - std::string description = this->is->getName();  
679 - if (!this->cur_object.empty()) {  
680 - description += ", " + this->cur_object; 748 + auto j_descr = std::get<QPDFValue::JSON_Descr>(*descr);
  749 + if (j_descr.object != cur_object) {
  750 + descr = std::make_shared<QPDFValue::Description>(
  751 + QPDFValue::JSON_Descr(j_descr.input, cur_object));
681 } 752 }
682 - description += " at offset " + std::to_string(value.getStart());  
683 - oh.setObjectDescription(&this->pdf, description); 753 +
  754 + oh.getObjectPtr()->setDescription(&pdf, descr, value.getStart());
684 } 755 }
685 756
686 QPDFObjectHandle 757 QPDFObjectHandle
libqpdf/qpdf/QPDFObject_private.hh
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 #include <qpdf/Types.h> 12 #include <qpdf/Types.h>
13 13
14 #include <string> 14 #include <string>
  15 +#include <string_view>
15 16
16 class QPDF; 17 class QPDF;
17 class QPDFObjectHandle; 18 class QPDFObjectHandle;
@@ -71,11 +72,30 @@ class QPDFObject @@ -71,11 +72,30 @@ class QPDFObject
71 void 72 void
72 setDescription( 73 setDescription(
73 QPDF* qpdf, 74 QPDF* qpdf,
74 - std::shared_ptr<std::string>& description, 75 + std::shared_ptr<QPDFValue::Description>& description,
75 qpdf_offset_t offset = -1) 76 qpdf_offset_t offset = -1)
76 { 77 {
77 return value->setDescription(qpdf, description, offset); 78 return value->setDescription(qpdf, description, offset);
78 } 79 }
  80 + void
  81 + setChildDescription(
  82 + std::shared_ptr<QPDFObject> parent,
  83 + std::string_view const& static_descr,
  84 + std::string var_descr)
  85 + {
  86 + auto qpdf = parent ? parent->value->qpdf : nullptr;
  87 + value->setChildDescription(
  88 + qpdf, parent->value, static_descr, var_descr);
  89 + }
  90 + void
  91 + setChildDescription(
  92 + std::shared_ptr<QPDFValue> parent,
  93 + std::string_view const& static_descr,
  94 + std::string var_descr)
  95 + {
  96 + auto qpdf = parent ? parent->qpdf : nullptr;
  97 + value->setChildDescription(qpdf, parent, static_descr, var_descr);
  98 + }
79 bool 99 bool
80 getDescription(QPDF*& qpdf, std::string& description) 100 getDescription(QPDF*& qpdf, std::string& description)
81 { 101 {
libqpdf/qpdf/QPDFParser.hh
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 #define QPDFPARSER_HH 2 #define QPDFPARSER_HH
3 3
4 #include <qpdf/QPDFObjectHandle.hh> 4 #include <qpdf/QPDFObjectHandle.hh>
  5 +#include <qpdf/QPDFValue.hh>
5 6
6 #include <memory> 7 #include <memory>
7 #include <string> 8 #include <string>
@@ -21,8 +22,8 @@ class QPDFParser @@ -21,8 +22,8 @@ class QPDFParser
21 tokenizer(tokenizer), 22 tokenizer(tokenizer),
22 decrypter(decrypter), 23 decrypter(decrypter),
23 context(context), 24 context(context),
24 - description(std::make_shared<std::string>(  
25 - input->getName() + ", " + object_description + " at offset $PO")) 25 + description(std::make_shared<QPDFValue::Description>(std::string(
  26 + input->getName() + ", " + object_description + " at offset $PO")))
26 { 27 {
27 } 28 }
28 virtual ~QPDFParser() = default; 29 virtual ~QPDFParser() = default;
@@ -49,7 +50,7 @@ class QPDFParser @@ -49,7 +50,7 @@ class QPDFParser
49 QPDFTokenizer& tokenizer; 50 QPDFTokenizer& tokenizer;
50 QPDFObjectHandle::StringDecrypter* decrypter; 51 QPDFObjectHandle::StringDecrypter* decrypter;
51 QPDF* context; 52 QPDF* context;
52 - std::shared_ptr<std::string> description; 53 + std::shared_ptr<QPDFValue::Description> description;
53 }; 54 };
54 55
55 #endif // QPDFPARSER_HH 56 #endif // QPDFPARSER_HH
libqpdf/qpdf/QPDFValue.hh
@@ -8,12 +8,14 @@ @@ -8,12 +8,14 @@
8 #include <qpdf/Types.h> 8 #include <qpdf/Types.h>
9 9
10 #include <string> 10 #include <string>
  11 +#include <string_view>
  12 +#include <variant>
11 13
12 class QPDF; 14 class QPDF;
13 class QPDFObjectHandle; 15 class QPDFObjectHandle;
14 class QPDFObject; 16 class QPDFObject;
15 17
16 -class QPDFValue 18 +class QPDFValue: public std::enable_shared_from_this<QPDFValue>
17 { 19 {
18 friend class QPDFObject; 20 friend class QPDFObject;
19 21
@@ -23,10 +25,43 @@ class QPDFValue @@ -23,10 +25,43 @@ class QPDFValue
23 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0; 25 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0;
24 virtual std::string unparse() = 0; 26 virtual std::string unparse() = 0;
25 virtual JSON getJSON(int json_version) = 0; 27 virtual JSON getJSON(int json_version) = 0;
  28 +
  29 + struct JSON_Descr
  30 + {
  31 + JSON_Descr(
  32 + std::shared_ptr<std::string> input, std::string const& object) :
  33 + input(input),
  34 + object(object)
  35 + {
  36 + }
  37 +
  38 + std::shared_ptr<std::string> input;
  39 + std::string object;
  40 + };
  41 +
  42 + struct ChildDescr
  43 + {
  44 + ChildDescr(
  45 + std::shared_ptr<QPDFValue> parent,
  46 + std::string_view const& static_descr,
  47 + std::string var_descr) :
  48 + parent(parent),
  49 + static_descr(static_descr),
  50 + var_descr(var_descr)
  51 + {
  52 + }
  53 +
  54 + std::weak_ptr<QPDFValue> parent;
  55 + std::string_view const& static_descr;
  56 + std::string var_descr;
  57 + };
  58 +
  59 + using Description = std::variant<std::string, JSON_Descr, ChildDescr>;
  60 +
26 virtual void 61 virtual void
27 setDescription( 62 setDescription(
28 QPDF* qpdf_p, 63 QPDF* qpdf_p,
29 - std::shared_ptr<std::string>& description, 64 + std::shared_ptr<Description>& description,
30 qpdf_offset_t offset) 65 qpdf_offset_t offset)
31 { 66 {
32 qpdf = qpdf_p; 67 qpdf = qpdf_p;
@@ -36,35 +71,25 @@ class QPDFValue @@ -36,35 +71,25 @@ class QPDFValue
36 void 71 void
37 setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og) 72 setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og)
38 { 73 {
39 - static auto default_description{  
40 - std::make_shared<std::string>("object $OG")};  
41 - if (!object_description) {  
42 - object_description = default_description;  
43 - }  
44 qpdf = a_qpdf; 74 qpdf = a_qpdf;
45 og = a_og; 75 og = a_og;
46 } 76 }
47 - std::string  
48 - getDescription() 77 + void
  78 + setChildDescription(
  79 + QPDF* a_qpdf,
  80 + std::shared_ptr<QPDFValue> parent,
  81 + std::string_view const& static_descr,
  82 + std::string var_descr)
49 { 83 {
50 - auto description = object_description ? *object_description : "";  
51 - if (auto pos = description.find("$OG"); pos != std::string::npos) {  
52 - description.replace(pos, 3, og.unparse(' '));  
53 - }  
54 - if (auto pos = description.find("$PO"); pos != std::string::npos) {  
55 - qpdf_offset_t shift = (type_code == ::ot_dictionary) ? 2  
56 - : (type_code == ::ot_array) ? 1  
57 - : 0;  
58 -  
59 - description.replace(pos, 3, std::to_string(parsed_offset + shift));  
60 - }  
61 - return description; 84 + object_description = std::make_shared<Description>(
  85 + ChildDescr(parent, static_descr, var_descr));
  86 + qpdf = a_qpdf;
62 } 87 }
  88 + std::string getDescription();
63 bool 89 bool
64 hasDescription() 90 hasDescription()
65 { 91 {
66 - return qpdf != nullptr && object_description &&  
67 - !object_description->empty(); 92 + return object_description || og.isIndirect();
68 } 93 }
69 void 94 void
70 setParsedOffset(qpdf_offset_t offset) 95 setParsedOffset(qpdf_offset_t offset)
@@ -123,7 +148,7 @@ class QPDFValue @@ -123,7 +148,7 @@ class QPDFValue
123 private: 148 private:
124 QPDFValue(QPDFValue const&) = delete; 149 QPDFValue(QPDFValue const&) = delete;
125 QPDFValue& operator=(QPDFValue const&) = delete; 150 QPDFValue& operator=(QPDFValue const&) = delete;
126 - std::shared_ptr<std::string> object_description; 151 + std::shared_ptr<Description> object_description;
127 152
128 const qpdf_object_type_e type_code{::ot_uninitialized}; 153 const qpdf_object_type_e type_code{::ot_uninitialized};
129 char const* type_name{"uninitialized"}; 154 char const* type_name{"uninitialized"};
libqpdf/qpdf/QPDF_Null.hh
@@ -8,6 +8,14 @@ class QPDF_Null: public QPDFValue @@ -8,6 +8,14 @@ class QPDF_Null: public QPDFValue
8 public: 8 public:
9 virtual ~QPDF_Null() = default; 9 virtual ~QPDF_Null() = default;
10 static std::shared_ptr<QPDFObject> create(); 10 static std::shared_ptr<QPDFObject> create();
  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);
11 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false); 19 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false);
12 virtual std::string unparse(); 20 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 21 virtual JSON getJSON(int json_version);
libqpdf/qpdf/QPDF_Stream.hh
@@ -27,7 +27,9 @@ class QPDF_Stream: public QPDFValue @@ -27,7 +27,9 @@ class QPDF_Stream: public QPDFValue
27 virtual std::string unparse(); 27 virtual std::string unparse();
28 virtual JSON getJSON(int json_version); 28 virtual JSON getJSON(int json_version);
29 virtual void setDescription( 29 virtual void setDescription(
30 - QPDF*, std::shared_ptr<std::string>& description, qpdf_offset_t offset); 30 + QPDF*,
  31 + std::shared_ptr<QPDFValue::Description>& description,
  32 + qpdf_offset_t offset);
31 virtual void disconnect(); 33 virtual void disconnect();
32 QPDFObjectHandle getDict() const; 34 QPDFObjectHandle getDict() const;
33 bool isDataModified() const; 35 bool isDataModified() const;