Commit 884d36becd8403eefa9cbaceb7d85b37ecaa61c5

Authored by m-holger
Committed by GitHub
2 parents 00ad6f55 f78b9993

Merge pull request #1380 from m-holger/object

Move QPDFObject::copy, disconnect, unparse and write_json to BaseHandle
include/qpdf/ObjectHandle.hh
... ... @@ -47,6 +47,8 @@ namespace qpdf
47 47 // QPDFObjGen and bool.
48 48 class BaseHandle
49 49 {
  50 + friend class QPDF;
  51 +
50 52 public:
51 53 explicit inline operator bool() const;
52 54 inline operator QPDFObjectHandle() const;
... ... @@ -54,12 +56,18 @@ namespace qpdf
54 56  
55 57 // The rest of the header file is for qpdf internal use only.
56 58  
  59 + std::shared_ptr<QPDFObject> copy(bool shallow = false) const;
  60 + // Recursively remove association with any QPDF object. This method may only be called
  61 + // during final destruction.
  62 + void disconnect(bool only_direct = true);
57 63 inline QPDFObjGen id_gen() const;
58 64 inline bool indirect() const;
59 65 inline bool null() const;
60 66 inline QPDF* qpdf() const;
61 67 inline qpdf_object_type_e raw_type_code() const;
62 68 inline qpdf_object_type_e type_code() const;
  69 + std::string unparse() const;
  70 + void write_json(int json_version, JSON::Writer& p) const;
63 71  
64 72 protected:
65 73 BaseHandle() = default;
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -1242,19 +1242,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle
1242 1242 QPDF_DLL
1243 1243 void warnIfPossible(std::string const& warning) const;
1244 1244  
1245   - // Provide access to specific classes for recursive disconnected().
1246   - class DisconnectAccess
1247   - {
1248   - friend class QPDFObject;
1249   -
1250   - private:
1251   - static void
1252   - disconnect(QPDFObjectHandle o)
1253   - {
1254   - o.disconnect();
1255   - }
1256   - };
1257   -
1258 1245 // Convenience routine: Throws if the assumption is violated. Your code will be better if you
1259 1246 // call one of the isType methods and handle the case of the type being wrong, but these can be
1260 1247 // convenient if you have already verified the type.
... ... @@ -1354,7 +1341,6 @@ class QPDFObjectHandle final: public qpdf::BaseHandle
1354 1341 void objectWarning(std::string const& warning) const;
1355 1342 void assertType(char const* type_name, bool istype) const;
1356 1343 void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams);
1357   - void disconnect();
1358 1344 void setParsedOffset(qpdf_offset_t offset);
1359 1345 void parseContentStream_internal(std::string const& description, ParserCallbacks* callbacks);
1360 1346 static void parseContentStream_data(
... ...
libqpdf/QPDF.cc
... ... @@ -212,6 +212,25 @@ QPDF::QPDF() :
212 212 m->unique_id = unique_id.fetch_add(1ULL);
213 213 }
214 214  
  215 +// Provide access to disconnect(). Disconnect will in due course be merged into the current ObjCache
  216 +// (future Objects::Entry) to centralize all QPDF access to QPDFObject.
  217 +class Disconnect: BaseHandle
  218 +{
  219 + public:
  220 + Disconnect(std::shared_ptr<QPDFObject> const& obj) :
  221 + BaseHandle(obj)
  222 + {
  223 + }
  224 + void
  225 + disconnect()
  226 + {
  227 + BaseHandle::disconnect(false);
  228 + if (raw_type_code() != ::ot_null) {
  229 + obj->value = QPDF_Destroyed();
  230 + }
  231 + }
  232 +};
  233 +
215 234 QPDF::~QPDF()
216 235 {
217 236 // If two objects are mutually referential (through each object having an array or dictionary
... ... @@ -228,10 +247,7 @@ QPDF::~QPDF()
228 247 // the xref table anyway just to prevent any possibility of resolve() succeeding.
229 248 m->xref_table.clear();
230 249 for (auto const& iter: m->obj_cache) {
231   - iter.second.object->disconnect();
232   - if (iter.second.object->getTypeCode() != ::ot_null) {
233   - iter.second.object->destroy();
234   - }
  250 + Disconnect(iter.second.object).disconnect();
235 251 }
236 252 }
237 253  
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -289,29 +289,29 @@ Name::normalize(std::string const&amp; name)
289 289 }
290 290  
291 291 std::shared_ptr<QPDFObject>
292   -QPDFObject::copy(bool shallow)
  292 +BaseHandle::copy(bool shallow) const
293 293 {
294   - switch (getResolvedTypeCode()) {
  294 + switch (type_code()) {
295 295 case ::ot_uninitialized:
296 296 throw std::logic_error("QPDFObjectHandle: attempting to copy an uninitialized object");
297 297 return {}; // does not return
298 298 case ::ot_reserved:
299   - return create<QPDF_Reserved>();
  299 + return QPDFObject::create<QPDF_Reserved>();
300 300 case ::ot_null:
301   - return create<QPDF_Null>();
  301 + return QPDFObject::create<QPDF_Null>();
302 302 case ::ot_boolean:
303   - return create<QPDF_Bool>(std::get<QPDF_Bool>(value).val);
  303 + return QPDFObject::create<QPDF_Bool>(std::get<QPDF_Bool>(obj->value).val);
304 304 case ::ot_integer:
305   - return create<QPDF_Integer>(std::get<QPDF_Integer>(value).val);
  305 + return QPDFObject::create<QPDF_Integer>(std::get<QPDF_Integer>(obj->value).val);
306 306 case ::ot_real:
307   - return create<QPDF_Real>(std::get<QPDF_Real>(value).val);
  307 + return QPDFObject::create<QPDF_Real>(std::get<QPDF_Real>(obj->value).val);
308 308 case ::ot_string:
309   - return create<QPDF_String>(std::get<QPDF_String>(value).val);
  309 + return QPDFObject::create<QPDF_String>(std::get<QPDF_String>(obj->value).val);
310 310 case ::ot_name:
311   - return create<QPDF_Name>(std::get<QPDF_Name>(value).name);
  311 + return QPDFObject::create<QPDF_Name>(std::get<QPDF_Name>(obj->value).name);
312 312 case ::ot_array:
313 313 {
314   - auto const& a = std::get<QPDF_Array>(value);
  314 + auto const& a = std::get<QPDF_Array>(obj->value);
315 315 if (shallow) {
316 316 return QPDFObject::create<QPDF_Array>(a);
317 317 } else {
... ... @@ -321,7 +321,7 @@ QPDFObject::copy(bool shallow)
321 321 result.sp = std::make_unique<QPDF_Array::Sparse>();
322 322 result.sp->size = a.sp->size;
323 323 for (auto const& [idx, oh]: a.sp->elements) {
324   - result.sp->elements[idx] = oh.indirect() ? oh : oh.getObj()->copy();
  324 + result.sp->elements[idx] = oh.indirect() ? oh : oh.copy();
325 325 }
326 326 return QPDFObject::create<QPDF_Array>(std::move(result));
327 327 } else {
... ... @@ -329,8 +329,7 @@ QPDFObject::copy(bool shallow)
329 329 result.reserve(a.elements.size());
330 330 for (auto const& element: a.elements) {
331 331 result.emplace_back(
332   - element ? (element.indirect() ? element : element.getObj()->copy())
333   - : element);
  332 + element ? (element.indirect() ? element : element.copy()) : element);
334 333 }
335 334 return QPDFObject::create<QPDF_Array>(std::move(result), false);
336 335 }
... ... @@ -338,13 +337,13 @@ QPDFObject::copy(bool shallow)
338 337 }
339 338 case ::ot_dictionary:
340 339 {
341   - auto const& d = std::get<QPDF_Dictionary>(value);
  340 + auto const& d = std::get<QPDF_Dictionary>(obj->value);
342 341 if (shallow) {
343 342 return QPDFObject::create<QPDF_Dictionary>(d.items);
344 343 } else {
345 344 std::map<std::string, QPDFObjectHandle> new_items;
346 345 for (auto const& [key, val]: d.items) {
347   - new_items[key] = val.indirect() ? val : val.getObj()->copy();
  346 + new_items[key] = val.indirect() ? val : val.copy();
348 347 }
349 348 return QPDFObject::create<QPDF_Dictionary>(new_items);
350 349 }
... ... @@ -354,9 +353,9 @@ QPDFObject::copy(bool shallow)
354 353 throw std::runtime_error("stream objects cannot be cloned");
355 354 return {}; // does not return
356 355 case ::ot_operator:
357   - return create<QPDF_Operator>(std::get<QPDF_Operator>(value).val);
  356 + return QPDFObject::create<QPDF_Operator>(std::get<QPDF_Operator>(obj->value).val);
358 357 case ::ot_inlineimage:
359   - return create<QPDF_InlineImage>(std::get<QPDF_InlineImage>(value).val);
  358 + return QPDFObject::create<QPDF_InlineImage>(std::get<QPDF_InlineImage>(obj->value).val);
360 359 case ::ot_unresolved:
361 360 throw std::logic_error("QPDFObjectHandle: attempting to unparse a reserved object");
362 361 return {}; // does not return
... ... @@ -364,15 +363,15 @@ QPDFObject::copy(bool shallow)
364 363 throw std::logic_error("attempted to shallow copy QPDFObjectHandle from destroyed QPDF");
365 364 return {}; // does not return
366 365 case ::ot_reference:
367   - return qpdf->getObject(og).getObj();
  366 + return obj->qpdf->getObject(obj->og).getObj();
368 367 }
369 368 return {}; // unreachable
370 369 }
371 370  
372 371 std::string
373   -QPDFObject::unparse()
  372 +BaseHandle::unparse() const
374 373 {
375   - switch (getResolvedTypeCode()) {
  374 + switch (type_code()) {
376 375 case ::ot_uninitialized:
377 376 throw std::logic_error("QPDFObjectHandle: attempting to unparse an uninitialized object");
378 377 return ""; // does not return
... ... @@ -382,18 +381,18 @@ QPDFObject::unparse()
382 381 case ::ot_null:
383 382 return "null";
384 383 case ::ot_boolean:
385   - return std::get<QPDF_Bool>(value).val ? "true" : "false";
  384 + return std::get<QPDF_Bool>(obj->value).val ? "true" : "false";
386 385 case ::ot_integer:
387   - return std::to_string(std::get<QPDF_Integer>(value).val);
  386 + return std::to_string(std::get<QPDF_Integer>(obj->value).val);
388 387 case ::ot_real:
389   - return std::get<QPDF_Real>(value).val;
  388 + return std::get<QPDF_Real>(obj->value).val;
390 389 case ::ot_string:
391   - return std::get<QPDF_String>(value).unparse(false);
  390 + return std::get<QPDF_String>(obj->value).unparse(false);
392 391 case ::ot_name:
393   - return Name::normalize(std::get<QPDF_Name>(value).name);
  392 + return Name::normalize(std::get<QPDF_Name>(obj->value).name);
394 393 case ::ot_array:
395 394 {
396   - auto const& a = std::get<QPDF_Array>(value);
  395 + auto const& a = std::get<QPDF_Array>(obj->value);
397 396 std::string result = "[ ";
398 397 if (a.sp) {
399 398 int next = 0;
... ... @@ -402,9 +401,7 @@ QPDFObject::unparse()
402 401 for (int j = next; j < key; ++j) {
403 402 result += "null ";
404 403 }
405   - auto item_og = item.second.id_gen();
406   - result += item_og.isIndirect() ? item_og.unparse(' ') + " R "
407   - : item.second.getObj()->unparse() + " ";
  404 + result += item.second.unparse() + " ";
408 405 next = ++key;
409 406 }
410 407 for (int j = next; j < a.sp->size; ++j) {
... ... @@ -412,9 +409,7 @@ QPDFObject::unparse()
412 409 }
413 410 } else {
414 411 for (auto const& item: a.elements) {
415   - auto item_og = item.id_gen();
416   - result += item_og.isIndirect() ? item_og.unparse(' ') + " R "
417   - : item.getObj()->unparse() + " ";
  412 + result += item.unparse() + " ";
418 413 }
419 414 }
420 415 result += "]";
... ... @@ -422,7 +417,7 @@ QPDFObject::unparse()
422 417 }
423 418 case ::ot_dictionary:
424 419 {
425   - auto const& items = std::get<QPDF_Dictionary>(value).items;
  420 + auto const& items = std::get<QPDF_Dictionary>(obj->value).items;
426 421 std::string result = "<< ";
427 422 for (auto& iter: items) {
428 423 if (!iter.second.null()) {
... ... @@ -433,11 +428,11 @@ QPDFObject::unparse()
433 428 return result;
434 429 }
435 430 case ::ot_stream:
436   - return og.unparse(' ') + " R";
  431 + return obj->og.unparse(' ') + " R";
437 432 case ::ot_operator:
438   - return std::get<QPDF_Operator>(value).val;
  433 + return std::get<QPDF_Operator>(obj->value).val;
439 434 case ::ot_inlineimage:
440   - return std::get<QPDF_InlineImage>(value).val;
  435 + return std::get<QPDF_InlineImage>(obj->value).val;
441 436 case ::ot_unresolved:
442 437 throw std::logic_error("QPDFObjectHandle: attempting to unparse a unresolved object");
443 438 return ""; // does not return
... ... @@ -445,15 +440,15 @@ QPDFObject::unparse()
445 440 throw std::logic_error("attempted to unparse a QPDFObjectHandle from a destroyed QPDF");
446 441 return ""; // does not return
447 442 case ::ot_reference:
448   - return og.unparse(' ') + " R";
  443 + return obj->og.unparse(' ') + " R";
449 444 }
450 445 return {}; // unreachable
451 446 }
452 447  
453 448 void
454   -QPDFObject::write_json(int json_version, JSON::Writer& p)
  449 +BaseHandle::write_json(int json_version, JSON::Writer& p) const
455 450 {
456   - switch (getResolvedTypeCode()) {
  451 + switch (type_code()) {
457 452 case ::ot_uninitialized:
458 453 throw std::logic_error(
459 454 "QPDFObjectHandle: attempting to get JSON from a uninitialized object");
... ... @@ -464,14 +459,14 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
464 459 p << "null";
465 460 break;
466 461 case ::ot_boolean:
467   - p << std::get<QPDF_Bool>(value).val;
  462 + p << std::get<QPDF_Bool>(obj->value).val;
468 463 break;
469 464 case ::ot_integer:
470   - p << std::to_string(std::get<QPDF_Integer>(value).val);
  465 + p << std::to_string(std::get<QPDF_Integer>(obj->value).val);
471 466 break;
472 467 case ::ot_real:
473 468 {
474   - auto const& val = std::get<QPDF_Real>(value).val;
  469 + auto const& val = std::get<QPDF_Real>(obj->value).val;
475 470 if (val.length() == 0) {
476 471 // Can't really happen...
477 472 p << "0";
... ... @@ -488,11 +483,11 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
488 483 }
489 484 break;
490 485 case ::ot_string:
491   - std::get<QPDF_String>(value).writeJSON(json_version, p);
  486 + std::get<QPDF_String>(obj->value).writeJSON(json_version, p);
492 487 break;
493 488 case ::ot_name:
494 489 {
495   - auto const& n = std::get<QPDF_Name>(value);
  490 + auto const& n = std::get<QPDF_Name>(obj->value);
496 491 // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When
497 492 // updating this method make sure QPDF_Dictionary is also update.
498 493 if (json_version == 1) {
... ... @@ -512,7 +507,7 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
512 507 break;
513 508 case ::ot_array:
514 509 {
515   - auto const& a = std::get<QPDF_Array>(value);
  510 + auto const& a = std::get<QPDF_Array>(obj->value);
516 511 p.writeStart('[');
517 512 if (a.sp) {
518 513 int next = 0;
... ... @@ -526,7 +521,7 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
526 521 if (item_og.isIndirect()) {
527 522 p << "\"" << item_og.unparse(' ') << " R\"";
528 523 } else {
529   - item.second.getObj()->write_json(json_version, p);
  524 + item.second.write_json(json_version, p);
530 525 }
531 526 next = ++key;
532 527 }
... ... @@ -540,7 +535,7 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
540 535 if (item_og.isIndirect()) {
541 536 p << "\"" << item_og.unparse(' ') << " R\"";
542 537 } else {
543   - item.getObj()->write_json(json_version, p);
  538 + item.write_json(json_version, p);
544 539 }
545 540 }
546 541 }
... ... @@ -549,7 +544,7 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
549 544 break;
550 545 case ::ot_dictionary:
551 546 {
552   - auto const& d = std::get<QPDF_Dictionary>(value);
  547 + auto const& d = std::get<QPDF_Dictionary>(obj->value);
553 548 p.writeStart('{');
554 549 for (auto& iter: d.items) {
555 550 if (!iter.second.null()) {
... ... @@ -574,10 +569,10 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
574 569 }
575 570 break;
576 571 case ::ot_stream:
577   - std::get<QPDF_Stream>(value).m->stream_dict.writeJSON(json_version, p);
  572 + std::get<QPDF_Stream>(obj->value).m->stream_dict.writeJSON(json_version, p);
578 573 break;
579 574 case ::ot_reference:
580   - p << "\"" << getObjGen().unparse(' ') << " R\"";
  575 + p << "\"" << obj->og.unparse(' ') << " R\"";
581 576 break;
582 577 default:
583 578 throw std::logic_error("attempted to write an unsuitable object as JSON");
... ... @@ -585,48 +580,49 @@ QPDFObject::write_json(int json_version, JSON::Writer&amp; p)
585 580 }
586 581  
587 582 void
588   -QPDFObject::disconnect()
  583 +BaseHandle::disconnect(bool only_direct)
589 584 {
590   - // Disconnect an object from its owning QPDF. This is called by QPDF's destructor.
  585 + // QPDF::~QPDF() calls disconnect for indirect objects, so we don't do that here.
  586 + if (only_direct && indirect()) {
  587 + return;
  588 + }
591 589  
592   - switch (getTypeCode()) {
  590 + switch (raw_type_code()) {
593 591 case ::ot_array:
594 592 {
595   - auto& a = std::get<QPDF_Array>(value);
  593 + auto& a = std::get<QPDF_Array>(obj->value);
596 594 if (a.sp) {
597 595 for (auto& item: a.sp->elements) {
598   - auto& obj = item.second;
599   - if (!obj.indirect()) {
600   - obj.getObj()->disconnect();
601   - }
  596 + item.second.disconnect();
602 597 }
603 598 } else {
604   - for (auto& obj: a.elements) {
605   - if (!obj.indirect()) {
606   - obj.getObj()->disconnect();
607   - }
  599 + for (auto& oh: a.elements) {
  600 + oh.disconnect();
608 601 }
609 602 }
610 603 }
611 604 break;
612 605 case ::ot_dictionary:
613   - for (auto& iter: std::get<QPDF_Dictionary>(value).items) {
614   - QPDFObjectHandle::DisconnectAccess::disconnect(iter.second);
  606 + for (auto& iter: std::get<QPDF_Dictionary>(obj->value).items) {
  607 + iter.second.disconnect();
615 608 }
616 609 break;
617 610 case ::ot_stream:
618 611 {
619   - auto& s = std::get<QPDF_Stream>(value);
  612 + auto& s = std::get<QPDF_Stream>(obj->value);
620 613 s.m->stream_provider = nullptr;
621   - QPDFObjectHandle::DisconnectAccess::disconnect(s.m->stream_dict);
  614 + s.m->stream_dict.disconnect();
622 615 }
623 616 break;
  617 + case ::ot_uninitialized:
  618 + return;
624 619 default:
625 620 break;
626 621 }
627   - qpdf = nullptr;
628   - og = QPDFObjGen();
  622 + obj->qpdf = nullptr;
  623 + obj->og = QPDFObjGen();
629 624 }
  625 +
630 626 std::string
631 627 QPDFObject::getStringValue() const
632 628 {
... ... @@ -654,16 +650,6 @@ QPDFObjectHandle::isSameObjectAs(QPDFObjectHandle const&amp; rhs) const
654 650 {
655 651 return this->obj == rhs.obj;
656 652 }
657   -void
658   -QPDFObjectHandle::disconnect()
659   -{
660   - // Recursively remove association with any QPDF object. This method may only be called during
661   - // final destruction. QPDF::~QPDF() calls it for indirect objects using the object pointer
662   - // itself, so we don't do that here. Other objects call it through this method.
663   - if (obj && !isIndirect()) {
664   - this->obj->disconnect();
665   - }
666   -}
667 653  
668 654 qpdf_object_type_e
669 655 QPDFObjectHandle::getTypeCode() const
... ... @@ -1439,7 +1425,7 @@ QPDFObjectHandle::unparseResolved() const
1439 1425 if (!obj) {
1440 1426 throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
1441 1427 }
1442   - return obj->unparse();
  1428 + return BaseHandle::unparse();
1443 1429 }
1444 1430  
1445 1431 std::string
... ... @@ -1476,7 +1462,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer&amp; p, bool dereference_
1476 1462 } else if (!obj) {
1477 1463 throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
1478 1464 } else {
1479   - obj->write_json(json_version, p);
  1465 + write_json(json_version, p);
1480 1466 }
1481 1467 }
1482 1468  
... ... @@ -1902,7 +1888,7 @@ QPDFObjectHandle::shallowCopy()
1902 1888 if (!obj) {
1903 1889 throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
1904 1890 }
1905   - return {obj->copy()};
  1891 + return {copy()};
1906 1892 }
1907 1893  
1908 1894 QPDFObjectHandle
... ... @@ -1911,7 +1897,7 @@ QPDFObjectHandle::unsafeShallowCopy()
1911 1897 if (!obj) {
1912 1898 throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle");
1913 1899 }
1914   - return {obj->copy(true)};
  1900 + return {copy(true)};
1915 1901 }
1916 1902  
1917 1903 void
... ... @@ -1926,7 +1912,7 @@ QPDFObjectHandle::makeDirect(QPDFObjGen::set&amp; visited, bool stop_at_streams)
1926 1912 }
1927 1913  
1928 1914 if (isBool() || isInteger() || isName() || isNull() || isReal() || isString()) {
1929   - this->obj = obj->copy(true);
  1915 + this->obj = copy(true);
1930 1916 } else if (auto a = as_array(strict)) {
1931 1917 std::vector<QPDFObjectHandle> items;
1932 1918 for (auto const& item: a) {
... ...
libqpdf/qpdf/QPDFObjectHandle_private.hh
... ... @@ -358,7 +358,7 @@ namespace qpdf
358 358 inline bool
359 359 BaseHandle::null() const
360 360 {
361   - return !obj || obj->getResolvedTypeCode() == ::ot_null;
  361 + return !obj || type_code() == ::ot_null;
362 362 }
363 363  
364 364 inline QPDF*
... ... @@ -383,7 +383,7 @@ namespace qpdf
383 383 return QPDF::Resolver::resolved(obj->qpdf, obj->og)->getTypeCode();
384 384 }
385 385 if (raw_type_code() == ::ot_reference) {
386   - return std::get<QPDF_Reference>(obj->value).obj->getResolvedTypeCode();
  386 + return std::get<QPDF_Reference>(obj->value).obj->getTypeCode();
387 387 }
388 388 return raw_type_code();
389 389 }
... ...
libqpdf/qpdf/QPDFObject_private.hh
... ... @@ -18,6 +18,7 @@
18 18 #include <variant>
19 19 #include <vector>
20 20  
  21 +class Disconnect;
21 22 class QPDFObject;
22 23 class QPDFObjectHandle;
23 24  
... ... @@ -50,7 +51,9 @@ class QPDF_Array final
50 51  
51 52 private:
52 53 friend class QPDFObject;
  54 + friend class qpdf::BaseHandle;
53 55 friend class qpdf::Array;
  56 +
54 57 QPDF_Array(std::vector<QPDFObjectHandle> const& items) :
55 58 elements(items)
56 59 {
... ... @@ -75,6 +78,7 @@ class QPDF_Array final
75 78 class QPDF_Bool final
76 79 {
77 80 friend class QPDFObject;
  81 + friend class qpdf::BaseHandle;
78 82 friend class QPDFObjectHandle;
79 83  
80 84 explicit QPDF_Bool(bool val) :
... ... @@ -92,6 +96,7 @@ class QPDF_Dictionary final
92 96 {
93 97 friend class QPDFObject;
94 98 friend class qpdf::BaseDictionary;
  99 + friend class qpdf::BaseHandle;
95 100  
96 101 QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items) :
97 102 items(items)
... ... @@ -105,6 +110,7 @@ class QPDF_Dictionary final
105 110 class QPDF_InlineImage final
106 111 {
107 112 friend class QPDFObject;
  113 + friend class qpdf::BaseHandle;
108 114  
109 115 explicit QPDF_InlineImage(std::string val) :
110 116 val(std::move(val))
... ... @@ -116,6 +122,7 @@ class QPDF_InlineImage final
116 122 class QPDF_Integer final
117 123 {
118 124 friend class QPDFObject;
  125 + friend class qpdf::BaseHandle;
119 126 friend class QPDFObjectHandle;
120 127  
121 128 QPDF_Integer(long long val) :
... ... @@ -128,6 +135,7 @@ class QPDF_Integer final
128 135 class QPDF_Name final
129 136 {
130 137 friend class QPDFObject;
  138 + friend class qpdf::BaseHandle;
131 139  
132 140 explicit QPDF_Name(std::string name) :
133 141 name(std::move(name))
... ... @@ -139,6 +147,7 @@ class QPDF_Name final
139 147 class QPDF_Null final
140 148 {
141 149 friend class QPDFObject;
  150 + friend class qpdf::BaseHandle;
142 151  
143 152 public:
144 153 static inline std::shared_ptr<QPDFObject> create(
... ... @@ -150,6 +159,7 @@ class QPDF_Null final
150 159 class QPDF_Operator final
151 160 {
152 161 friend class QPDFObject;
  162 + friend class qpdf::BaseHandle;
153 163  
154 164 QPDF_Operator(std::string val) :
155 165 val(std::move(val))
... ... @@ -162,6 +172,7 @@ class QPDF_Operator final
162 172 class QPDF_Real final
163 173 {
164 174 friend class QPDFObject;
  175 + friend class qpdf::BaseHandle;
165 176  
166 177 QPDF_Real(std::string val) :
167 178 val(std::move(val))
... ... @@ -199,6 +210,7 @@ class QPDF_Stream final
199 210 friend class QPDF_Stream;
200 211 friend class QPDFObject;
201 212 friend class qpdf::Stream;
  213 + friend class qpdf::BaseHandle;
202 214  
203 215 public:
204 216 Members(QPDFObjectHandle stream_dict, size_t length) :
... ... @@ -217,6 +229,7 @@ class QPDF_Stream final
217 229 };
218 230  
219 231 friend class QPDFObject;
  232 + friend class qpdf::BaseHandle;
220 233 friend class qpdf::Stream;
221 234  
222 235 QPDF_Stream(QPDFObjectHandle stream_dict, size_t length) :
... ... @@ -235,6 +248,7 @@ class QPDF_Stream final
235 248 class QPDF_String final
236 249 {
237 250 friend class QPDFObject;
  251 + friend class qpdf::BaseHandle;
238 252 friend class QPDFWriter;
239 253  
240 254 public:
... ... @@ -284,10 +298,6 @@ class QPDFObject
284 298 qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
285 299 }
286 300  
287   - std::shared_ptr<QPDFObject> copy(bool shallow = false);
288   - std::string unparse();
289   - void write_json(int json_version, JSON::Writer& p);
290   - void disconnect();
291 301 std::string getStringValue() const;
292 302  
293 303 // Return a unique type code for the resolved object
... ... @@ -298,7 +308,7 @@ class QPDFObject
298 308 return QPDF::Resolver::resolved(qpdf, og)->getTypeCode();
299 309 }
300 310 if (getTypeCode() == ::ot_reference) {
301   - return std::get<QPDF_Reference>(value).obj->getResolvedTypeCode();
  311 + return std::get<QPDF_Reference>(value).obj->getTypeCode();
302 312 }
303 313 return getTypeCode();
304 314 }
... ... @@ -344,23 +354,12 @@ class QPDFObject
344 354 qpdf = a_qpdf;
345 355 og = a_og;
346 356 }
347   - // Mark an object as destroyed. Used by QPDF's destructor for its indirect objects.
348   - void
349   - destroy()
350   - {
351   - value = QPDF_Destroyed();
352   - }
353 357  
354 358 bool
355 359 isUnresolved() const
356 360 {
357 361 return getTypeCode() == ::ot_unresolved;
358 362 }
359   - const QPDFObject*
360   - resolved_object() const
361   - {
362   - return isUnresolved() ? QPDF::Resolver::resolved(qpdf, og).get() : this;
363   - }
364 363  
365 364 struct JSON_Descr
366 365 {
... ... @@ -457,6 +456,7 @@ class QPDFObject
457 456 private:
458 457 friend class QPDF_Stream;
459 458 friend class qpdf::BaseHandle;
  459 + friend class Disconnect;
460 460  
461 461 typedef std::variant<
462 462 std::monostate,
... ...
libtests/sparse_array.cc
... ... @@ -95,12 +95,14 @@ main()
95 95 assert(b.at(3).second.isNull());
96 96 assert(b.at(8).second.isNull());
97 97 assert(b.at(5).second.isIndirect());
98   - assert(obj->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
99   - auto c = obj->copy(true);
100   - auto d = obj->copy(false);
  98 + assert(
  99 + QPDFObjectHandle(obj).unparse() ==
  100 + "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
  101 + auto c = QPDFObjectHandle(obj).unsafeShallowCopy();
  102 + auto d = QPDFObjectHandle(obj).shallowCopy();
101 103 b.at(7).second.setArrayItem(2, "42"_qpdf);
102   - assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]");
103   - assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
  104 + assert(c.unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]");
  105 + assert(d.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
104 106  
105 107 try {
106 108 b.setAt(3, {});
... ...