Commit 7b64f219a66de4803d37d1d3bd0ed43ec786e024
Committed by
GitHub
Merge pull request #901 from m-holger/jrrr
Refactor removal of reserved objects in QPDF::JSONReactor
Showing
3 changed files
with
51 additions
and
57 deletions
include/qpdf/JSON.hh
| @@ -54,6 +54,8 @@ class JSON | @@ -54,6 +54,8 @@ class JSON | ||
| 54 | { | 54 | { |
| 55 | public: | 55 | public: |
| 56 | static int constexpr LATEST = 2; | 56 | static int constexpr LATEST = 2; |
| 57 | + | ||
| 58 | + QPDF_DLL | ||
| 57 | JSON() = default; | 59 | JSON() = default; |
| 58 | 60 | ||
| 59 | QPDF_DLL | 61 | QPDF_DLL |
| @@ -369,7 +371,7 @@ class JSON | @@ -369,7 +371,7 @@ class JSON | ||
| 369 | } | 371 | } |
| 370 | virtual ~JSON_dictionary() = default; | 372 | virtual ~JSON_dictionary() = default; |
| 371 | virtual void write(Pipeline*, size_t depth) const; | 373 | virtual void write(Pipeline*, size_t depth) const; |
| 372 | - std::map<std::string, std::shared_ptr<JSON_value>> members; | 374 | + std::map<std::string, JSON> members; |
| 373 | std::set<std::string> parsed_keys; | 375 | std::set<std::string> parsed_keys; |
| 374 | }; | 376 | }; |
| 375 | struct JSON_array: public JSON_value | 377 | struct JSON_array: public JSON_value |
| @@ -380,7 +382,7 @@ class JSON | @@ -380,7 +382,7 @@ class JSON | ||
| 380 | } | 382 | } |
| 381 | virtual ~JSON_array() = default; | 383 | virtual ~JSON_array() = default; |
| 382 | virtual void write(Pipeline*, size_t depth) const; | 384 | virtual void write(Pipeline*, size_t depth) const; |
| 383 | - std::vector<std::shared_ptr<JSON_value>> elements; | 385 | + std::vector<JSON> elements; |
| 384 | }; | 386 | }; |
| 385 | struct JSON_string: public JSON_value | 387 | struct JSON_string: public JSON_value |
| 386 | { | 388 | { |
| @@ -423,7 +425,7 @@ class JSON | @@ -423,7 +425,7 @@ class JSON | ||
| 423 | std::function<void(Pipeline*)> fn; | 425 | std::function<void(Pipeline*)> fn; |
| 424 | }; | 426 | }; |
| 425 | 427 | ||
| 426 | - JSON(std::shared_ptr<JSON_value>); | 428 | + JSON(std::unique_ptr<JSON_value>); |
| 427 | 429 | ||
| 428 | static bool checkSchemaInternal( | 430 | static bool checkSchemaInternal( |
| 429 | JSON_value* this_v, | 431 | JSON_value* this_v, |
| @@ -441,13 +443,13 @@ class JSON | @@ -441,13 +443,13 @@ class JSON | ||
| 441 | ~Members() = default; | 443 | ~Members() = default; |
| 442 | 444 | ||
| 443 | private: | 445 | private: |
| 444 | - Members(std::shared_ptr<JSON_value>); | 446 | + Members(std::unique_ptr<JSON_value>); |
| 445 | Members(Members const&) = delete; | 447 | Members(Members const&) = delete; |
| 446 | 448 | ||
| 447 | - std::shared_ptr<JSON_value> value; | 449 | + std::unique_ptr<JSON_value> value; |
| 448 | // start and end are only populated for objects created by parse | 450 | // start and end are only populated for objects created by parse |
| 449 | - qpdf_offset_t start; | ||
| 450 | - qpdf_offset_t end; | 451 | + qpdf_offset_t start{0}; |
| 452 | + qpdf_offset_t end{0}; | ||
| 451 | }; | 453 | }; |
| 452 | 454 | ||
| 453 | std::shared_ptr<Members> m; | 455 | std::shared_ptr<Members> m; |
libqpdf/JSON.cc
| @@ -9,15 +9,13 @@ | @@ -9,15 +9,13 @@ | ||
| 9 | #include <cstring> | 9 | #include <cstring> |
| 10 | #include <stdexcept> | 10 | #include <stdexcept> |
| 11 | 11 | ||
| 12 | -JSON::Members::Members(std::shared_ptr<JSON_value> value) : | ||
| 13 | - value(value), | ||
| 14 | - start(0), | ||
| 15 | - end(0) | 12 | +JSON::Members::Members(std::unique_ptr<JSON_value> value) : |
| 13 | + value(std::move(value)) | ||
| 16 | { | 14 | { |
| 17 | } | 15 | } |
| 18 | 16 | ||
| 19 | -JSON::JSON(std::shared_ptr<JSON_value> value) : | ||
| 20 | - m(new Members(value)) | 17 | +JSON::JSON(std::unique_ptr<JSON_value> value) : |
| 18 | + m(new Members(std::move(value))) | ||
| 21 | { | 19 | { |
| 22 | } | 20 | } |
| 23 | 21 | ||
| @@ -278,7 +276,7 @@ JSON::encode_string(std::string const& str) | @@ -278,7 +276,7 @@ JSON::encode_string(std::string const& str) | ||
| 278 | JSON | 276 | JSON |
| 279 | JSON::makeDictionary() | 277 | JSON::makeDictionary() |
| 280 | { | 278 | { |
| 281 | - return JSON(std::make_shared<JSON_dictionary>()); | 279 | + return JSON(std::make_unique<JSON_dictionary>()); |
| 282 | } | 280 | } |
| 283 | 281 | ||
| 284 | JSON | 282 | JSON |
| @@ -286,7 +284,7 @@ JSON::addDictionaryMember(std::string const& key, JSON const& val) | @@ -286,7 +284,7 @@ JSON::addDictionaryMember(std::string const& key, JSON const& val) | ||
| 286 | { | 284 | { |
| 287 | if (auto* obj = dynamic_cast<JSON_dictionary*>(this->m->value.get())) { | 285 | if (auto* obj = dynamic_cast<JSON_dictionary*>(this->m->value.get())) { |
| 288 | return obj->members[encode_string(key)] = | 286 | return obj->members[encode_string(key)] = |
| 289 | - val.m->value ? val.m->value : std::make_shared<JSON_null>(); | 287 | + val.m->value ? val : makeNull(); |
| 290 | } else { | 288 | } else { |
| 291 | throw std::runtime_error( | 289 | throw std::runtime_error( |
| 292 | "JSON::addDictionaryMember called on non-dictionary"); | 290 | "JSON::addDictionaryMember called on non-dictionary"); |
| @@ -311,7 +309,7 @@ JSON::checkDictionaryKeySeen(std::string const& key) | @@ -311,7 +309,7 @@ JSON::checkDictionaryKeySeen(std::string const& key) | ||
| 311 | JSON | 309 | JSON |
| 312 | JSON::makeArray() | 310 | JSON::makeArray() |
| 313 | { | 311 | { |
| 314 | - return JSON(std::make_shared<JSON_array>()); | 312 | + return JSON(std::make_unique<JSON_array>()); |
| 315 | } | 313 | } |
| 316 | 314 | ||
| 317 | JSON | 315 | JSON |
| @@ -322,9 +320,9 @@ JSON::addArrayElement(JSON const& val) | @@ -322,9 +320,9 @@ JSON::addArrayElement(JSON const& val) | ||
| 322 | throw std::runtime_error("JSON::addArrayElement called on non-array"); | 320 | throw std::runtime_error("JSON::addArrayElement called on non-array"); |
| 323 | } | 321 | } |
| 324 | if (val.m->value.get()) { | 322 | if (val.m->value.get()) { |
| 325 | - arr->elements.push_back(val.m->value); | 323 | + arr->elements.push_back(val); |
| 326 | } else { | 324 | } else { |
| 327 | - arr->elements.push_back(std::make_shared<JSON_null>()); | 325 | + arr->elements.push_back(makeNull()); |
| 328 | } | 326 | } |
| 329 | return arr->elements.back(); | 327 | return arr->elements.back(); |
| 330 | } | 328 | } |
| @@ -332,43 +330,43 @@ JSON::addArrayElement(JSON const& val) | @@ -332,43 +330,43 @@ JSON::addArrayElement(JSON const& val) | ||
| 332 | JSON | 330 | JSON |
| 333 | JSON::makeString(std::string const& utf8) | 331 | JSON::makeString(std::string const& utf8) |
| 334 | { | 332 | { |
| 335 | - return JSON(std::make_shared<JSON_string>(utf8)); | 333 | + return JSON(std::make_unique<JSON_string>(utf8)); |
| 336 | } | 334 | } |
| 337 | 335 | ||
| 338 | JSON | 336 | JSON |
| 339 | JSON::makeInt(long long int value) | 337 | JSON::makeInt(long long int value) |
| 340 | { | 338 | { |
| 341 | - return JSON(std::make_shared<JSON_number>(value)); | 339 | + return JSON(std::make_unique<JSON_number>(value)); |
| 342 | } | 340 | } |
| 343 | 341 | ||
| 344 | JSON | 342 | JSON |
| 345 | JSON::makeReal(double value) | 343 | JSON::makeReal(double value) |
| 346 | { | 344 | { |
| 347 | - return JSON(std::make_shared<JSON_number>(value)); | 345 | + return JSON(std::make_unique<JSON_number>(value)); |
| 348 | } | 346 | } |
| 349 | 347 | ||
| 350 | JSON | 348 | JSON |
| 351 | JSON::makeNumber(std::string const& encoded) | 349 | JSON::makeNumber(std::string const& encoded) |
| 352 | { | 350 | { |
| 353 | - return JSON(std::make_shared<JSON_number>(encoded)); | 351 | + return JSON(std::make_unique<JSON_number>(encoded)); |
| 354 | } | 352 | } |
| 355 | 353 | ||
| 356 | JSON | 354 | JSON |
| 357 | JSON::makeBool(bool value) | 355 | JSON::makeBool(bool value) |
| 358 | { | 356 | { |
| 359 | - return JSON(std::make_shared<JSON_bool>(value)); | 357 | + return JSON(std::make_unique<JSON_bool>(value)); |
| 360 | } | 358 | } |
| 361 | 359 | ||
| 362 | JSON | 360 | JSON |
| 363 | JSON::makeNull() | 361 | JSON::makeNull() |
| 364 | { | 362 | { |
| 365 | - return JSON(std::make_shared<JSON_null>()); | 363 | + return JSON(std::make_unique<JSON_null>()); |
| 366 | } | 364 | } |
| 367 | 365 | ||
| 368 | JSON | 366 | JSON |
| 369 | JSON::makeBlob(std::function<void(Pipeline*)> fn) | 367 | JSON::makeBlob(std::function<void(Pipeline*)> fn) |
| 370 | { | 368 | { |
| 371 | - return JSON(std::make_shared<JSON_blob>(fn)); | 369 | + return JSON(std::make_unique<JSON_blob>(fn)); |
| 372 | } | 370 | } |
| 373 | 371 | ||
| 374 | bool | 372 | bool |
| @@ -504,11 +502,11 @@ JSON::checkSchemaInternal( | @@ -504,11 +502,11 @@ JSON::checkSchemaInternal( | ||
| 504 | } | 502 | } |
| 505 | 503 | ||
| 506 | if (sch_dict && (!pattern_key.empty())) { | 504 | if (sch_dict && (!pattern_key.empty())) { |
| 507 | - auto pattern_schema = sch_dict->members[pattern_key].get(); | 505 | + auto pattern_schema = sch_dict->members[pattern_key].m->value.get(); |
| 508 | for (auto const& iter: this_dict->members) { | 506 | for (auto const& iter: this_dict->members) { |
| 509 | std::string const& key = iter.first; | 507 | std::string const& key = iter.first; |
| 510 | checkSchemaInternal( | 508 | checkSchemaInternal( |
| 511 | - this_dict->members[key].get(), | 509 | + this_dict->members[key].m->value.get(), |
| 512 | pattern_schema, | 510 | pattern_schema, |
| 513 | flags, | 511 | flags, |
| 514 | errors, | 512 | errors, |
| @@ -519,8 +517,8 @@ JSON::checkSchemaInternal( | @@ -519,8 +517,8 @@ JSON::checkSchemaInternal( | ||
| 519 | std::string const& key = iter.first; | 517 | std::string const& key = iter.first; |
| 520 | if (this_dict->members.count(key)) { | 518 | if (this_dict->members.count(key)) { |
| 521 | checkSchemaInternal( | 519 | checkSchemaInternal( |
| 522 | - this_dict->members[key].get(), | ||
| 523 | - iter.second.get(), | 520 | + this_dict->members[key].m->value.get(), |
| 521 | + iter.second.m->value.get(), | ||
| 524 | flags, | 522 | flags, |
| 525 | errors, | 523 | errors, |
| 526 | prefix + "." + key); | 524 | prefix + "." + key); |
| @@ -557,8 +555,8 @@ JSON::checkSchemaInternal( | @@ -557,8 +555,8 @@ JSON::checkSchemaInternal( | ||
| 557 | int i = 0; | 555 | int i = 0; |
| 558 | for (auto const& element: this_arr->elements) { | 556 | for (auto const& element: this_arr->elements) { |
| 559 | checkSchemaInternal( | 557 | checkSchemaInternal( |
| 560 | - element.get(), | ||
| 561 | - sch_arr->elements.at(0).get(), | 558 | + element.m->value.get(), |
| 559 | + sch_arr->elements.at(0).m->value.get(), | ||
| 562 | flags, | 560 | flags, |
| 563 | errors, | 561 | errors, |
| 564 | prefix + "." + std::to_string(i)); | 562 | prefix + "." + std::to_string(i)); |
| @@ -568,7 +566,7 @@ JSON::checkSchemaInternal( | @@ -568,7 +566,7 @@ JSON::checkSchemaInternal( | ||
| 568 | QTC::TC("libtests", "JSON schema array for single item"); | 566 | QTC::TC("libtests", "JSON schema array for single item"); |
| 569 | checkSchemaInternal( | 567 | checkSchemaInternal( |
| 570 | this_v, | 568 | this_v, |
| 571 | - sch_arr->elements.at(0).get(), | 569 | + sch_arr->elements.at(0).m->value.get(), |
| 572 | flags, | 570 | flags, |
| 573 | errors, | 571 | errors, |
| 574 | prefix); | 572 | prefix); |
| @@ -587,8 +585,8 @@ JSON::checkSchemaInternal( | @@ -587,8 +585,8 @@ JSON::checkSchemaInternal( | ||
| 587 | size_t i = 0; | 585 | size_t i = 0; |
| 588 | for (auto const& element: this_arr->elements) { | 586 | for (auto const& element: this_arr->elements) { |
| 589 | checkSchemaInternal( | 587 | checkSchemaInternal( |
| 590 | - element.get(), | ||
| 591 | - sch_arr->elements.at(i).get(), | 588 | + element.m->value.get(), |
| 589 | + sch_arr->elements.at(i).m->value.get(), | ||
| 592 | flags, | 590 | flags, |
| 593 | errors, | 591 | errors, |
| 594 | prefix + "." + std::to_string(i)); | 592 | prefix + "." + std::to_string(i)); |
libqpdf/QPDF_json.cc
| @@ -6,6 +6,7 @@ | @@ -6,6 +6,7 @@ | ||
| 6 | #include <qpdf/QIntC.hh> | 6 | #include <qpdf/QIntC.hh> |
| 7 | #include <qpdf/QPDFObject_private.hh> | 7 | #include <qpdf/QPDFObject_private.hh> |
| 8 | #include <qpdf/QPDFValue.hh> | 8 | #include <qpdf/QPDFValue.hh> |
| 9 | +#include <qpdf/QPDF_Null.hh> | ||
| 9 | #include <qpdf/QTC.hh> | 10 | #include <qpdf/QTC.hh> |
| 10 | #include <qpdf/QUtil.hh> | 11 | #include <qpdf/QUtil.hh> |
| 11 | #include <algorithm> | 12 | #include <algorithm> |
| @@ -234,6 +235,11 @@ class QPDF::JSONReactor: public JSON::Reactor | @@ -234,6 +235,11 @@ class QPDF::JSONReactor: public JSON::Reactor | ||
| 234 | descr(std::make_shared<QPDFValue::Description>(QPDFValue::JSON_Descr( | 235 | descr(std::make_shared<QPDFValue::Description>(QPDFValue::JSON_Descr( |
| 235 | std::make_shared<std::string>(is->getName()), ""))) | 236 | std::make_shared<std::string>(is->getName()), ""))) |
| 236 | { | 237 | { |
| 238 | + for (auto& oc: pdf.m->obj_cache) { | ||
| 239 | + if (oc.second.object->getTypeCode() == ::ot_reserved) { | ||
| 240 | + reserved.insert(oc.first); | ||
| 241 | + } | ||
| 242 | + } | ||
| 237 | } | 243 | } |
| 238 | virtual ~JSONReactor() = default; | 244 | virtual ~JSONReactor() = default; |
| 239 | virtual void dictionaryStart() override; | 245 | virtual void dictionaryStart() override; |
| @@ -265,7 +271,6 @@ class QPDF::JSONReactor: public JSON::Reactor | @@ -265,7 +271,6 @@ class QPDF::JSONReactor: public JSON::Reactor | ||
| 265 | void setObjectDescription(QPDFObjectHandle& oh, JSON const& value); | 271 | void setObjectDescription(QPDFObjectHandle& oh, JSON const& value); |
| 266 | QPDFObjectHandle makeObject(JSON const& value); | 272 | QPDFObjectHandle makeObject(JSON const& value); |
| 267 | void error(qpdf_offset_t offset, std::string const& message); | 273 | void error(qpdf_offset_t offset, std::string const& message); |
| 268 | - QPDFObjectHandle reserveObject(int obj, int gen); | ||
| 269 | void replaceObject( | 274 | void replaceObject( |
| 270 | QPDFObjectHandle to_replace, | 275 | QPDFObjectHandle to_replace, |
| 271 | QPDFObjectHandle replacement, | 276 | QPDFObjectHandle replacement, |
| @@ -416,27 +421,17 @@ QPDF::JSONReactor::containerEnd(JSON const& value) | @@ -416,27 +421,17 @@ QPDF::JSONReactor::containerEnd(JSON const& value) | ||
| 416 | object_stack.pop_back(); | 421 | object_stack.pop_back(); |
| 417 | } | 422 | } |
| 418 | } else if ((state == st_top) && (from_state == st_qpdf)) { | 423 | } else if ((state == st_top) && (from_state == st_qpdf)) { |
| 419 | - for (auto const& og: this->reserved) { | ||
| 420 | - // Handle dangling indirect object references which the | ||
| 421 | - // PDF spec says to treat as nulls. It's tempting to make | ||
| 422 | - // this an error, but that would be wrong since valid | ||
| 423 | - // input files may have these. | ||
| 424 | - QTC::TC("qpdf", "QPDF_json non-trivial null reserved"); | ||
| 425 | - this->pdf.replaceObject(og, QPDFObjectHandle::newNull()); | 424 | + // Handle dangling indirect object references which the PDF spec says to |
| 425 | + // treat as nulls. It's tempting to make this an error, but that would | ||
| 426 | + // be wrong since valid input files may have these. | ||
| 427 | + for (auto& oc: pdf.m->obj_cache) { | ||
| 428 | + if (oc.second.object->getTypeCode() == ::ot_reserved && | ||
| 429 | + reserved.count(oc.first) == 0) { | ||
| 430 | + QTC::TC("qpdf", "QPDF_json non-trivial null reserved"); | ||
| 431 | + pdf.updateCache(oc.first, QPDF_Null::create(), -1, -1); | ||
| 432 | + } | ||
| 426 | } | 433 | } |
| 427 | - this->reserved.clear(); | ||
| 428 | - } | ||
| 429 | -} | ||
| 430 | - | ||
| 431 | -QPDFObjectHandle | ||
| 432 | -QPDF::JSONReactor::reserveObject(int obj, int gen) | ||
| 433 | -{ | ||
| 434 | - QPDFObjGen og(obj, gen); | ||
| 435 | - auto oh = pdf.reserveObjectIfNotExists(og); | ||
| 436 | - if (oh.isReserved()) { | ||
| 437 | - this->reserved.insert(og); | ||
| 438 | } | 434 | } |
| 439 | - return oh; | ||
| 440 | } | 435 | } |
| 441 | 436 | ||
| 442 | void | 437 | void |
| @@ -446,7 +441,6 @@ QPDF::JSONReactor::replaceObject( | @@ -446,7 +441,6 @@ QPDF::JSONReactor::replaceObject( | ||
| 446 | JSON const& value) | 441 | JSON const& value) |
| 447 | { | 442 | { |
| 448 | auto og = to_replace.getObjGen(); | 443 | auto og = to_replace.getObjGen(); |
| 449 | - this->reserved.erase(og); | ||
| 450 | this->pdf.replaceObject(og, replacement); | 444 | this->pdf.replaceObject(og, replacement); |
| 451 | auto oh = pdf.getObject(og); | 445 | auto oh = pdf.getObject(og); |
| 452 | setObjectDescription(oh, value); | 446 | setObjectDescription(oh, value); |
| @@ -564,7 +558,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | @@ -564,7 +558,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | ||
| 564 | this->cur_object = "trailer"; | 558 | this->cur_object = "trailer"; |
| 565 | } else if (is_obj_key(key, obj, gen)) { | 559 | } else if (is_obj_key(key, obj, gen)) { |
| 566 | this->cur_object = key; | 560 | this->cur_object = key; |
| 567 | - auto oh = reserveObject(obj, gen); | 561 | + auto oh = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen)); |
| 568 | object_stack.push_back(oh); | 562 | object_stack.push_back(oh); |
| 569 | nestedState(key, value, st_object_top); | 563 | nestedState(key, value, st_object_top); |
| 570 | } else { | 564 | } else { |
| @@ -763,7 +757,7 @@ QPDF::JSONReactor::makeObject(JSON const& value) | @@ -763,7 +757,7 @@ QPDF::JSONReactor::makeObject(JSON const& value) | ||
| 763 | int gen = 0; | 757 | int gen = 0; |
| 764 | std::string str; | 758 | std::string str; |
| 765 | if (is_indirect_object(str_v, obj, gen)) { | 759 | if (is_indirect_object(str_v, obj, gen)) { |
| 766 | - result = reserveObject(obj, gen); | 760 | + result = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen)); |
| 767 | } else if (is_unicode_string(str_v, str)) { | 761 | } else if (is_unicode_string(str_v, str)) { |
| 768 | result = QPDFObjectHandle::newUnicodeString(str); | 762 | result = QPDFObjectHandle::newUnicodeString(str); |
| 769 | } else if (is_binary_string(str_v, str)) { | 763 | } else if (is_binary_string(str_v, str)) { |