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 | 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 | 1113 | void parse(char const* password); |
| 1178 | 1114 | void inParse(bool); | ... | ... |
libqpdf/QPDFObjectHandle.cc
| ... | ... | @@ -36,6 +36,8 @@ |
| 36 | 36 | #include <stdexcept> |
| 37 | 37 | #include <stdlib.h> |
| 38 | 38 | |
| 39 | +using namespace std::literals; | |
| 40 | + | |
| 39 | 41 | namespace |
| 40 | 42 | { |
| 41 | 43 | class TerminateParsing |
| ... | ... | @@ -800,12 +802,10 @@ QPDFObjectHandle::getArrayNItems() |
| 800 | 802 | QPDFObjectHandle |
| 801 | 803 | QPDFObjectHandle::getArrayItem(int n) |
| 802 | 804 | { |
| 803 | - QPDFObjectHandle result; | |
| 804 | 805 | auto array = asArray(); |
| 805 | 806 | if (array && (n < array->getNItems()) && (n >= 0)) { |
| 806 | - result = array->getItem(n); | |
| 807 | + return array->getItem(n); | |
| 807 | 808 | } else { |
| 808 | - result = newNull(); | |
| 809 | 809 | if (array) { |
| 810 | 810 | objectWarning("returning null for out of bounds array access"); |
| 811 | 811 | QTC::TC("qpdf", "QPDFObjectHandle array bounds"); |
| ... | ... | @@ -813,15 +813,10 @@ QPDFObjectHandle::getArrayItem(int n) |
| 813 | 813 | typeWarning("array", "returning null"); |
| 814 | 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 | 822 | bool |
| ... | ... | @@ -1030,24 +1025,15 @@ QPDFObjectHandle::hasKey(std::string const& key) |
| 1030 | 1025 | QPDFObjectHandle |
| 1031 | 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 | 1030 | } else { |
| 1038 | 1031 | typeWarning("dictionary", "returning null for attempted key retrieval"); |
| 1039 | 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 | 1039 | QPDFObjectHandle |
| ... | ... | @@ -2176,7 +2162,8 @@ QPDFObjectHandle::setObjectDescription( |
| 2176 | 2162 | // This is called during parsing on newly created direct objects, |
| 2177 | 2163 | // so we can't call dereference() here. |
| 2178 | 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 | 2167 | obj->setDescription(owning_qpdf, descr); |
| 2181 | 2168 | } |
| 2182 | 2169 | } | ... | ... |
libqpdf/QPDFValue.cc
| ... | ... | @@ -9,3 +9,58 @@ QPDFValue::do_create(QPDFValue* object) |
| 9 | 9 | obj->value = std::shared_ptr<QPDFValue>(object); |
| 10 | 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 | 1 | #include <qpdf/QPDF_Dictionary.hh> |
| 2 | 2 | |
| 3 | +#include <qpdf/QPDFObject_private.hh> | |
| 3 | 4 | #include <qpdf/QPDF_Name.hh> |
| 5 | +#include <qpdf/QPDF_Null.hh> | |
| 6 | + | |
| 7 | +using namespace std::literals; | |
| 4 | 8 | |
| 5 | 9 | QPDF_Dictionary::QPDF_Dictionary( |
| 6 | 10 | std::map<std::string, QPDFObjectHandle> const& items) : |
| ... | ... | @@ -97,12 +101,8 @@ QPDF_Dictionary::getKey(std::string const& key) |
| 97 | 101 | // May be a null object |
| 98 | 102 | return item->second; |
| 99 | 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 | 1 | #include <qpdf/QPDF_Null.hh> |
| 2 | 2 | |
| 3 | +#include <qpdf/QPDFObject_private.hh> | |
| 4 | + | |
| 3 | 5 | QPDF_Null::QPDF_Null() : |
| 4 | 6 | QPDFValue(::ot_null, "null") |
| 5 | 7 | { |
| ... | ... | @@ -12,6 +14,28 @@ QPDF_Null::create() |
| 12 | 14 | } |
| 13 | 15 | |
| 14 | 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 | 39 | QPDF_Null::copy(bool shallow) |
| 16 | 40 | { |
| 17 | 41 | return create(); | ... | ... |
libqpdf/QPDF_Stream.cc
| ... | ... | @@ -123,7 +123,7 @@ QPDF_Stream::QPDF_Stream( |
| 123 | 123 | throw std::logic_error("stream object instantiated with non-dictionary " |
| 124 | 124 | "object for dictionary"); |
| 125 | 125 | } |
| 126 | - auto descr = std::make_shared<std::string>( | |
| 126 | + auto descr = std::make_shared<QPDFValue::Description>( | |
| 127 | 127 | qpdf->getFilename() + ", stream object " + og.unparse(' ')); |
| 128 | 128 | setDescription(qpdf, descr, offset); |
| 129 | 129 | } |
| ... | ... | @@ -283,7 +283,9 @@ QPDF_Stream::getStreamJSON( |
| 283 | 283 | |
| 284 | 284 | void |
| 285 | 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 | 290 | this->QPDFValue::setDescription(qpdf, description, offset); |
| 289 | 291 | setDictDescription(); | ... | ... |
libqpdf/QPDF_json.cc
| ... | ... | @@ -4,6 +4,8 @@ |
| 4 | 4 | #include <qpdf/Pl_Base64.hh> |
| 5 | 5 | #include <qpdf/Pl_StdioFile.hh> |
| 6 | 6 | #include <qpdf/QIntC.hh> |
| 7 | +#include <qpdf/QPDFObject_private.hh> | |
| 8 | +#include <qpdf/QPDFValue.hh> | |
| 7 | 9 | #include <qpdf/QTC.hh> |
| 8 | 10 | #include <qpdf/QUtil.hh> |
| 9 | 11 | #include <algorithm> |
| ... | ... | @@ -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 | 292 | QPDF::JSONReactor::JSONReactor( |
| 225 | 293 | QPDF& pdf, std::shared_ptr<InputSource> is, bool must_be_complete) : |
| 226 | 294 | pdf(pdf), |
| 227 | 295 | is(is), |
| 228 | 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 | 299 | errors(false), |
| 230 | 300 | parse_error(false), |
| 231 | 301 | saw_qpdf(false), |
| ... | ... | @@ -675,12 +745,13 @@ QPDF::JSONReactor::arrayItem(JSON const& value) |
| 675 | 745 | void |
| 676 | 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 | 757 | QPDFObjectHandle | ... | ... |
libqpdf/qpdf/QPDFObject_private.hh
| ... | ... | @@ -12,6 +12,7 @@ |
| 12 | 12 | #include <qpdf/Types.h> |
| 13 | 13 | |
| 14 | 14 | #include <string> |
| 15 | +#include <string_view> | |
| 15 | 16 | |
| 16 | 17 | class QPDF; |
| 17 | 18 | class QPDFObjectHandle; |
| ... | ... | @@ -71,11 +72,30 @@ class QPDFObject |
| 71 | 72 | void |
| 72 | 73 | setDescription( |
| 73 | 74 | QPDF* qpdf, |
| 74 | - std::shared_ptr<std::string>& description, | |
| 75 | + std::shared_ptr<QPDFValue::Description>& description, | |
| 75 | 76 | qpdf_offset_t offset = -1) |
| 76 | 77 | { |
| 77 | 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 | 99 | bool |
| 80 | 100 | getDescription(QPDF*& qpdf, std::string& description) |
| 81 | 101 | { | ... | ... |
libqpdf/qpdf/QPDFParser.hh
| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | #define QPDFPARSER_HH |
| 3 | 3 | |
| 4 | 4 | #include <qpdf/QPDFObjectHandle.hh> |
| 5 | +#include <qpdf/QPDFValue.hh> | |
| 5 | 6 | |
| 6 | 7 | #include <memory> |
| 7 | 8 | #include <string> |
| ... | ... | @@ -21,8 +22,8 @@ class QPDFParser |
| 21 | 22 | tokenizer(tokenizer), |
| 22 | 23 | decrypter(decrypter), |
| 23 | 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 | 29 | virtual ~QPDFParser() = default; |
| ... | ... | @@ -49,7 +50,7 @@ class QPDFParser |
| 49 | 50 | QPDFTokenizer& tokenizer; |
| 50 | 51 | QPDFObjectHandle::StringDecrypter* decrypter; |
| 51 | 52 | QPDF* context; |
| 52 | - std::shared_ptr<std::string> description; | |
| 53 | + std::shared_ptr<QPDFValue::Description> description; | |
| 53 | 54 | }; |
| 54 | 55 | |
| 55 | 56 | #endif // QPDFPARSER_HH | ... | ... |
libqpdf/qpdf/QPDFValue.hh
| ... | ... | @@ -8,12 +8,14 @@ |
| 8 | 8 | #include <qpdf/Types.h> |
| 9 | 9 | |
| 10 | 10 | #include <string> |
| 11 | +#include <string_view> | |
| 12 | +#include <variant> | |
| 11 | 13 | |
| 12 | 14 | class QPDF; |
| 13 | 15 | class QPDFObjectHandle; |
| 14 | 16 | class QPDFObject; |
| 15 | 17 | |
| 16 | -class QPDFValue | |
| 18 | +class QPDFValue: public std::enable_shared_from_this<QPDFValue> | |
| 17 | 19 | { |
| 18 | 20 | friend class QPDFObject; |
| 19 | 21 | |
| ... | ... | @@ -23,10 +25,43 @@ class QPDFValue |
| 23 | 25 | virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0; |
| 24 | 26 | virtual std::string unparse() = 0; |
| 25 | 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 | 61 | virtual void |
| 27 | 62 | setDescription( |
| 28 | 63 | QPDF* qpdf_p, |
| 29 | - std::shared_ptr<std::string>& description, | |
| 64 | + std::shared_ptr<Description>& description, | |
| 30 | 65 | qpdf_offset_t offset) |
| 31 | 66 | { |
| 32 | 67 | qpdf = qpdf_p; |
| ... | ... | @@ -36,35 +71,25 @@ class QPDFValue |
| 36 | 71 | void |
| 37 | 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 | 74 | qpdf = a_qpdf; |
| 45 | 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 | 89 | bool |
| 64 | 90 | hasDescription() |
| 65 | 91 | { |
| 66 | - return qpdf != nullptr && object_description && | |
| 67 | - !object_description->empty(); | |
| 92 | + return object_description || og.isIndirect(); | |
| 68 | 93 | } |
| 69 | 94 | void |
| 70 | 95 | setParsedOffset(qpdf_offset_t offset) |
| ... | ... | @@ -123,7 +148,7 @@ class QPDFValue |
| 123 | 148 | private: |
| 124 | 149 | QPDFValue(QPDFValue const&) = delete; |
| 125 | 150 | QPDFValue& operator=(QPDFValue const&) = delete; |
| 126 | - std::shared_ptr<std::string> object_description; | |
| 151 | + std::shared_ptr<Description> object_description; | |
| 127 | 152 | |
| 128 | 153 | const qpdf_object_type_e type_code{::ot_uninitialized}; |
| 129 | 154 | char const* type_name{"uninitialized"}; | ... | ... |
libqpdf/qpdf/QPDF_Null.hh
| ... | ... | @@ -8,6 +8,14 @@ class QPDF_Null: public QPDFValue |
| 8 | 8 | public: |
| 9 | 9 | virtual ~QPDF_Null() = default; |
| 10 | 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 | 19 | virtual std::shared_ptr<QPDFObject> copy(bool shallow = false); |
| 12 | 20 | virtual std::string unparse(); |
| 13 | 21 | virtual JSON getJSON(int json_version); | ... | ... |
libqpdf/qpdf/QPDF_Stream.hh
| ... | ... | @@ -27,7 +27,9 @@ class QPDF_Stream: public QPDFValue |
| 27 | 27 | virtual std::string unparse(); |
| 28 | 28 | virtual JSON getJSON(int json_version); |
| 29 | 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 | 33 | virtual void disconnect(); |
| 32 | 34 | QPDFObjectHandle getDict() const; |
| 33 | 35 | bool isDataModified() const; | ... | ... |