Commit 9641626cae44ed17ef4af4e72e89276065dd85ed
1 parent
ce5b864c
Refactor resolving of objects
Showing
9 changed files
with
112 additions
and
119 deletions
include/qpdf/QPDF.hh
| @@ -792,12 +792,13 @@ class QPDF | @@ -792,12 +792,13 @@ class QPDF | ||
| 792 | class Resolver | 792 | class Resolver |
| 793 | { | 793 | { |
| 794 | friend class QPDFObject; | 794 | friend class QPDFObject; |
| 795 | + friend class QPDF_Unresolved; | ||
| 795 | 796 | ||
| 796 | private: | 797 | private: |
| 797 | - static void | ||
| 798 | - resolve(QPDF* qpdf, QPDFObjGen const& og) | 798 | + static QPDFObject* |
| 799 | + resolved(QPDF* qpdf, QPDFObjGen og) | ||
| 799 | { | 800 | { |
| 800 | - qpdf->resolve(og); | 801 | + return qpdf->resolve(og); |
| 801 | } | 802 | } |
| 802 | }; | 803 | }; |
| 803 | 804 | ||
| @@ -1056,7 +1057,7 @@ class QPDF | @@ -1056,7 +1057,7 @@ class QPDF | ||
| 1056 | QPDFObjGen exp_og, | 1057 | QPDFObjGen exp_og, |
| 1057 | QPDFObjGen& og, | 1058 | QPDFObjGen& og, |
| 1058 | bool skip_cache_if_in_xref); | 1059 | bool skip_cache_if_in_xref); |
| 1059 | - void resolve(QPDFObjGen og); | 1060 | + QPDFObject* resolve(QPDFObjGen og); |
| 1060 | void resolveObjectsInStream(int obj_stream_number); | 1061 | void resolveObjectsInStream(int obj_stream_number); |
| 1061 | void stopOnError(std::string const& message); | 1062 | void stopOnError(std::string const& message); |
| 1062 | QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); | 1063 | QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); |
include/qpdf/QPDFObjectHandle.hh
| @@ -1363,24 +1363,23 @@ class QPDFObjectHandle | @@ -1363,24 +1363,23 @@ class QPDFObjectHandle | ||
| 1363 | void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false); | 1363 | void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false); |
| 1364 | 1364 | ||
| 1365 | private: | 1365 | private: |
| 1366 | - QPDF_Array* asArray(); | ||
| 1367 | - QPDF_Bool* asBool(); | ||
| 1368 | - QPDF_Dictionary* asDictionary(); | ||
| 1369 | - QPDF_InlineImage* asInlineImage(); | ||
| 1370 | - QPDF_Integer* asInteger(); | ||
| 1371 | - QPDF_Name* asName(); | ||
| 1372 | - QPDF_Null* asNull(); | ||
| 1373 | - QPDF_Operator* asOperator(); | ||
| 1374 | - QPDF_Real* asReal(); | ||
| 1375 | - QPDF_Reserved* asReserved(); | ||
| 1376 | - QPDF_Stream* asStream(); | 1366 | + QPDF_Array* asArray() const; |
| 1367 | + QPDF_Bool* asBool() const; | ||
| 1368 | + QPDF_Dictionary* asDictionary() const; | ||
| 1369 | + QPDF_InlineImage* asInlineImage() const; | ||
| 1370 | + QPDF_Integer* asInteger() const; | ||
| 1371 | + QPDF_Name* asName() const; | ||
| 1372 | + QPDF_Null* asNull() const; | ||
| 1373 | + QPDF_Operator* asOperator() const; | ||
| 1374 | + QPDF_Real* asReal() const; | ||
| 1375 | + QPDF_Reserved* asReserved() const; | ||
| 1376 | + QPDF_Stream* asStream() const; | ||
| 1377 | QPDF_Stream* asStreamWithAssert(); | 1377 | QPDF_Stream* asStreamWithAssert(); |
| 1378 | - QPDF_String* asString(); | 1378 | + QPDF_String* asString() const; |
| 1379 | 1379 | ||
| 1380 | void typeWarning(char const* expected_type, std::string const& warning); | 1380 | void typeWarning(char const* expected_type, std::string const& warning); |
| 1381 | void objectWarning(std::string const& warning); | 1381 | void objectWarning(std::string const& warning); |
| 1382 | void assertType(char const* type_name, bool istype); | 1382 | void assertType(char const* type_name, bool istype); |
| 1383 | - inline bool dereference(); | ||
| 1384 | void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); | 1383 | void makeDirect(QPDFObjGen::set& visited, bool stop_at_streams); |
| 1385 | void disconnect(); | 1384 | void disconnect(); |
| 1386 | void setParsedOffset(qpdf_offset_t offset); | 1385 | void setParsedOffset(qpdf_offset_t offset); |
libqpdf/QPDF.cc
| @@ -1728,11 +1728,11 @@ QPDF::readObjectAtOffset( | @@ -1728,11 +1728,11 @@ QPDF::readObjectAtOffset( | ||
| 1728 | return oh; | 1728 | return oh; |
| 1729 | } | 1729 | } |
| 1730 | 1730 | ||
| 1731 | -void | 1731 | +QPDFObject* |
| 1732 | QPDF::resolve(QPDFObjGen og) | 1732 | QPDF::resolve(QPDFObjGen og) |
| 1733 | { | 1733 | { |
| 1734 | if (!isUnresolved(og)) { | 1734 | if (!isUnresolved(og)) { |
| 1735 | - return; | 1735 | + return m->obj_cache[og].object.get(); |
| 1736 | } | 1736 | } |
| 1737 | 1737 | ||
| 1738 | if (m->resolving.count(og)) { | 1738 | if (m->resolving.count(og)) { |
| @@ -1741,7 +1741,7 @@ QPDF::resolve(QPDFObjGen og) | @@ -1741,7 +1741,7 @@ QPDF::resolve(QPDFObjGen og) | ||
| 1741 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); | 1741 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); |
| 1742 | warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); | 1742 | warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); |
| 1743 | updateCache(og, QPDF_Null::create(), -1, -1); | 1743 | updateCache(og, QPDF_Null::create(), -1, -1); |
| 1744 | - return; | 1744 | + return m->obj_cache[og].object.get(); |
| 1745 | } | 1745 | } |
| 1746 | ResolveRecorder rr(this, og); | 1746 | ResolveRecorder rr(this, og); |
| 1747 | 1747 | ||
| @@ -1782,6 +1782,7 @@ QPDF::resolve(QPDFObjGen og) | @@ -1782,6 +1782,7 @@ QPDF::resolve(QPDFObjGen og) | ||
| 1782 | 1782 | ||
| 1783 | auto result(m->obj_cache[og].object); | 1783 | auto result(m->obj_cache[og].object); |
| 1784 | result->setDefaultDescription(this, og); | 1784 | result->setDefaultDescription(this, og); |
| 1785 | + return result.get(); | ||
| 1785 | } | 1786 | } |
| 1786 | 1787 | ||
| 1787 | void | 1788 | void |
libqpdf/QPDFObject.cc
| @@ -4,13 +4,6 @@ | @@ -4,13 +4,6 @@ | ||
| 4 | #include <qpdf/QPDF_Destroyed.hh> | 4 | #include <qpdf/QPDF_Destroyed.hh> |
| 5 | 5 | ||
| 6 | void | 6 | void |
| 7 | -QPDFObject::doResolve() | ||
| 8 | -{ | ||
| 9 | - auto og = value->og; | ||
| 10 | - QPDF::Resolver::resolve(value->qpdf, og); | ||
| 11 | -} | ||
| 12 | - | ||
| 13 | -void | ||
| 14 | QPDFObject::destroy() | 7 | QPDFObject::destroy() |
| 15 | { | 8 | { |
| 16 | value = QPDF_Destroyed::getInstance(); | 9 | value = QPDF_Destroyed::getInstance(); |
libqpdf/QPDFObjectHandle.cc
| @@ -240,79 +240,79 @@ QPDFObjectHandle::disconnect() | @@ -240,79 +240,79 @@ QPDFObjectHandle::disconnect() | ||
| 240 | qpdf_object_type_e | 240 | qpdf_object_type_e |
| 241 | QPDFObjectHandle::getTypeCode() | 241 | QPDFObjectHandle::getTypeCode() |
| 242 | { | 242 | { |
| 243 | - return dereference() ? this->obj->getTypeCode() : ::ot_uninitialized; | 243 | + return obj ? obj->getResolvedTypeCode() : ::ot_uninitialized; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | char const* | 246 | char const* |
| 247 | QPDFObjectHandle::getTypeName() | 247 | QPDFObjectHandle::getTypeName() |
| 248 | { | 248 | { |
| 249 | - return dereference() ? this->obj->getTypeName() : "uninitialized"; | 249 | + return obj ? obj->getTypeName() : "uninitialized"; |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | QPDF_Array* | 252 | QPDF_Array* |
| 253 | -QPDFObjectHandle::asArray() | 253 | +QPDFObjectHandle::asArray() const |
| 254 | { | 254 | { |
| 255 | - return dereference() ? obj->as<QPDF_Array>() : nullptr; | 255 | + return obj ? obj->as<QPDF_Array>() : nullptr; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | QPDF_Bool* | 258 | QPDF_Bool* |
| 259 | -QPDFObjectHandle::asBool() | 259 | +QPDFObjectHandle::asBool() const |
| 260 | { | 260 | { |
| 261 | - return dereference() ? obj->as<QPDF_Bool>() : nullptr; | 261 | + return obj ? obj->as<QPDF_Bool>() : nullptr; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | QPDF_Dictionary* | 264 | QPDF_Dictionary* |
| 265 | -QPDFObjectHandle::asDictionary() | 265 | +QPDFObjectHandle::asDictionary() const |
| 266 | { | 266 | { |
| 267 | - return dereference() ? obj->as<QPDF_Dictionary>() : nullptr; | 267 | + return obj ? obj->as<QPDF_Dictionary>() : nullptr; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | QPDF_InlineImage* | 270 | QPDF_InlineImage* |
| 271 | -QPDFObjectHandle::asInlineImage() | 271 | +QPDFObjectHandle::asInlineImage() const |
| 272 | { | 272 | { |
| 273 | - return dereference() ? obj->as<QPDF_InlineImage>() : nullptr; | 273 | + return obj ? obj->as<QPDF_InlineImage>() : nullptr; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | QPDF_Integer* | 276 | QPDF_Integer* |
| 277 | -QPDFObjectHandle::asInteger() | 277 | +QPDFObjectHandle::asInteger() const |
| 278 | { | 278 | { |
| 279 | - return dereference() ? obj->as<QPDF_Integer>() : nullptr; | 279 | + return obj ? obj->as<QPDF_Integer>() : nullptr; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | QPDF_Name* | 282 | QPDF_Name* |
| 283 | -QPDFObjectHandle::asName() | 283 | +QPDFObjectHandle::asName() const |
| 284 | { | 284 | { |
| 285 | - return dereference() ? obj->as<QPDF_Name>() : nullptr; | 285 | + return obj ? obj->as<QPDF_Name>() : nullptr; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | QPDF_Null* | 288 | QPDF_Null* |
| 289 | -QPDFObjectHandle::asNull() | 289 | +QPDFObjectHandle::asNull() const |
| 290 | { | 290 | { |
| 291 | - return dereference() ? obj->as<QPDF_Null>() : nullptr; | 291 | + return obj ? obj->as<QPDF_Null>() : nullptr; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | QPDF_Operator* | 294 | QPDF_Operator* |
| 295 | -QPDFObjectHandle::asOperator() | 295 | +QPDFObjectHandle::asOperator() const |
| 296 | { | 296 | { |
| 297 | - return dereference() ? obj->as<QPDF_Operator>() : nullptr; | 297 | + return obj ? obj->as<QPDF_Operator>() : nullptr; |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | QPDF_Real* | 300 | QPDF_Real* |
| 301 | -QPDFObjectHandle::asReal() | 301 | +QPDFObjectHandle::asReal() const |
| 302 | { | 302 | { |
| 303 | - return dereference() ? obj->as<QPDF_Real>() : nullptr; | 303 | + return obj ? obj->as<QPDF_Real>() : nullptr; |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | QPDF_Reserved* | 306 | QPDF_Reserved* |
| 307 | -QPDFObjectHandle::asReserved() | 307 | +QPDFObjectHandle::asReserved() const |
| 308 | { | 308 | { |
| 309 | - return dereference() ? obj->as<QPDF_Reserved>() : nullptr; | 309 | + return obj ? obj->as<QPDF_Reserved>() : nullptr; |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | QPDF_Stream* | 312 | QPDF_Stream* |
| 313 | -QPDFObjectHandle::asStream() | 313 | +QPDFObjectHandle::asStream() const |
| 314 | { | 314 | { |
| 315 | - return dereference() ? obj->as<QPDF_Stream>() : nullptr; | 315 | + return obj ? obj->as<QPDF_Stream>() : nullptr; |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | QPDF_Stream* | 318 | QPDF_Stream* |
| @@ -324,21 +324,21 @@ QPDFObjectHandle::asStreamWithAssert() | @@ -324,21 +324,21 @@ QPDFObjectHandle::asStreamWithAssert() | ||
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | QPDF_String* | 326 | QPDF_String* |
| 327 | -QPDFObjectHandle::asString() | 327 | +QPDFObjectHandle::asString() const |
| 328 | { | 328 | { |
| 329 | - return dereference() ? obj->as<QPDF_String>() : nullptr; | 329 | + return obj ? obj->as<QPDF_String>() : nullptr; |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | bool | 332 | bool |
| 333 | QPDFObjectHandle::isDestroyed() | 333 | QPDFObjectHandle::isDestroyed() |
| 334 | { | 334 | { |
| 335 | - return dereference() && (obj->getTypeCode() == ::ot_destroyed); | 335 | + return obj && obj->getResolvedTypeCode() == ::ot_destroyed; |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | bool | 338 | bool |
| 339 | QPDFObjectHandle::isBool() | 339 | QPDFObjectHandle::isBool() |
| 340 | { | 340 | { |
| 341 | - return dereference() && (obj->getTypeCode() == ::ot_boolean); | 341 | + return obj && obj->getResolvedTypeCode() == ::ot_boolean; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | bool | 344 | bool |
| @@ -346,25 +346,25 @@ QPDFObjectHandle::isDirectNull() const | @@ -346,25 +346,25 @@ QPDFObjectHandle::isDirectNull() const | ||
| 346 | { | 346 | { |
| 347 | // Don't call dereference() -- this is a const method, and we know | 347 | // Don't call dereference() -- this is a const method, and we know |
| 348 | // objid == 0, so there's nothing to resolve. | 348 | // objid == 0, so there's nothing to resolve. |
| 349 | - return (isInitialized() && (getObjectID() == 0) && (obj->getTypeCode() == ::ot_null)); | 349 | + return (obj && getObjectID() == 0 && obj->getTypeCode() == ::ot_null); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | bool | 352 | bool |
| 353 | QPDFObjectHandle::isNull() | 353 | QPDFObjectHandle::isNull() |
| 354 | { | 354 | { |
| 355 | - return dereference() && (obj->getTypeCode() == ::ot_null); | 355 | + return obj && obj->getResolvedTypeCode() == ::ot_null; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | bool | 358 | bool |
| 359 | QPDFObjectHandle::isInteger() | 359 | QPDFObjectHandle::isInteger() |
| 360 | { | 360 | { |
| 361 | - return dereference() && (obj->getTypeCode() == ::ot_integer); | 361 | + return obj && obj->getResolvedTypeCode() == ::ot_integer; |
| 362 | } | 362 | } |
| 363 | 363 | ||
| 364 | bool | 364 | bool |
| 365 | QPDFObjectHandle::isReal() | 365 | QPDFObjectHandle::isReal() |
| 366 | { | 366 | { |
| 367 | - return dereference() && (obj->getTypeCode() == ::ot_real); | 367 | + return obj && obj->getResolvedTypeCode() == ::ot_real; |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | bool | 370 | bool |
| @@ -401,49 +401,49 @@ QPDFObjectHandle::getValueAsNumber(double& value) | @@ -401,49 +401,49 @@ QPDFObjectHandle::getValueAsNumber(double& value) | ||
| 401 | bool | 401 | bool |
| 402 | QPDFObjectHandle::isName() | 402 | QPDFObjectHandle::isName() |
| 403 | { | 403 | { |
| 404 | - return dereference() && (obj->getTypeCode() == ::ot_name); | 404 | + return obj && obj->getResolvedTypeCode() == ::ot_name; |
| 405 | } | 405 | } |
| 406 | 406 | ||
| 407 | bool | 407 | bool |
| 408 | QPDFObjectHandle::isString() | 408 | QPDFObjectHandle::isString() |
| 409 | { | 409 | { |
| 410 | - return dereference() && (obj->getTypeCode() == ::ot_string); | 410 | + return obj && obj->getResolvedTypeCode() == ::ot_string; |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | bool | 413 | bool |
| 414 | QPDFObjectHandle::isOperator() | 414 | QPDFObjectHandle::isOperator() |
| 415 | { | 415 | { |
| 416 | - return dereference() && (obj->getTypeCode() == ::ot_operator); | 416 | + return obj && obj->getResolvedTypeCode() == ::ot_operator; |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | bool | 419 | bool |
| 420 | QPDFObjectHandle::isInlineImage() | 420 | QPDFObjectHandle::isInlineImage() |
| 421 | { | 421 | { |
| 422 | - return dereference() && (obj->getTypeCode() == ::ot_inlineimage); | 422 | + return obj && obj->getResolvedTypeCode() == ::ot_inlineimage; |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | bool | 425 | bool |
| 426 | QPDFObjectHandle::isArray() | 426 | QPDFObjectHandle::isArray() |
| 427 | { | 427 | { |
| 428 | - return dereference() && (obj->getTypeCode() == ::ot_array); | 428 | + return obj && obj->getResolvedTypeCode() == ::ot_array; |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | bool | 431 | bool |
| 432 | QPDFObjectHandle::isDictionary() | 432 | QPDFObjectHandle::isDictionary() |
| 433 | { | 433 | { |
| 434 | - return dereference() && (obj->getTypeCode() == ::ot_dictionary); | 434 | + return obj && obj->getResolvedTypeCode() == ::ot_dictionary; |
| 435 | } | 435 | } |
| 436 | 436 | ||
| 437 | bool | 437 | bool |
| 438 | QPDFObjectHandle::isStream() | 438 | QPDFObjectHandle::isStream() |
| 439 | { | 439 | { |
| 440 | - return dereference() && (obj->getTypeCode() == ::ot_stream); | 440 | + return obj && obj->getResolvedTypeCode() == ::ot_stream; |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | bool | 443 | bool |
| 444 | QPDFObjectHandle::isReserved() | 444 | QPDFObjectHandle::isReserved() |
| 445 | { | 445 | { |
| 446 | - return dereference() && (obj->getTypeCode() == ::ot_reserved); | 446 | + return obj && obj->getResolvedTypeCode() == ::ot_reserved; |
| 447 | } | 447 | } |
| 448 | 448 | ||
| 449 | bool | 449 | bool |
| @@ -1586,7 +1586,7 @@ QPDFObjectHandle::unparse() | @@ -1586,7 +1586,7 @@ QPDFObjectHandle::unparse() | ||
| 1586 | std::string | 1586 | std::string |
| 1587 | QPDFObjectHandle::unparseResolved() | 1587 | QPDFObjectHandle::unparseResolved() |
| 1588 | { | 1588 | { |
| 1589 | - if (!dereference()) { | 1589 | + if (!obj) { |
| 1590 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); | 1590 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 1591 | } | 1591 | } |
| 1592 | return obj->unparse(); | 1592 | return obj->unparse(); |
| @@ -1615,7 +1615,7 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) | @@ -1615,7 +1615,7 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) | ||
| 1615 | { | 1615 | { |
| 1616 | if ((!dereference_indirect) && isIndirect()) { | 1616 | if ((!dereference_indirect) && isIndirect()) { |
| 1617 | return JSON::makeString(unparse()); | 1617 | return JSON::makeString(unparse()); |
| 1618 | - } else if (!dereference()) { | 1618 | + } else if (!obj) { |
| 1619 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); | 1619 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 1620 | } else { | 1620 | } else { |
| 1621 | Pl_Buffer p{"json"}; | 1621 | Pl_Buffer p{"json"}; |
| @@ -1631,7 +1631,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ | @@ -1631,7 +1631,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_ | ||
| 1631 | { | 1631 | { |
| 1632 | if (!dereference_indirect && isIndirect()) { | 1632 | if (!dereference_indirect && isIndirect()) { |
| 1633 | p << "\"" << getObjGen().unparse(' ') << " R\""; | 1633 | p << "\"" << getObjGen().unparse(' ') << " R\""; |
| 1634 | - } else if (!dereference()) { | 1634 | + } else if (!obj) { |
| 1635 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); | 1635 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 1636 | } else { | 1636 | } else { |
| 1637 | obj->writeJSON(json_version, p); | 1637 | obj->writeJSON(json_version, p); |
| @@ -1874,11 +1874,7 @@ QPDFObjectHandle::parse( | @@ -1874,11 +1874,7 @@ QPDFObjectHandle::parse( | ||
| 1874 | qpdf_offset_t | 1874 | qpdf_offset_t |
| 1875 | QPDFObjectHandle::getParsedOffset() | 1875 | QPDFObjectHandle::getParsedOffset() |
| 1876 | { | 1876 | { |
| 1877 | - if (dereference()) { | ||
| 1878 | - return this->obj->getParsedOffset(); | ||
| 1879 | - } else { | ||
| 1880 | - return -1; | ||
| 1881 | - } | 1877 | + return obj ? obj->getParsedOffset() : -1; |
| 1882 | } | 1878 | } |
| 1883 | 1879 | ||
| 1884 | QPDFObjectHandle | 1880 | QPDFObjectHandle |
| @@ -2055,9 +2051,7 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) | @@ -2055,9 +2051,7 @@ QPDFObjectHandle::newReserved(QPDF* qpdf) | ||
| 2055 | void | 2051 | void |
| 2056 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) | 2052 | QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& object_description) |
| 2057 | { | 2053 | { |
| 2058 | - // This is called during parsing on newly created direct objects, so we can't call dereference() | ||
| 2059 | - // here. | ||
| 2060 | - if (isInitialized() && obj.get()) { | 2054 | + if (obj) { |
| 2061 | auto descr = std::make_shared<QPDFValue::Description>(object_description); | 2055 | auto descr = std::make_shared<QPDFValue::Description>(object_description); |
| 2062 | obj->setDescription(owning_qpdf, descr); | 2056 | obj->setDescription(owning_qpdf, descr); |
| 2063 | } | 2057 | } |
| @@ -2066,13 +2060,13 @@ QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& obj | @@ -2066,13 +2060,13 @@ QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const& obj | ||
| 2066 | bool | 2060 | bool |
| 2067 | QPDFObjectHandle::hasObjectDescription() | 2061 | QPDFObjectHandle::hasObjectDescription() |
| 2068 | { | 2062 | { |
| 2069 | - return dereference() && obj.get() && obj->hasDescription(); | 2063 | + return obj && obj->hasDescription(); |
| 2070 | } | 2064 | } |
| 2071 | 2065 | ||
| 2072 | QPDFObjectHandle | 2066 | QPDFObjectHandle |
| 2073 | QPDFObjectHandle::shallowCopy() | 2067 | QPDFObjectHandle::shallowCopy() |
| 2074 | { | 2068 | { |
| 2075 | - if (!dereference()) { | 2069 | + if (!obj) { |
| 2076 | throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); | 2070 | throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); |
| 2077 | } | 2071 | } |
| 2078 | return {obj->copy()}; | 2072 | return {obj->copy()}; |
| @@ -2081,7 +2075,7 @@ QPDFObjectHandle::shallowCopy() | @@ -2081,7 +2075,7 @@ QPDFObjectHandle::shallowCopy() | ||
| 2081 | QPDFObjectHandle | 2075 | QPDFObjectHandle |
| 2082 | QPDFObjectHandle::unsafeShallowCopy() | 2076 | QPDFObjectHandle::unsafeShallowCopy() |
| 2083 | { | 2077 | { |
| 2084 | - if (!dereference()) { | 2078 | + if (!obj) { |
| 2085 | throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); | 2079 | throw std::logic_error("operation attempted on uninitialized QPDFObjectHandle"); |
| 2086 | } | 2080 | } |
| 2087 | return {obj->copy(true)}; | 2081 | return {obj->copy(true)}; |
| @@ -2172,10 +2166,10 @@ QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& warn | @@ -2172,10 +2166,10 @@ QPDFObjectHandle::typeWarning(char const* expected_type, std::string const& warn | ||
| 2172 | std::string description; | 2166 | std::string description; |
| 2173 | // Type checks above guarantee that the object has been dereferenced. Nevertheless, dereference | 2167 | // Type checks above guarantee that the object has been dereferenced. Nevertheless, dereference |
| 2174 | // throws exceptions in the test suite | 2168 | // throws exceptions in the test suite |
| 2175 | - if (!dereference()) { | 2169 | + if (!obj) { |
| 2176 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); | 2170 | throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle"); |
| 2177 | } | 2171 | } |
| 2178 | - this->obj->getDescription(context, description); | 2172 | + obj->getDescription(context, description); |
| 2179 | // Null context handled by warn | 2173 | // Null context handled by warn |
| 2180 | warn( | 2174 | warn( |
| 2181 | context, | 2175 | context, |
| @@ -2193,7 +2187,7 @@ QPDFObjectHandle::warnIfPossible(std::string const& warning) | @@ -2193,7 +2187,7 @@ QPDFObjectHandle::warnIfPossible(std::string const& warning) | ||
| 2193 | { | 2187 | { |
| 2194 | QPDF* context = nullptr; | 2188 | QPDF* context = nullptr; |
| 2195 | std::string description; | 2189 | std::string description; |
| 2196 | - if (dereference() && obj->getDescription(context, description)) { | 2190 | + if (obj && obj->getDescription(context, description)) { |
| 2197 | warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning)); | 2191 | warn(context, QPDFExc(qpdf_e_damaged_pdf, "", description, 0, warning)); |
| 2198 | } else { | 2192 | } else { |
| 2199 | *QPDFLogger::defaultLogger()->getError() << warning << "\n"; | 2193 | *QPDFLogger::defaultLogger()->getError() << warning << "\n"; |
| @@ -2205,8 +2199,8 @@ QPDFObjectHandle::objectWarning(std::string const& warning) | @@ -2205,8 +2199,8 @@ QPDFObjectHandle::objectWarning(std::string const& warning) | ||
| 2205 | { | 2199 | { |
| 2206 | QPDF* context = nullptr; | 2200 | QPDF* context = nullptr; |
| 2207 | std::string description; | 2201 | std::string description; |
| 2208 | - // Type checks above guarantee that the object has been dereferenced. | ||
| 2209 | - this->obj->getDescription(context, description); | 2202 | + // Type checks above guarantee that the object is initialized. |
| 2203 | + obj->getDescription(context, description); | ||
| 2210 | // Null context handled by warn | 2204 | // Null context handled by warn |
| 2211 | warn(context, QPDFExc(qpdf_e_object, "", description, 0, warning)); | 2205 | warn(context, QPDFExc(qpdf_e_object, "", description, 0, warning)); |
| 2212 | } | 2206 | } |
| @@ -2372,16 +2366,6 @@ QPDFObjectHandle::assertPageObject() | @@ -2372,16 +2366,6 @@ QPDFObjectHandle::assertPageObject() | ||
| 2372 | } | 2366 | } |
| 2373 | } | 2367 | } |
| 2374 | 2368 | ||
| 2375 | -inline bool | ||
| 2376 | -QPDFObjectHandle::dereference() | ||
| 2377 | -{ | ||
| 2378 | - if (!isInitialized()) { | ||
| 2379 | - return false; | ||
| 2380 | - } | ||
| 2381 | - this->obj->resolve(); | ||
| 2382 | - return true; | ||
| 2383 | -} | ||
| 2384 | - | ||
| 2385 | void | 2369 | void |
| 2386 | QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e) | 2370 | QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e) |
| 2387 | { | 2371 | { |
libqpdf/QPDF_Array.cc
| @@ -130,8 +130,7 @@ QPDF_Array::unparse() | @@ -130,8 +130,7 @@ QPDF_Array::unparse() | ||
| 130 | for (int j = next; j < key; ++j) { | 130 | for (int j = next; j < key; ++j) { |
| 131 | result += "null "; | 131 | result += "null "; |
| 132 | } | 132 | } |
| 133 | - item.second->resolve(); | ||
| 134 | - auto og = item.second->getObjGen(); | 133 | + auto og = item.second->resolved_object()->getObjGen(); |
| 135 | result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " "; | 134 | result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " "; |
| 136 | next = ++key; | 135 | next = ++key; |
| 137 | } | 136 | } |
| @@ -140,8 +139,7 @@ QPDF_Array::unparse() | @@ -140,8 +139,7 @@ QPDF_Array::unparse() | ||
| 140 | } | 139 | } |
| 141 | } else { | 140 | } else { |
| 142 | for (auto const& item: elements) { | 141 | for (auto const& item: elements) { |
| 143 | - item->resolve(); | ||
| 144 | - auto og = item->getObjGen(); | 142 | + auto og = item->resolved_object()->getObjGen(); |
| 145 | result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " "; | 143 | result += og.isIndirect() ? og.unparse(' ') + " R " : item->unparse() + " "; |
| 146 | } | 144 | } |
| 147 | } | 145 | } |
libqpdf/QPDF_Unresolved.cc
| 1 | #include <qpdf/QPDF_Unresolved.hh> | 1 | #include <qpdf/QPDF_Unresolved.hh> |
| 2 | 2 | ||
| 3 | -#include <stdexcept> | 3 | +#include <qpdf/QPDF.hh> |
| 4 | +#include <qpdf/QPDFObject_private.hh> | ||
| 4 | 5 | ||
| 5 | QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) : | 6 | QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) : |
| 6 | QPDFValue(::ot_unresolved, "unresolved", qpdf, og) | 7 | QPDFValue(::ot_unresolved, "unresolved", qpdf, og) |
| @@ -16,19 +17,23 @@ QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og) | @@ -16,19 +17,23 @@ QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og) | ||
| 16 | std::shared_ptr<QPDFObject> | 17 | std::shared_ptr<QPDFObject> |
| 17 | QPDF_Unresolved::copy(bool shallow) | 18 | QPDF_Unresolved::copy(bool shallow) |
| 18 | { | 19 | { |
| 19 | - throw std::logic_error("attempted to shallow copy an unresolved QPDFObjectHandle"); | ||
| 20 | - return nullptr; | 20 | + return QPDF::Resolver::resolved(qpdf, og)->copy(shallow); |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | std::string | 23 | std::string |
| 24 | QPDF_Unresolved::unparse() | 24 | QPDF_Unresolved::unparse() |
| 25 | { | 25 | { |
| 26 | - throw std::logic_error("attempted to unparse an unresolved QPDFObjectHandle"); | ||
| 27 | - return ""; | 26 | + return QPDF::Resolver::resolved(qpdf, og)->unparse(); |
| 28 | } | 27 | } |
| 29 | 28 | ||
| 30 | void | 29 | void |
| 31 | QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p) | 30 | QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p) |
| 32 | { | 31 | { |
| 33 | - throw std::logic_error("attempted to get JSON from an unresolved QPDFObjectHandle"); | 32 | + QPDF::Resolver::resolved(qpdf, og)->writeJSON(json_version, p); |
| 33 | +} | ||
| 34 | + | ||
| 35 | +std::string | ||
| 36 | +QPDF_Unresolved::getStringValue() const | ||
| 37 | +{ | ||
| 38 | + return QPDF::Resolver::resolved(qpdf, og)->getStringValue(); | ||
| 34 | } | 39 | } |
libqpdf/qpdf/QPDFObject_private.hh
| @@ -5,8 +5,8 @@ | @@ -5,8 +5,8 @@ | ||
| 5 | // include/qpdf/QPDFObject.hh. See comments there for an explanation. | 5 | // include/qpdf/QPDFObject.hh. See comments there for an explanation. |
| 6 | 6 | ||
| 7 | #include <qpdf/Constants.h> | 7 | #include <qpdf/Constants.h> |
| 8 | -#include <qpdf/DLL.h> | ||
| 9 | #include <qpdf/JSON.hh> | 8 | #include <qpdf/JSON.hh> |
| 9 | +#include <qpdf/QPDF.hh> | ||
| 10 | #include <qpdf/QPDFValue.hh> | 10 | #include <qpdf/QPDFValue.hh> |
| 11 | #include <qpdf/Types.h> | 11 | #include <qpdf/Types.h> |
| 12 | 12 | ||
| @@ -43,18 +43,26 @@ class QPDFObject | @@ -43,18 +43,26 @@ class QPDFObject | ||
| 43 | { | 43 | { |
| 44 | return value->getStringValue(); | 44 | return value->getStringValue(); |
| 45 | } | 45 | } |
| 46 | + // Return a unique type code for the resolved object | ||
| 47 | + qpdf_object_type_e | ||
| 48 | + getResolvedTypeCode() const | ||
| 49 | + { | ||
| 50 | + auto tc = value->type_code; | ||
| 51 | + return tc == ::ot_unresolved | ||
| 52 | + ? QPDF::Resolver::resolved(value->qpdf, value->og)->value->type_code | ||
| 53 | + : tc; | ||
| 54 | + } | ||
| 46 | // Return a unique type code for the object | 55 | // Return a unique type code for the object |
| 47 | qpdf_object_type_e | 56 | qpdf_object_type_e |
| 48 | - getTypeCode() const | 57 | + getTypeCode() const noexcept |
| 49 | { | 58 | { |
| 50 | return value->type_code; | 59 | return value->type_code; |
| 51 | } | 60 | } |
| 52 | - | ||
| 53 | // Return a string literal that describes the type, useful for debugging and testing | 61 | // Return a string literal that describes the type, useful for debugging and testing |
| 54 | char const* | 62 | char const* |
| 55 | getTypeName() const | 63 | getTypeName() const |
| 56 | { | 64 | { |
| 57 | - return value->type_name; | 65 | + return resolved_object()->value->type_name; |
| 58 | } | 66 | } |
| 59 | 67 | ||
| 60 | QPDF* | 68 | QPDF* |
| @@ -157,20 +165,23 @@ class QPDFObject | @@ -157,20 +165,23 @@ class QPDFObject | ||
| 157 | { | 165 | { |
| 158 | return value->type_code == ::ot_unresolved; | 166 | return value->type_code == ::ot_unresolved; |
| 159 | } | 167 | } |
| 160 | - void | ||
| 161 | - resolve() | 168 | + const QPDFObject* |
| 169 | + resolved_object() const | ||
| 162 | { | 170 | { |
| 163 | - if (isUnresolved()) { | ||
| 164 | - doResolve(); | ||
| 165 | - } | 171 | + return isUnresolved() ? QPDF::Resolver::resolved(value->qpdf, value->og) : this; |
| 166 | } | 172 | } |
| 167 | - void doResolve(); | ||
| 168 | 173 | ||
| 169 | template <typename T> | 174 | template <typename T> |
| 170 | T* | 175 | T* |
| 171 | - as() | ||
| 172 | - { | ||
| 173 | - return dynamic_cast<T*>(value.get()); | 176 | + as() const |
| 177 | + { | ||
| 178 | + if (auto result = dynamic_cast<T*>(value.get())) { | ||
| 179 | + return result; | ||
| 180 | + } else { | ||
| 181 | + return isUnresolved() | ||
| 182 | + ? dynamic_cast<T*>(QPDF::Resolver::resolved(value->qpdf, value->og)->value.get()) | ||
| 183 | + : nullptr; | ||
| 184 | + } | ||
| 174 | } | 185 | } |
| 175 | 186 | ||
| 176 | private: | 187 | private: |
libqpdf/qpdf/QPDF_Unresolved.hh
| @@ -11,6 +11,7 @@ class QPDF_Unresolved: public QPDFValue | @@ -11,6 +11,7 @@ class QPDF_Unresolved: public QPDFValue | ||
| 11 | std::shared_ptr<QPDFObject> copy(bool shallow = false) override; | 11 | std::shared_ptr<QPDFObject> copy(bool shallow = false) override; |
| 12 | std::string unparse() override; | 12 | std::string unparse() override; |
| 13 | void writeJSON(int json_version, JSON::Writer& p) override; | 13 | void writeJSON(int json_version, JSON::Writer& p) override; |
| 14 | + std::string getStringValue() const override; | ||
| 14 | 15 | ||
| 15 | private: | 16 | private: |
| 16 | QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og); | 17 | QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og); |