Commit 884d36becd8403eefa9cbaceb7d85b37ecaa61c5
Committed by
GitHub
Merge pull request #1380 from m-holger/object
Move QPDFObject::copy, disconnect, unparse and write_json to BaseHandle
Showing
7 changed files
with
122 additions
and
124 deletions
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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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& 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, {}); | ... | ... |