Commit b3cfa1010f95514a13590266dd50677445f74309
Committed by
GitHub
Merge pull request #902 from m-holger/od
Refactor creation of object descriptions
Showing
12 changed files
with
264 additions
and
133 deletions
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& key) | @@ -1030,24 +1025,15 @@ QPDFObjectHandle::hasKey(std::string const& 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& key) | @@ -97,12 +101,8 @@ QPDF_Dictionary::getKey(std::string const& 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& value) | @@ -675,12 +745,13 @@ QPDF::JSONReactor::arrayItem(JSON const& 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; |