Commit 9641626cae44ed17ef4af4e72e89276065dd85ed

Authored by m-holger
1 parent ce5b864c

Refactor resolving of objects

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&amp; value) @@ -401,49 +401,49 @@ QPDFObjectHandle::getValueAsNumber(double&amp; 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&amp; p, bool dereference_ @@ -1631,7 +1631,7 @@ QPDFObjectHandle::writeJSON(int json_version, JSON::Writer&amp; 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&amp; obj @@ -2066,13 +2060,13 @@ QPDFObjectHandle::setObjectDescription(QPDF* owning_qpdf, std::string const&amp; 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&amp; warn @@ -2172,10 +2166,10 @@ QPDFObjectHandle::typeWarning(char const* expected_type, std::string const&amp; 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&amp; warning) @@ -2193,7 +2187,7 @@ QPDFObjectHandle::warnIfPossible(std::string const&amp; 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&amp; warning) @@ -2205,8 +2199,8 @@ QPDFObjectHandle::objectWarning(std::string const&amp; 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&amp; og) @@ -16,19 +17,23 @@ QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const&amp; 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);