Commit 7b64f219a66de4803d37d1d3bd0ed43ec786e024

Authored by Jay Berkenbilt
Committed by GitHub
2 parents b4c36d9b f099246b

Merge pull request #901 from m-holger/jrrr

Refactor removal of reserved objects in QPDF::JSONReactor
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&amp; str) @@ -278,7 +276,7 @@ JSON::encode_string(std::string const&amp; 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&amp; key, JSON const&amp; val) @@ -286,7 +284,7 @@ JSON::addDictionaryMember(std::string const&amp; key, JSON const&amp; 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&amp; key) @@ -311,7 +309,7 @@ JSON::checkDictionaryKeySeen(std::string const&amp; 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&amp; val) @@ -322,9 +320,9 @@ JSON::addArrayElement(JSON const&amp; 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&amp; val) @@ -332,43 +330,43 @@ JSON::addArrayElement(JSON const&amp; 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&amp; value) @@ -416,27 +421,17 @@ QPDF::JSONReactor::containerEnd(JSON const&amp; 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&amp; key, JSON const&amp; value) @@ -564,7 +558,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; 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&amp; value) @@ -763,7 +757,7 @@ QPDF::JSONReactor::makeObject(JSON const&amp; 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)) {