Commit f8fd7d60e301b9b1bf4d705ce747e281c320487e

Authored by Jay Berkenbilt
Committed by GitHub
2 parents a078202c 805c1ad4

Merge pull request #726 from m-holger/tidy3

Split QPDFObject into QPDFObject and QPDFValue
include/qpdf/Constants.h
@@ -82,6 +82,8 @@ enum qpdf_object_type_e { @@ -82,6 +82,8 @@ enum qpdf_object_type_e {
82 /* Additional object types that can occur in content streams */ 82 /* Additional object types that can occur in content streams */
83 ot_operator, 83 ot_operator,
84 ot_inlineimage, 84 ot_inlineimage,
  85 + /* Object types internal to qpdf */
  86 + ot_unresolved,
85 /* NOTE: if adding to this list, update QPDFObject.hh */ 87 /* NOTE: if adding to this list, update QPDFObject.hh */
86 }; 88 };
87 89
include/qpdf/QPDF.hh
@@ -843,19 +843,13 @@ class QPDF @@ -843,19 +843,13 @@ class QPDF
843 // it can resolve indirect references. 843 // it can resolve indirect references.
844 class Resolver 844 class Resolver
845 { 845 {
846 - friend class QPDFObjectHandle; 846 + friend class QPDFObject;
847 847
848 private: 848 private:
849 - static std::shared_ptr<QPDFObject> 849 + static void
850 resolve(QPDF* qpdf, QPDFObjGen const& og) 850 resolve(QPDF* qpdf, QPDFObjGen const& og)
851 { 851 {
852 - return qpdf->resolve(og);  
853 - }  
854 - static bool  
855 - objectChanged(  
856 - QPDF* qpdf, QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph)  
857 - {  
858 - return qpdf->objectChanged(og, oph); 852 + qpdf->resolve(og);
859 } 853 }
860 }; 854 };
861 friend class Resolver; 855 friend class Resolver;
@@ -1174,12 +1168,20 @@ class QPDF @@ -1174,12 +1168,20 @@ class QPDF
1174 std::string const& description, 1168 std::string const& description,
1175 QPDFObjGen const& exp_og, 1169 QPDFObjGen const& exp_og,
1176 QPDFObjGen& og); 1170 QPDFObjGen& og);
1177 - bool objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph);  
1178 - std::shared_ptr<QPDFObject> resolve(QPDFObjGen const& og); 1171 + void resolve(QPDFObjGen const& og);
1179 void resolveObjectsInStream(int obj_stream_number); 1172 void resolveObjectsInStream(int obj_stream_number);
1180 void stopOnError(std::string const& message); 1173 void stopOnError(std::string const& message);
1181 QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); 1174 QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
1182 QPDFObjectHandle reserveStream(QPDFObjGen const& og); 1175 QPDFObjectHandle reserveStream(QPDFObjGen const& og);
  1176 + QPDFObjectHandle
  1177 + newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&);
  1178 + bool isCached(QPDFObjGen const& og);
  1179 + bool isUnresolved(QPDFObjGen const& og);
  1180 + void updateCache(
  1181 + QPDFObjGen const& og,
  1182 + std::shared_ptr<QPDFObject> const& object,
  1183 + qpdf_offset_t end_before_space,
  1184 + qpdf_offset_t end_after_space);
1183 1185
1184 // Calls finish() on the pipeline when done but does not delete it 1186 // Calls finish() on the pipeline when done but does not delete it
1185 bool pipeStreamData( 1187 bool pipeStreamData(
@@ -1727,7 +1729,6 @@ class QPDF @@ -1727,7 +1729,6 @@ class QPDF
1727 bool in_parse; 1729 bool in_parse;
1728 bool parsed; 1730 bool parsed;
1729 std::set<int> resolved_object_streams; 1731 std::set<int> resolved_object_streams;
1730 - bool ever_replaced_objects;  
1731 1732
1732 // Linearization data 1733 // Linearization data
1733 qpdf_offset_t first_xref_item_offset; // actual value from file 1734 qpdf_offset_t first_xref_item_offset; // actual value from file
include/qpdf/QPDFObject.hh
@@ -25,6 +25,7 @@ @@ -25,6 +25,7 @@
25 #include <qpdf/Constants.h> 25 #include <qpdf/Constants.h>
26 #include <qpdf/DLL.h> 26 #include <qpdf/DLL.h>
27 #include <qpdf/JSON.hh> 27 #include <qpdf/JSON.hh>
  28 +#include <qpdf/QPDFValue.hh>
28 #include <qpdf/Types.h> 29 #include <qpdf/Types.h>
29 30
30 #include <string> 31 #include <string>
@@ -34,9 +35,9 @@ class QPDFObjectHandle; @@ -34,9 +35,9 @@ class QPDFObjectHandle;
34 35
35 class QPDFObject 36 class QPDFObject
36 { 37 {
37 - public:  
38 - QPDFObject(); 38 + friend class QPDFValue;
39 39
  40 + public:
40 // Objects derived from QPDFObject are accessible through 41 // Objects derived from QPDFObject are accessible through
41 // QPDFObjectHandle. Each object returns a unique type code that 42 // QPDFObjectHandle. Each object returns a unique type code that
42 // has one of the valid qpdf_object_type_e values. As new object 43 // has one of the valid qpdf_object_type_e values. As new object
@@ -61,18 +62,128 @@ class QPDFObject @@ -61,18 +62,128 @@ class QPDFObject
61 static constexpr object_type_e ot_stream = ::ot_stream; 62 static constexpr object_type_e ot_stream = ::ot_stream;
62 static constexpr object_type_e ot_operator = ::ot_operator; 63 static constexpr object_type_e ot_operator = ::ot_operator;
63 static constexpr object_type_e ot_inlineimage = ::ot_inlineimage; 64 static constexpr object_type_e ot_inlineimage = ::ot_inlineimage;
  65 + static constexpr object_type_e ot_unresolved = ::ot_unresolved;
64 66
  67 + QPDFObject() = default;
65 virtual ~QPDFObject() = default; 68 virtual ~QPDFObject() = default;
66 - virtual std::shared_ptr<QPDFObject> shallowCopy() = 0;  
67 - virtual std::string unparse() = 0;  
68 - virtual JSON getJSON(int json_version) = 0; 69 +
  70 + std::shared_ptr<QPDFObject>
  71 + shallowCopy()
  72 + {
  73 + return value->shallowCopy();
  74 + }
  75 + std::string
  76 + unparse()
  77 + {
  78 + return value->unparse();
  79 + }
  80 + JSON
  81 + getJSON(int json_version)
  82 + {
  83 + return value->getJSON(json_version);
  84 + }
69 85
70 // Return a unique type code for the object 86 // Return a unique type code for the object
71 - virtual object_type_e getTypeCode() const = 0; 87 + object_type_e
  88 + getTypeCode() const
  89 + {
  90 + return value->type_code;
  91 + }
72 92
73 // Return a string literal that describes the type, useful for 93 // Return a string literal that describes the type, useful for
74 // debugging and testing 94 // debugging and testing
75 - virtual char const* getTypeName() const = 0; 95 + char const*
  96 + getTypeName() const
  97 + {
  98 + return value->type_name;
  99 + }
  100 + // Returns nullptr for direct objects
  101 + QPDF*
  102 + getQPDF() const
  103 + {
  104 + return value->qpdf;
  105 + }
  106 + QPDFObjGen
  107 + getObjGen() const
  108 + {
  109 + return value->og;
  110 + }
  111 +
  112 + void
  113 + setDescription(QPDF* qpdf, std::string const& description)
  114 + {
  115 + return value->setDescription(qpdf, description);
  116 + }
  117 + bool
  118 + getDescription(QPDF*& qpdf, std::string& description)
  119 + {
  120 + return value->getDescription(qpdf, description);
  121 + }
  122 + bool
  123 + hasDescription()
  124 + {
  125 + return value->hasDescription();
  126 + }
  127 + void
  128 + setParsedOffset(qpdf_offset_t offset)
  129 + {
  130 + value->setParsedOffset(offset);
  131 + }
  132 + qpdf_offset_t
  133 + getParsedOffset()
  134 + {
  135 + return value->getParsedOffset();
  136 + }
  137 + void
  138 + assign(std::shared_ptr<QPDFObject> o)
  139 + {
  140 + value = o->value;
  141 + }
  142 + void
  143 + swapWith(std::shared_ptr<QPDFObject> o)
  144 + {
  145 + auto v = value;
  146 + value = o->value;
  147 + o->value = v;
  148 + auto og = value->og;
  149 + value->og = o->value->og;
  150 + o->value->og = og;
  151 + }
  152 +
  153 + // The following two methods are for use by class QPDF only
  154 + void
  155 + setObjGen(QPDF* qpdf, QPDFObjGen const& og)
  156 + {
  157 + value->qpdf = qpdf;
  158 + value->og = og;
  159 + }
  160 + void
  161 + resetObjGen()
  162 + {
  163 + value->qpdf = nullptr;
  164 + value->og = QPDFObjGen();
  165 + }
  166 +
  167 + bool
  168 + isUnresolved() const
  169 + {
  170 + return value->type_code == ::ot_unresolved;
  171 + }
  172 + void
  173 + resolve()
  174 + {
  175 + if (isUnresolved()) {
  176 + doResolve();
  177 + }
  178 + }
  179 + void doResolve();
  180 +
  181 + template <typename T>
  182 + T*
  183 + as()
  184 + {
  185 + return dynamic_cast<T*>(value.get());
  186 + }
76 187
77 // Accessor to give specific access to non-public methods 188 // Accessor to give specific access to non-public methods
78 class ObjAccessor 189 class ObjAccessor
@@ -89,29 +200,20 @@ class QPDFObject @@ -89,29 +200,20 @@ class QPDFObject
89 } 200 }
90 } 201 }
91 }; 202 };
92 - friend class ObjAccessor;  
93 203
94 - virtual void setDescription(QPDF*, std::string const&);  
95 - bool getDescription(QPDF*&, std::string&);  
96 - bool hasDescription();  
97 -  
98 - void setParsedOffset(qpdf_offset_t offset);  
99 - qpdf_offset_t getParsedOffset(); 204 + friend class ObjAccessor;
100 205
101 protected: 206 protected:
102 virtual void 207 virtual void
103 releaseResolved() 208 releaseResolved()
104 { 209 {
  210 + value->releaseResolved();
105 } 211 }
106 - static std::shared_ptr<QPDFObject> do_create(QPDFObject*);  
107 212
108 private: 213 private:
109 QPDFObject(QPDFObject const&) = delete; 214 QPDFObject(QPDFObject const&) = delete;
110 QPDFObject& operator=(QPDFObject const&) = delete; 215 QPDFObject& operator=(QPDFObject const&) = delete;
111 -  
112 - QPDF* owning_qpdf;  
113 - std::string object_description;  
114 - qpdf_offset_t parsed_offset; 216 + std::shared_ptr<QPDFValue> value;
115 }; 217 };
116 218
117 #endif // QPDFOBJECT_HH 219 #endif // QPDFOBJECT_HH
include/qpdf/QPDFObjectHandle.hh
@@ -43,8 +43,18 @@ @@ -43,8 +43,18 @@
43 43
44 class Pipeline; 44 class Pipeline;
45 class QPDF; 45 class QPDF;
46 -class QPDF_Dictionary;  
47 class QPDF_Array; 46 class QPDF_Array;
  47 +class QPDF_Bool;
  48 +class QPDF_Dictionary;
  49 +class QPDF_InlineImage;
  50 +class QPDF_Integer;
  51 +class QPDF_Name;
  52 +class QPDF_Null;
  53 +class QPDF_Operator;
  54 +class QPDF_Real;
  55 +class QPDF_Reserved;
  56 +class QPDF_Stream;
  57 +class QPDF_String;
48 class QPDFTokenizer; 58 class QPDFTokenizer;
49 class QPDFExc; 59 class QPDFExc;
50 class Pl_QPDFTokenizer; 60 class Pl_QPDFTokenizer;
@@ -316,7 +326,7 @@ class QPDFObjectHandle @@ -316,7 +326,7 @@ class QPDFObjectHandle
316 }; 326 };
317 327
318 QPDF_DLL 328 QPDF_DLL
319 - QPDFObjectHandle(); 329 + QPDFObjectHandle() = default;
320 QPDF_DLL 330 QPDF_DLL
321 QPDFObjectHandle(QPDFObjectHandle const&) = default; 331 QPDFObjectHandle(QPDFObjectHandle const&) = default;
322 QPDF_DLL 332 QPDF_DLL
@@ -963,8 +973,8 @@ class QPDFObjectHandle @@ -963,8 +973,8 @@ class QPDFObjectHandle
963 // null for a direct object if allow_nullptr is set to true or 973 // null for a direct object if allow_nullptr is set to true or
964 // throws a runtime error otherwise. 974 // throws a runtime error otherwise.
965 QPDF_DLL 975 QPDF_DLL
966 - inline QPDF*  
967 - getOwningQPDF(bool allow_nullptr = true, std::string const& error_msg = ""); 976 + inline QPDF* getOwningQPDF(
  977 + bool allow_nullptr = true, std::string const& error_msg = "") const;
968 978
969 // Create a shallow copy of an object as a direct object, but do not 979 // Create a shallow copy of an object as a direct object, but do not
970 // traverse across indirect object boundaries. That means that, 980 // traverse across indirect object boundaries. That means that,
@@ -1443,9 +1453,9 @@ class QPDFObjectHandle @@ -1443,9 +1453,9 @@ class QPDFObjectHandle
1443 1453
1444 private: 1454 private:
1445 static QPDFObjectHandle 1455 static QPDFObjectHandle
1446 - newIndirect(QPDF* qpdf, QPDFObjGen const& og) 1456 + newIndirect(std::shared_ptr<QPDFObject> const& obj)
1447 { 1457 {
1448 - return QPDFObjectHandle::newIndirect(qpdf, og); 1458 + return QPDFObjectHandle(obj);
1449 } 1459 }
1450 static QPDFObjectHandle 1460 static QPDFObjectHandle
1451 newStream( 1461 newStream(
@@ -1458,12 +1468,6 @@ class QPDFObjectHandle @@ -1458,12 +1468,6 @@ class QPDFObjectHandle
1458 return QPDFObjectHandle::newStream( 1468 return QPDFObjectHandle::newStream(
1459 qpdf, og, stream_dict, offset, length); 1469 qpdf, og, stream_dict, offset, length);
1460 } 1470 }
1461 - // Reserve an object with a specific ID  
1462 - static QPDFObjectHandle  
1463 - makeReserved()  
1464 - {  
1465 - return QPDFObjectHandle::makeReserved();  
1466 - }  
1467 }; 1471 };
1468 friend class Factory; 1472 friend class Factory;
1469 1473
@@ -1483,6 +1487,16 @@ class QPDFObjectHandle @@ -1483,6 +1487,16 @@ class QPDFObjectHandle
1483 }; 1487 };
1484 return o.obj; 1488 return o.obj;
1485 } 1489 }
  1490 + static QPDF_Array*
  1491 + asArray(QPDFObjectHandle& oh)
  1492 + {
  1493 + return oh.asArray();
  1494 + }
  1495 + static QPDF_Stream*
  1496 + asStream(QPDFObjectHandle& oh)
  1497 + {
  1498 + return oh.asStream();
  1499 + }
1486 }; 1500 };
1487 friend class ObjAccessor; 1501 friend class ObjAccessor;
1488 1502
@@ -1563,18 +1577,32 @@ class QPDFObjectHandle @@ -1563,18 +1577,32 @@ class QPDFObjectHandle
1563 bool isImage(bool exclude_imagemask = true); 1577 bool isImage(bool exclude_imagemask = true);
1564 1578
1565 private: 1579 private:
1566 - QPDFObjectHandle(QPDF*, QPDFObjGen const& og);  
1567 - QPDFObjectHandle(std::shared_ptr<QPDFObject> const&); 1580 + QPDFObjectHandle(std::shared_ptr<QPDFObject> const& obj) :
  1581 + obj(obj)
  1582 + {
  1583 + }
1568 1584
1569 // Private object factory methods 1585 // Private object factory methods
1570 - static QPDFObjectHandle newIndirect(QPDF*, QPDFObjGen const& og);  
1571 static QPDFObjectHandle newStream( 1586 static QPDFObjectHandle newStream(
1572 QPDF* qpdf, 1587 QPDF* qpdf,
1573 QPDFObjGen const& og, 1588 QPDFObjGen const& og,
1574 QPDFObjectHandle stream_dict, 1589 QPDFObjectHandle stream_dict,
1575 qpdf_offset_t offset, 1590 qpdf_offset_t offset,
1576 size_t length); 1591 size_t length);
1577 - static QPDFObjectHandle makeReserved(); 1592 +
  1593 + QPDF_Array* asArray();
  1594 + QPDF_Bool* asBool();
  1595 + QPDF_Dictionary* asDictionary();
  1596 + QPDF_InlineImage* asInlineImage();
  1597 + QPDF_Integer* asInteger();
  1598 + QPDF_Name* asName();
  1599 + QPDF_Null* asNull();
  1600 + QPDF_Operator* asOperator();
  1601 + QPDF_Real* asReal();
  1602 + QPDF_Reserved* asReserved();
  1603 + QPDF_Stream* asStream();
  1604 + QPDF_Stream* asStreamWithAssert();
  1605 + QPDF_String* asString();
1578 1606
1579 void typeWarning(char const* expected_type, std::string const& warning); 1607 void typeWarning(char const* expected_type, std::string const& warning);
1580 void objectWarning(std::string const& warning); 1608 void objectWarning(std::string const& warning);
@@ -1601,15 +1629,10 @@ class QPDFObjectHandle @@ -1601,15 +1629,10 @@ class QPDFObjectHandle
1601 static void warn(QPDF*, QPDFExc const&); 1629 static void warn(QPDF*, QPDFExc const&);
1602 void checkOwnership(QPDFObjectHandle const&) const; 1630 void checkOwnership(QPDFObjectHandle const&) const;
1603 1631
1604 - bool initialized;  
1605 -  
1606 // Moving members of QPDFObjectHandle into a smart pointer incurs 1632 // Moving members of QPDFObjectHandle into a smart pointer incurs
1607 // a substantial performance penalty since QPDFObjectHandle 1633 // a substantial performance penalty since QPDFObjectHandle
1608 // objects are copied around so frequently. 1634 // objects are copied around so frequently.
1609 - QPDF* qpdf;  
1610 - QPDFObjGen og;  
1611 std::shared_ptr<QPDFObject> obj; 1635 std::shared_ptr<QPDFObject> obj;
1612 - bool reserved;  
1613 }; 1636 };
1614 1637
1615 #ifndef QPDF_NO_QPDF_STRING 1638 #ifndef QPDF_NO_QPDF_STRING
@@ -1832,44 +1855,45 @@ class QPDFObjectHandle::QPDFArrayItems @@ -1832,44 +1855,45 @@ class QPDFObjectHandle::QPDFArrayItems
1832 inline QPDFObjGen 1855 inline QPDFObjGen
1833 QPDFObjectHandle::getObjGen() const 1856 QPDFObjectHandle::getObjGen() const
1834 { 1857 {
1835 - return og; 1858 + return isInitialized() ? obj->getObjGen() : QPDFObjGen();
1836 } 1859 }
1837 1860
1838 inline int 1861 inline int
1839 QPDFObjectHandle::getObjectID() const 1862 QPDFObjectHandle::getObjectID() const
1840 { 1863 {
1841 - return og.getObj(); 1864 + return getObjGen().getObj();
1842 } 1865 }
1843 1866
1844 inline int 1867 inline int
1845 QPDFObjectHandle::getGeneration() const 1868 QPDFObjectHandle::getGeneration() const
1846 { 1869 {
1847 - return og.getGen(); 1870 + return getObjGen().getGen();
1848 } 1871 }
1849 1872
1850 inline bool 1873 inline bool
1851 QPDFObjectHandle::isIndirect() const 1874 QPDFObjectHandle::isIndirect() const
1852 { 1875 {
1853 - return initialized && (getObjectID() != 0); 1876 + return (obj != nullptr) && (getObjectID() != 0);
1854 } 1877 }
1855 1878
1856 inline bool 1879 inline bool
1857 QPDFObjectHandle::isInitialized() const 1880 QPDFObjectHandle::isInitialized() const
1858 { 1881 {
1859 - return initialized; 1882 + return obj != nullptr;
1860 } 1883 }
1861 1884
1862 // Indirect object accessors 1885 // Indirect object accessors
1863 inline QPDF* 1886 inline QPDF*
1864 QPDFObjectHandle::getOwningQPDF( 1887 QPDFObjectHandle::getOwningQPDF(
1865 - bool allow_nullptr, std::string const& error_msg) 1888 + bool allow_nullptr, std::string const& error_msg) const
1866 { 1889 {
1867 // Will be null for direct objects 1890 // Will be null for direct objects
1868 - if (!allow_nullptr && (this->qpdf == nullptr)) { 1891 + auto result = isInitialized() ? this->obj->getQPDF() : nullptr;
  1892 + if (!allow_nullptr && (result == nullptr)) {
1869 throw std::runtime_error( 1893 throw std::runtime_error(
1870 error_msg == "" ? "attempt to use a null qpdf object" : error_msg); 1894 error_msg == "" ? "attempt to use a null qpdf object" : error_msg);
1871 } 1895 }
1872 - return this->qpdf; 1896 + return result;
1873 } 1897 }
1874 1898
1875 inline void 1899 inline void
@@ -1877,7 +1901,7 @@ QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset) @@ -1877,7 +1901,7 @@ QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset)
1877 { 1901 {
1878 // This is called during parsing on newly created direct objects, 1902 // This is called during parsing on newly created direct objects,
1879 // so we can't call dereference() here. 1903 // so we can't call dereference() here.
1880 - if (this->obj.get()) { 1904 + if (isInitialized()) {
1881 this->obj->setParsedOffset(offset); 1905 this->obj->setParsedOffset(offset);
1882 } 1906 }
1883 } 1907 }
include/qpdf/QPDFValue.hh 0 โ†’ 100644
  1 +// Copyright (c) 2005-2022 Jay Berkenbilt
  2 +//
  3 +// This file is part of qpdf.
  4 +//
  5 +// Licensed under the Apache License, Version 2.0 (the "License");
  6 +// you may not use this file except in compliance with the License.
  7 +// You may obtain a copy of the License at
  8 +//
  9 +// http://www.apache.org/licenses/LICENSE-2.0
  10 +//
  11 +// Unless required by applicable law or agreed to in writing, software
  12 +// distributed under the License is distributed on an "AS IS" BASIS,
  13 +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 +// See the License for the specific language governing permissions and
  15 +// limitations under the License.
  16 +//
  17 +// Versions of qpdf prior to version 7 were released under the terms
  18 +// of version 2.0 of the Artistic License. At your option, you may
  19 +// continue to consider qpdf to be licensed under those terms. Please
  20 +// see the manual for additional information.
  21 +
  22 +#ifndef QPDFVALUE_HH
  23 +#define QPDFVALUE_HH
  24 +
  25 +#include <qpdf/Constants.h>
  26 +#include <qpdf/DLL.h>
  27 +#include <qpdf/JSON.hh>
  28 +#include <qpdf/QPDFObjGen.hh>
  29 +#include <qpdf/Types.h>
  30 +
  31 +#include <string>
  32 +
  33 +class QPDF;
  34 +class QPDFObjectHandle;
  35 +class QPDFObject;
  36 +
  37 +class QPDFValue
  38 +{
  39 + friend class QPDFObject;
  40 +
  41 + public:
  42 + virtual ~QPDFValue() = default;
  43 +
  44 + virtual std::shared_ptr<QPDFObject> shallowCopy() = 0;
  45 + virtual std::string unparse() = 0;
  46 + virtual JSON getJSON(int json_version) = 0;
  47 + virtual void
  48 + setDescription(QPDF* qpdf, std::string const& description)
  49 + {
  50 + owning_qpdf = qpdf;
  51 + object_description = description;
  52 + }
  53 + bool
  54 + getDescription(QPDF*& qpdf, std::string& description)
  55 + {
  56 + qpdf = owning_qpdf;
  57 + description = object_description;
  58 + return owning_qpdf != nullptr;
  59 + }
  60 + bool
  61 + hasDescription()
  62 + {
  63 + return owning_qpdf != nullptr;
  64 + }
  65 + void
  66 + setParsedOffset(qpdf_offset_t offset)
  67 + {
  68 + if (parsed_offset < 0) {
  69 + parsed_offset = offset;
  70 + }
  71 + }
  72 + qpdf_offset_t
  73 + getParsedOffset()
  74 + {
  75 + return parsed_offset;
  76 + }
  77 + QPDF*
  78 + getQPDF()
  79 + {
  80 + return qpdf;
  81 + }
  82 + QPDFObjGen
  83 + getObjGen()
  84 + {
  85 + return og;
  86 + }
  87 +
  88 + protected:
  89 + QPDFValue() :
  90 + type_code(::ot_uninitialized),
  91 + type_name("uninitialized")
  92 + {
  93 + }
  94 + QPDFValue(qpdf_object_type_e type_code, char const* type_name) :
  95 + type_code(type_code),
  96 + type_name(type_name)
  97 + {
  98 + }
  99 + QPDFValue(
  100 + qpdf_object_type_e type_code,
  101 + char const* type_name,
  102 + QPDF* qpdf,
  103 + QPDFObjGen const& og) :
  104 + type_code(type_code),
  105 + type_name(type_name),
  106 + qpdf(qpdf),
  107 + og(og)
  108 + {
  109 + }
  110 + virtual void
  111 + releaseResolved()
  112 + {
  113 + }
  114 + static std::shared_ptr<QPDFObject> do_create(QPDFValue*);
  115 +
  116 + private:
  117 + QPDFValue(QPDFValue const&) = delete;
  118 + QPDFValue& operator=(QPDFValue const&) = delete;
  119 + QPDF* owning_qpdf{nullptr};
  120 + std::string object_description;
  121 + qpdf_offset_t parsed_offset{-1};
  122 + const qpdf_object_type_e type_code;
  123 + char const* type_name;
  124 +
  125 + protected:
  126 + QPDF* qpdf{nullptr};
  127 + QPDFObjGen og;
  128 +};
  129 +
  130 +#endif // QPDFVALUE_HH
libqpdf/CMakeLists.txt
@@ -85,6 +85,7 @@ set(libqpdf_SOURCES @@ -85,6 +85,7 @@ set(libqpdf_SOURCES
85 QPDFSystemError.cc 85 QPDFSystemError.cc
86 QPDFTokenizer.cc 86 QPDFTokenizer.cc
87 QPDFUsage.cc 87 QPDFUsage.cc
  88 + QPDFValue.cc
88 QPDFWriter.cc 89 QPDFWriter.cc
89 QPDFXRefEntry.cc 90 QPDFXRefEntry.cc
90 QPDF_Array.cc 91 QPDF_Array.cc
@@ -99,6 +100,7 @@ set(libqpdf_SOURCES @@ -99,6 +100,7 @@ set(libqpdf_SOURCES
99 QPDF_Reserved.cc 100 QPDF_Reserved.cc
100 QPDF_Stream.cc 101 QPDF_Stream.cc
101 QPDF_String.cc 102 QPDF_String.cc
  103 + QPDF_Unresolved.cc
102 QPDF_encryption.cc 104 QPDF_encryption.cc
103 QPDF_json.cc 105 QPDF_json.cc
104 QPDF_linearization.cc 106 QPDF_linearization.cc
libqpdf/QPDF.cc
@@ -24,7 +24,9 @@ @@ -24,7 +24,9 @@
24 #include <qpdf/QPDF_Array.hh> 24 #include <qpdf/QPDF_Array.hh>
25 #include <qpdf/QPDF_Dictionary.hh> 25 #include <qpdf/QPDF_Dictionary.hh>
26 #include <qpdf/QPDF_Null.hh> 26 #include <qpdf/QPDF_Null.hh>
  27 +#include <qpdf/QPDF_Reserved.hh>
27 #include <qpdf/QPDF_Stream.hh> 28 #include <qpdf/QPDF_Stream.hh>
  29 +#include <qpdf/QPDF_Unresolved.hh>
28 #include <qpdf/QTC.hh> 30 #include <qpdf/QTC.hh>
29 #include <qpdf/QUtil.hh> 31 #include <qpdf/QUtil.hh>
30 32
@@ -222,7 +224,6 @@ QPDF::Members::Members() : @@ -222,7 +224,6 @@ QPDF::Members::Members() :
222 immediate_copy_from(false), 224 immediate_copy_from(false),
223 in_parse(false), 225 in_parse(false),
224 parsed(false), 226 parsed(false),
225 - ever_replaced_objects(false),  
226 first_xref_item_offset(0), 227 first_xref_item_offset(0),
227 uncompressed_after_compressed(false) 228 uncompressed_after_compressed(false)
228 { 229 {
@@ -258,6 +259,7 @@ QPDF::~QPDF() @@ -258,6 +259,7 @@ QPDF::~QPDF()
258 this->m->xref_table.clear(); 259 this->m->xref_table.clear();
259 for (auto const& iter: this->m->obj_cache) { 260 for (auto const& iter: this->m->obj_cache) {
260 QPDFObject::ObjAccessor::releaseResolved(iter.second.object.get()); 261 QPDFObject::ObjAccessor::releaseResolved(iter.second.object.get());
  262 + iter.second.object->resetObjGen();
261 } 263 }
262 } 264 }
263 265
@@ -1397,7 +1399,7 @@ QPDF::fixDanglingReferences(bool force) @@ -1397,7 +1399,7 @@ QPDF::fixDanglingReferences(bool force)
1397 std::list<QPDFObjectHandle> queue; 1399 std::list<QPDFObjectHandle> queue;
1398 queue.push_back(this->m->trailer); 1400 queue.push_back(this->m->trailer);
1399 for (auto const& og: to_process) { 1401 for (auto const& og: to_process) {
1400 - QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect(this, og); 1402 + auto obj = getObject(og);
1401 if (obj.isDictionary() || obj.isArray()) { 1403 if (obj.isDictionary() || obj.isArray()) {
1402 queue.push_back(obj); 1404 queue.push_back(obj);
1403 } else if (obj.isStream()) { 1405 } else if (obj.isStream()) {
@@ -1419,18 +1421,15 @@ QPDF::fixDanglingReferences(bool force) @@ -1419,18 +1421,15 @@ QPDF::fixDanglingReferences(bool force)
1419 to_check.push_back(iter.second); 1421 to_check.push_back(iter.second);
1420 } 1422 }
1421 } else if (obj.isArray()) { 1423 } else if (obj.isArray()) {
1422 - QPDF_Array* arr = dynamic_cast<QPDF_Array*>(  
1423 - QPDFObjectHandle::ObjAccessor::getObject(obj).get()); 1424 + auto arr = QPDFObjectHandle::ObjAccessor::asArray(obj);
1424 arr->addExplicitElementsToList(to_check); 1425 arr->addExplicitElementsToList(to_check);
1425 } 1426 }
1426 for (auto sub: to_check) { 1427 for (auto sub: to_check) {
1427 if (sub.isIndirect()) { 1428 if (sub.isIndirect()) {
1428 - if (sub.getOwningQPDF() == this) {  
1429 - QPDFObjGen og(sub.getObjGen());  
1430 - if (this->m->obj_cache.count(og) == 0) {  
1431 - QTC::TC("qpdf", "QPDF detected dangling ref");  
1432 - queue.push_back(sub);  
1433 - } 1429 + if ((sub.getOwningQPDF() == this) &&
  1430 + isUnresolved(sub.getObjGen())) {
  1431 + QTC::TC("qpdf", "QPDF detected dangling ref");
  1432 + queue.push_back(sub);
1434 } 1433 }
1435 } else { 1434 } else {
1436 queue.push_back(sub); 1435 queue.push_back(sub);
@@ -1462,8 +1461,7 @@ QPDF::getAllObjects() @@ -1462,8 +1461,7 @@ QPDF::getAllObjects()
1462 fixDanglingReferences(true); 1461 fixDanglingReferences(true);
1463 std::vector<QPDFObjectHandle> result; 1462 std::vector<QPDFObjectHandle> result;
1464 for (auto const& iter: this->m->obj_cache) { 1463 for (auto const& iter: this->m->obj_cache) {
1465 - QPDFObjGen const& og = iter.first;  
1466 - result.push_back(QPDFObjectHandle::Factory::newIndirect(this, og)); 1464 + result.push_back(newIndirect(iter.first, iter.second.object));
1467 } 1465 }
1468 return result; 1466 return result;
1469 } 1467 }
@@ -1888,7 +1886,7 @@ QPDF::readObjectAtOffset( @@ -1888,7 +1886,7 @@ QPDF::readObjectAtOffset(
1888 "expected endobj"); 1886 "expected endobj");
1889 } 1887 }
1890 1888
1891 - if (!this->m->obj_cache.count(og)) { 1889 + if (isUnresolved(og)) {
1892 // Store the object in the cache here so it gets cached 1890 // Store the object in the cache here so it gets cached
1893 // whether we first know the offset or whether we first know 1891 // whether we first know the offset or whether we first know
1894 // the object ID and generation (in which we case we would get 1892 // the object ID and generation (in which we case we would get
@@ -1919,8 +1917,8 @@ QPDF::readObjectAtOffset( @@ -1919,8 +1917,8 @@ QPDF::readObjectAtOffset(
1919 } 1917 }
1920 } 1918 }
1921 qpdf_offset_t end_after_space = this->m->file->tell(); 1919 qpdf_offset_t end_after_space = this->m->file->tell();
1922 -  
1923 - this->m->obj_cache[og] = ObjCache( 1920 + updateCache(
  1921 + og,
1924 QPDFObjectHandle::ObjAccessor::getObject(oh), 1922 QPDFObjectHandle::ObjAccessor::getObject(oh),
1925 end_before_space, 1923 end_before_space,
1926 end_after_space); 1924 end_after_space);
@@ -1929,31 +1927,14 @@ QPDF::readObjectAtOffset( @@ -1929,31 +1927,14 @@ QPDF::readObjectAtOffset(
1929 return oh; 1927 return oh;
1930 } 1928 }
1931 1929
1932 -bool  
1933 -QPDF::objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph)  
1934 -{  
1935 - // See if the object cached at og, if any, is the one passed in.  
1936 - // QPDFObjectHandle uses this to detect outdated handles to  
1937 - // replaced or swapped objects. This is a somewhat expensive check  
1938 - // because it happens with every dereference of a  
1939 - // QPDFObjectHandle. To reduce the hit somewhat, short-circuit the  
1940 - // check if we never called a function that replaces an object  
1941 - // already in cache. It is important for functions that do this to  
1942 - // set ever_replaced_objects = true.  
1943 -  
1944 - if (!this->m->ever_replaced_objects) {  
1945 - return false;  
1946 - }  
1947 - auto c = this->m->obj_cache.find(og);  
1948 - if (c == this->m->obj_cache.end()) {  
1949 - return true;  
1950 - }  
1951 - return (c->second.object.get() != oph.get());  
1952 -}  
1953 -  
1954 -std::shared_ptr<QPDFObject> 1930 +void
1955 QPDF::resolve(QPDFObjGen const& og) 1931 QPDF::resolve(QPDFObjGen const& og)
1956 { 1932 {
  1933 + if (isCached(og) && !isUnresolved(og)) {
  1934 + // We only need to resolve unresolved objects
  1935 + return;
  1936 + }
  1937 +
1957 // Check object cache before checking xref table. This allows us 1938 // Check object cache before checking xref table. This allows us
1958 // to insert things into the object cache that don't actually 1939 // to insert things into the object cache that don't actually
1959 // exist in the file. 1940 // exist in the file.
@@ -1967,11 +1948,12 @@ QPDF::resolve(QPDFObjGen const&amp; og) @@ -1967,11 +1948,12 @@ QPDF::resolve(QPDFObjGen const&amp; og)
1967 "", 1948 "",
1968 this->m->file->getLastOffset(), 1949 this->m->file->getLastOffset(),
1969 ("loop detected resolving object " + og.unparse(' '))); 1950 ("loop detected resolving object " + og.unparse(' ')));
1970 - return QPDF_Null::create(); 1951 + updateCache(og, QPDF_Null::create(), -1, -1);
  1952 + return;
1971 } 1953 }
1972 ResolveRecorder rr(this, og); 1954 ResolveRecorder rr(this, og);
1973 1955
1974 - if ((!this->m->obj_cache.count(og)) && this->m->xref_table.count(og)) { 1956 + if (m->xref_table.count(og) != 0) {
1975 QPDFXRefEntry const& entry = this->m->xref_table[og]; 1957 QPDFXRefEntry const& entry = this->m->xref_table[og];
1976 try { 1958 try {
1977 switch (entry.getType()) { 1959 switch (entry.getType()) {
@@ -2009,19 +1991,17 @@ QPDF::resolve(QPDFObjGen const&amp; og) @@ -2009,19 +1991,17 @@ QPDF::resolve(QPDFObjGen const&amp; og)
2009 ": error reading object: " + e.what())); 1991 ": error reading object: " + e.what()));
2010 } 1992 }
2011 } 1993 }
2012 - if (this->m->obj_cache.count(og) == 0) { 1994 +
  1995 + if (isUnresolved(og)) {
2013 // PDF spec says unknown objects resolve to the null object. 1996 // PDF spec says unknown objects resolve to the null object.
2014 QTC::TC("qpdf", "QPDF resolve failure to null"); 1997 QTC::TC("qpdf", "QPDF resolve failure to null");
2015 - QPDFObjectHandle oh = QPDFObjectHandle::newNull();  
2016 - this->m->obj_cache[og] =  
2017 - ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); 1998 + updateCache(og, QPDF_Null::create(), -1, -1);
2018 } 1999 }
2019 2000
2020 - std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object); 2001 + auto result(this->m->obj_cache[og].object);
2021 if (!result->hasDescription()) { 2002 if (!result->hasDescription()) {
2022 result->setDescription(this, ("object " + og.unparse(' '))); 2003 result->setDescription(this, ("object " + og.unparse(' ')));
2023 } 2004 }
2024 - return result;  
2025 } 2005 }
2026 2006
2027 void 2007 void
@@ -2109,15 +2089,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number) @@ -2109,15 +2089,15 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
2109 // objects appended to the file, so it is necessary to recheck the 2089 // objects appended to the file, so it is necessary to recheck the
2110 // xref table and only cache what would actually be resolved here. 2090 // xref table and only cache what would actually be resolved here.
2111 for (auto const& iter: offsets) { 2091 for (auto const& iter: offsets) {
2112 - int obj = iter.first;  
2113 - QPDFObjGen og(obj, 0); 2092 + QPDFObjGen og(iter.first, 0);
2114 QPDFXRefEntry const& entry = this->m->xref_table[og]; 2093 QPDFXRefEntry const& entry = this->m->xref_table[og];
2115 if ((entry.getType() == 2) && 2094 if ((entry.getType() == 2) &&
2116 (entry.getObjStreamNumber() == obj_stream_number)) { 2095 (entry.getObjStreamNumber() == obj_stream_number)) {
2117 int offset = iter.second; 2096 int offset = iter.second;
2118 input->seek(offset, SEEK_SET); 2097 input->seek(offset, SEEK_SET);
2119 QPDFObjectHandle oh = readObject(input, "", og, true); 2098 QPDFObjectHandle oh = readObject(input, "", og, true);
2120 - this->m->obj_cache[og] = ObjCache( 2099 + updateCache(
  2100 + og,
2121 QPDFObjectHandle::ObjAccessor::getObject(oh), 2101 QPDFObjectHandle::ObjAccessor::getObject(oh),
2122 end_before_space, 2102 end_before_space,
2123 end_after_space); 2103 end_after_space);
@@ -2128,6 +2108,47 @@ QPDF::resolveObjectsInStream(int obj_stream_number) @@ -2128,6 +2108,47 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
2128 } 2108 }
2129 2109
2130 QPDFObjectHandle 2110 QPDFObjectHandle
  2111 +QPDF::newIndirect(QPDFObjGen const& og, std::shared_ptr<QPDFObject> const& obj)
  2112 +{
  2113 + obj->setObjGen(this, og);
  2114 + if (!obj->hasDescription()) {
  2115 + obj->setDescription(this, "object " + og.unparse(' '));
  2116 + }
  2117 + return QPDFObjectHandle::Factory::newIndirect(obj);
  2118 +}
  2119 +
  2120 +void
  2121 +QPDF::updateCache(
  2122 + QPDFObjGen const& og,
  2123 + std::shared_ptr<QPDFObject> const& object,
  2124 + qpdf_offset_t end_before_space,
  2125 + qpdf_offset_t end_after_space)
  2126 +{
  2127 + object->setObjGen(this, og);
  2128 + if (isCached(og)) {
  2129 + auto& cache = m->obj_cache[og];
  2130 + cache.object->resetObjGen();
  2131 + cache.object->assign(object);
  2132 + cache.end_before_space = end_before_space;
  2133 + cache.end_after_space = end_after_space;
  2134 + } else {
  2135 + m->obj_cache[og] = ObjCache(object, end_before_space, end_after_space);
  2136 + }
  2137 +}
  2138 +
  2139 +bool
  2140 +QPDF::isCached(QPDFObjGen const& og)
  2141 +{
  2142 + return m->obj_cache.count(og) != 0;
  2143 +}
  2144 +
  2145 +bool
  2146 +QPDF::isUnresolved(QPDFObjGen const& og)
  2147 +{
  2148 + return !isCached(og) || m->obj_cache[og].object->isUnresolved();
  2149 +}
  2150 +
  2151 +QPDFObjectHandle
2131 QPDF::makeIndirectObject(QPDFObjectHandle oh) 2152 QPDF::makeIndirectObject(QPDFObjectHandle oh)
2132 { 2153 {
2133 int max_objid = toI(getObjectCount()); 2154 int max_objid = toI(getObjectCount());
@@ -2136,19 +2157,21 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh) @@ -2136,19 +2157,21 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh)
2136 "max object id is too high to create new objects"); 2157 "max object id is too high to create new objects");
2137 } 2158 }
2138 QPDFObjGen next(max_objid + 1, 0); 2159 QPDFObjGen next(max_objid + 1, 0);
2139 - this->m->obj_cache[next] = 2160 + m->obj_cache[next] =
2140 ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); 2161 ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
2141 - return QPDFObjectHandle::Factory::newIndirect(this, next); 2162 + return newIndirect(next, m->obj_cache[next].object);
2142 } 2163 }
2143 2164
2144 QPDFObjectHandle 2165 QPDFObjectHandle
2145 QPDF::reserveObjectIfNotExists(QPDFObjGen const& og) 2166 QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
2146 { 2167 {
2147 - if ((!this->m->obj_cache.count(og)) && (!this->m->xref_table.count(og))) { 2168 + if (!isCached(og) && !m->xref_table.count(og)) {
2148 resolve(og); 2169 resolve(og);
2149 - replaceObject(og, QPDFObjectHandle::Factory::makeReserved()); 2170 + m->obj_cache[og].object = QPDF_Reserved::create();
  2171 + return newIndirect(og, m->obj_cache[og].object);
  2172 + } else {
  2173 + return getObject(og);
2150 } 2174 }
2151 - return getObject(og);  
2152 } 2175 }
2153 2176
2154 QPDFObjectHandle 2177 QPDFObjectHandle
@@ -2161,7 +2184,13 @@ QPDF::reserveStream(QPDFObjGen const&amp; og) @@ -2161,7 +2184,13 @@ QPDF::reserveStream(QPDFObjGen const&amp; og)
2161 QPDFObjectHandle 2184 QPDFObjectHandle
2162 QPDF::getObject(QPDFObjGen const& og) 2185 QPDF::getObject(QPDFObjGen const& og)
2163 { 2186 {
2164 - return QPDFObjectHandle::Factory::newIndirect(this, og); 2187 + if (!og.isIndirect()) {
  2188 + return QPDFObjectHandle::newNull();
  2189 + }
  2190 + if (!isCached(og)) {
  2191 + m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
  2192 + }
  2193 + return newIndirect(og, m->obj_cache[og].object);
2165 } 2194 }
2166 2195
2167 QPDFObjectHandle 2196 QPDFObjectHandle
@@ -2196,14 +2225,11 @@ QPDF::replaceObject(QPDFObjGen const&amp; og, QPDFObjectHandle oh) @@ -2196,14 +2225,11 @@ QPDF::replaceObject(QPDFObjGen const&amp; og, QPDFObjectHandle oh)
2196 throw std::logic_error( 2225 throw std::logic_error(
2197 "QPDF::replaceObject called with indirect object handle"); 2226 "QPDF::replaceObject called with indirect object handle");
2198 } 2227 }
2199 -  
2200 // Force new object to appear in the cache 2228 // Force new object to appear in the cache
2201 resolve(og); 2229 resolve(og);
2202 2230
2203 // Replace the object in the object cache 2231 // Replace the object in the object cache
2204 - this->m->ever_replaced_objects = true;  
2205 - this->m->obj_cache[og] =  
2206 - ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1); 2232 + updateCache(og, QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
2207 } 2233 }
2208 2234
2209 void 2235 void
@@ -2456,12 +2482,12 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) @@ -2456,12 +2482,12 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
2456 QPDFObjGen local_og(result.getObjGen()); 2482 QPDFObjGen local_og(result.getObjGen());
2457 // Copy information from the foreign stream so we can pipe its 2483 // Copy information from the foreign stream so we can pipe its
2458 // data later without keeping the original QPDF object around. 2484 // data later without keeping the original QPDF object around.
  2485 +
2459 QPDF* foreign_stream_qpdf = foreign.getOwningQPDF( 2486 QPDF* foreign_stream_qpdf = foreign.getOwningQPDF(
2460 false, "unable to retrieve owning qpdf from foreign stream"); 2487 false, "unable to retrieve owning qpdf from foreign stream");
2461 2488
2462 - QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(  
2463 - QPDFObjectHandle::ObjAccessor::getObject(foreign).get());  
2464 - if (!stream) { 2489 + auto stream = QPDFObjectHandle::ObjAccessor::asStream(foreign);
  2490 + if (stream == nullptr) {
2465 throw std::logic_error("unable to retrieve underlying" 2491 throw std::logic_error("unable to retrieve underlying"
2466 " stream object from foreign stream"); 2492 " stream object from foreign stream");
2467 } 2493 }
@@ -2525,10 +2551,7 @@ QPDF::swapObjects(QPDFObjGen const&amp; og1, QPDFObjGen const&amp; og2) @@ -2525,10 +2551,7 @@ QPDF::swapObjects(QPDFObjGen const&amp; og1, QPDFObjGen const&amp; og2)
2525 // cache. 2551 // cache.
2526 resolve(og1); 2552 resolve(og1);
2527 resolve(og2); 2553 resolve(og2);
2528 - ObjCache t = this->m->obj_cache[og1];  
2529 - this->m->ever_replaced_objects = true;  
2530 - this->m->obj_cache[og1] = this->m->obj_cache[og2];  
2531 - this->m->obj_cache[og2] = t; 2554 + m->obj_cache[og1].object->swapWith(m->obj_cache[og2].object);
2532 } 2555 }
2533 2556
2534 unsigned long long 2557 unsigned long long
libqpdf/QPDFObject.cc
1 #include <qpdf/QPDFObject.hh> 1 #include <qpdf/QPDFObject.hh>
2 2
3 -QPDFObject::QPDFObject() :  
4 - owning_qpdf(nullptr),  
5 - parsed_offset(-1)  
6 -{  
7 -}  
8 -  
9 -std::shared_ptr<QPDFObject>  
10 -QPDFObject::do_create(QPDFObject* object)  
11 -{  
12 - std::shared_ptr<QPDFObject> obj(object);  
13 - return obj;  
14 -}  
15 -  
16 -void  
17 -QPDFObject::setDescription(QPDF* qpdf, std::string const& description)  
18 -{  
19 - this->owning_qpdf = qpdf;  
20 - this->object_description = description;  
21 -}  
22 -  
23 -bool  
24 -QPDFObject::getDescription(QPDF*& qpdf, std::string& description)  
25 -{  
26 - qpdf = this->owning_qpdf;  
27 - description = this->object_description;  
28 - return this->owning_qpdf != nullptr;  
29 -}  
30 -  
31 -bool  
32 -QPDFObject::hasDescription()  
33 -{  
34 - return this->owning_qpdf != nullptr;  
35 -} 3 +#include <qpdf/QPDF.hh>
36 4
37 void 5 void
38 -QPDFObject::setParsedOffset(qpdf_offset_t offset)  
39 -{  
40 - this->parsed_offset = offset;  
41 -}  
42 -  
43 -qpdf_offset_t  
44 -QPDFObject::getParsedOffset() 6 +QPDFObject::doResolve()
45 { 7 {
46 - return this->parsed_offset; 8 + auto og = value->og;
  9 + QPDF::Resolver::resolve(value->qpdf, og);
47 } 10 }
libqpdf/QPDFObjectHandle.cc
@@ -21,6 +21,7 @@ @@ -21,6 +21,7 @@
21 #include <qpdf/QPDF_Reserved.hh> 21 #include <qpdf/QPDF_Reserved.hh>
22 #include <qpdf/QPDF_Stream.hh> 22 #include <qpdf/QPDF_Stream.hh>
23 #include <qpdf/QPDF_String.hh> 23 #include <qpdf/QPDF_String.hh>
  24 +#include <qpdf/QPDF_Unresolved.hh>
24 #include <qpdf/SparseOHArray.hh> 25 #include <qpdf/SparseOHArray.hh>
25 26
26 #include <qpdf/QIntC.hh> 27 #include <qpdf/QIntC.hh>
@@ -234,29 +235,6 @@ LastChar::getLastChar() @@ -234,29 +235,6 @@ LastChar::getLastChar()
234 return this->last_char; 235 return this->last_char;
235 } 236 }
236 237
237 -QPDFObjectHandle::QPDFObjectHandle() :  
238 - initialized(false),  
239 - qpdf(nullptr),  
240 - reserved(false)  
241 -{  
242 -}  
243 -  
244 -QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, QPDFObjGen const& og) :  
245 - initialized(true),  
246 - qpdf(qpdf),  
247 - og(og),  
248 - reserved(false)  
249 -{  
250 -}  
251 -  
252 -QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr<QPDFObject> const& data) :  
253 - initialized(true),  
254 - qpdf(nullptr),  
255 - obj(data),  
256 - reserved(false)  
257 -{  
258 -}  
259 -  
260 void 238 void
261 QPDFObjectHandle::releaseResolved() 239 QPDFObjectHandle::releaseResolved()
262 { 240 {
@@ -286,24 +264,90 @@ QPDFObjectHandle::getTypeName() @@ -286,24 +264,90 @@ QPDFObjectHandle::getTypeName()
286 return dereference() ? this->obj->getTypeName() : "uninitialized"; 264 return dereference() ? this->obj->getTypeName() : "uninitialized";
287 } 265 }
288 266
289 -namespace 267 +QPDF_Array*
  268 +QPDFObjectHandle::asArray()
290 { 269 {
291 - template <class T>  
292 - class QPDFObjectTypeAccessor  
293 - {  
294 - public:  
295 - static bool  
296 - check(std::shared_ptr<QPDFObject> const& o)  
297 - {  
298 - return (o && dynamic_cast<T const*>(o.get()));  
299 - }  
300 - };  
301 -} // namespace 270 + return dereference() ? obj->as<QPDF_Array>() : nullptr;
  271 +}
  272 +
  273 +QPDF_Bool*
  274 +QPDFObjectHandle::asBool()
  275 +{
  276 + return dereference() ? obj->as<QPDF_Bool>() : nullptr;
  277 +}
  278 +
  279 +QPDF_Dictionary*
  280 +QPDFObjectHandle::asDictionary()
  281 +{
  282 + return dereference() ? obj->as<QPDF_Dictionary>() : nullptr;
  283 +}
  284 +
  285 +QPDF_InlineImage*
  286 +QPDFObjectHandle::asInlineImage()
  287 +{
  288 + return dereference() ? obj->as<QPDF_InlineImage>() : nullptr;
  289 +}
  290 +
  291 +QPDF_Integer*
  292 +QPDFObjectHandle::asInteger()
  293 +{
  294 + return dereference() ? obj->as<QPDF_Integer>() : nullptr;
  295 +}
  296 +
  297 +QPDF_Name*
  298 +QPDFObjectHandle::asName()
  299 +{
  300 + return dereference() ? obj->as<QPDF_Name>() : nullptr;
  301 +}
  302 +
  303 +QPDF_Null*
  304 +QPDFObjectHandle::asNull()
  305 +{
  306 + return dereference() ? obj->as<QPDF_Null>() : nullptr;
  307 +}
  308 +
  309 +QPDF_Operator*
  310 +QPDFObjectHandle::asOperator()
  311 +{
  312 + return dereference() ? obj->as<QPDF_Operator>() : nullptr;
  313 +}
  314 +
  315 +QPDF_Real*
  316 +QPDFObjectHandle::asReal()
  317 +{
  318 + return dereference() ? obj->as<QPDF_Real>() : nullptr;
  319 +}
  320 +
  321 +QPDF_Reserved*
  322 +QPDFObjectHandle::asReserved()
  323 +{
  324 + return dereference() ? obj->as<QPDF_Reserved>() : nullptr;
  325 +}
  326 +
  327 +QPDF_Stream*
  328 +QPDFObjectHandle::asStream()
  329 +{
  330 + return dereference() ? obj->as<QPDF_Stream>() : nullptr;
  331 +}
  332 +
  333 +QPDF_Stream*
  334 +QPDFObjectHandle::asStreamWithAssert()
  335 +{
  336 + auto stream = asStream();
  337 + assertType("stream", stream);
  338 + return stream;
  339 +}
  340 +
  341 +QPDF_String*
  342 +QPDFObjectHandle::asString()
  343 +{
  344 + return dereference() ? obj->as<QPDF_String>() : nullptr;
  345 +}
302 346
303 bool 347 bool
304 QPDFObjectHandle::isBool() 348 QPDFObjectHandle::isBool()
305 { 349 {
306 - return dereference() && QPDFObjectTypeAccessor<QPDF_Bool>::check(obj); 350 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_boolean);
307 } 351 }
308 352
309 bool 353 bool
@@ -312,26 +356,26 @@ QPDFObjectHandle::isDirectNull() const @@ -312,26 +356,26 @@ QPDFObjectHandle::isDirectNull() const
312 // Don't call dereference() -- this is a const method, and we know 356 // Don't call dereference() -- this is a const method, and we know
313 // objid == 0, so there's nothing to resolve. 357 // objid == 0, so there's nothing to resolve.
314 return ( 358 return (
315 - this->initialized && (getObjectID() == 0) &&  
316 - QPDFObjectTypeAccessor<QPDF_Null>::check(obj)); 359 + isInitialized() && (getObjectID() == 0) &&
  360 + (obj->getTypeCode() == QPDFObject::ot_null));
317 } 361 }
318 362
319 bool 363 bool
320 QPDFObjectHandle::isNull() 364 QPDFObjectHandle::isNull()
321 { 365 {
322 - return dereference() && QPDFObjectTypeAccessor<QPDF_Null>::check(obj); 366 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_null);
323 } 367 }
324 368
325 bool 369 bool
326 QPDFObjectHandle::isInteger() 370 QPDFObjectHandle::isInteger()
327 { 371 {
328 - return dereference() && QPDFObjectTypeAccessor<QPDF_Integer>::check(obj); 372 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_integer);
329 } 373 }
330 374
331 bool 375 bool
332 QPDFObjectHandle::isReal() 376 QPDFObjectHandle::isReal()
333 { 377 {
334 - return dereference() && QPDFObjectTypeAccessor<QPDF_Real>::check(obj); 378 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_real);
335 } 379 }
336 380
337 bool 381 bool
@@ -368,51 +412,49 @@ QPDFObjectHandle::getValueAsNumber(double&amp; value) @@ -368,51 +412,49 @@ QPDFObjectHandle::getValueAsNumber(double&amp; value)
368 bool 412 bool
369 QPDFObjectHandle::isName() 413 QPDFObjectHandle::isName()
370 { 414 {
371 - return dereference() && QPDFObjectTypeAccessor<QPDF_Name>::check(obj); 415 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_name);
372 } 416 }
373 417
374 bool 418 bool
375 QPDFObjectHandle::isString() 419 QPDFObjectHandle::isString()
376 { 420 {
377 - return dereference() && QPDFObjectTypeAccessor<QPDF_String>::check(obj); 421 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_string);
378 } 422 }
379 423
380 bool 424 bool
381 QPDFObjectHandle::isOperator() 425 QPDFObjectHandle::isOperator()
382 { 426 {
383 - return dereference() && QPDFObjectTypeAccessor<QPDF_Operator>::check(obj); 427 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_operator);
384 } 428 }
385 429
386 bool 430 bool
387 QPDFObjectHandle::isInlineImage() 431 QPDFObjectHandle::isInlineImage()
388 { 432 {
389 - return dereference() &&  
390 - QPDFObjectTypeAccessor<QPDF_InlineImage>::check(obj); 433 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_inlineimage);
391 } 434 }
392 435
393 bool 436 bool
394 QPDFObjectHandle::isArray() 437 QPDFObjectHandle::isArray()
395 { 438 {
396 - return dereference() && QPDFObjectTypeAccessor<QPDF_Array>::check(obj); 439 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_array);
397 } 440 }
398 441
399 bool 442 bool
400 QPDFObjectHandle::isDictionary() 443 QPDFObjectHandle::isDictionary()
401 { 444 {
402 - return dereference() && QPDFObjectTypeAccessor<QPDF_Dictionary>::check(obj); 445 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_dictionary);
403 } 446 }
404 447
405 bool 448 bool
406 QPDFObjectHandle::isStream() 449 QPDFObjectHandle::isStream()
407 { 450 {
408 - return dereference() && QPDFObjectTypeAccessor<QPDF_Stream>::check(obj); 451 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_stream);
409 } 452 }
410 453
411 bool 454 bool
412 QPDFObjectHandle::isReserved() 455 QPDFObjectHandle::isReserved()
413 { 456 {
414 - // dereference will clear reserved if this has been replaced  
415 - return dereference() && this->reserved; 457 + return dereference() && (obj->getTypeCode() == QPDFObject::ot_reserved);
416 } 458 }
417 459
418 bool 460 bool
@@ -450,8 +492,9 @@ QPDFObjectHandle::isStreamOfType( @@ -450,8 +492,9 @@ QPDFObjectHandle::isStreamOfType(
450 bool 492 bool
451 QPDFObjectHandle::getBoolValue() 493 QPDFObjectHandle::getBoolValue()
452 { 494 {
453 - if (isBool()) {  
454 - return dynamic_cast<QPDF_Bool*>(obj.get())->getVal(); 495 + auto boolean = asBool();
  496 + if (boolean) {
  497 + return boolean->getVal();
455 } else { 498 } else {
456 typeWarning("boolean", "returning false"); 499 typeWarning("boolean", "returning false");
457 QTC::TC("qpdf", "QPDFObjectHandle boolean returning false"); 500 QTC::TC("qpdf", "QPDFObjectHandle boolean returning false");
@@ -462,10 +505,11 @@ QPDFObjectHandle::getBoolValue() @@ -462,10 +505,11 @@ QPDFObjectHandle::getBoolValue()
462 bool 505 bool
463 QPDFObjectHandle::getValueAsBool(bool& value) 506 QPDFObjectHandle::getValueAsBool(bool& value)
464 { 507 {
465 - if (!isBool()) { 508 + auto boolean = asBool();
  509 + if (boolean == nullptr) {
466 return false; 510 return false;
467 } 511 }
468 - value = dynamic_cast<QPDF_Bool*>(obj.get())->getVal(); 512 + value = boolean->getVal();
469 return true; 513 return true;
470 } 514 }
471 515
@@ -474,8 +518,9 @@ QPDFObjectHandle::getValueAsBool(bool&amp; value) @@ -474,8 +518,9 @@ QPDFObjectHandle::getValueAsBool(bool&amp; value)
474 long long 518 long long
475 QPDFObjectHandle::getIntValue() 519 QPDFObjectHandle::getIntValue()
476 { 520 {
477 - if (isInteger()) {  
478 - return dynamic_cast<QPDF_Integer*>(obj.get())->getVal(); 521 + auto integer = asInteger();
  522 + if (integer) {
  523 + return integer->getVal();
479 } else { 524 } else {
480 typeWarning("integer", "returning 0"); 525 typeWarning("integer", "returning 0");
481 QTC::TC("qpdf", "QPDFObjectHandle integer returning 0"); 526 QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
@@ -486,10 +531,11 @@ QPDFObjectHandle::getIntValue() @@ -486,10 +531,11 @@ QPDFObjectHandle::getIntValue()
486 bool 531 bool
487 QPDFObjectHandle::getValueAsInt(long long& value) 532 QPDFObjectHandle::getValueAsInt(long long& value)
488 { 533 {
489 - if (!isInteger()) { 534 + auto integer = asInteger();
  535 + if (integer == nullptr) {
490 return false; 536 return false;
491 } 537 }
492 - value = dynamic_cast<QPDF_Integer*>(obj.get())->getVal(); 538 + value = integer->getVal();
493 return true; 539 return true;
494 } 540 }
495 541
@@ -585,8 +631,9 @@ QPDFObjectHandle::getValueAsUInt(unsigned int&amp; value) @@ -585,8 +631,9 @@ QPDFObjectHandle::getValueAsUInt(unsigned int&amp; value)
585 std::string 631 std::string
586 QPDFObjectHandle::getRealValue() 632 QPDFObjectHandle::getRealValue()
587 { 633 {
588 - if (isReal()) {  
589 - return dynamic_cast<QPDF_Real*>(obj.get())->getVal(); 634 + auto real = asReal();
  635 + if (real) {
  636 + return real->getVal();
590 } else { 637 } else {
591 typeWarning("real", "returning 0.0"); 638 typeWarning("real", "returning 0.0");
592 QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0"); 639 QTC::TC("qpdf", "QPDFObjectHandle real returning 0.0");
@@ -597,10 +644,11 @@ QPDFObjectHandle::getRealValue() @@ -597,10 +644,11 @@ QPDFObjectHandle::getRealValue()
597 bool 644 bool
598 QPDFObjectHandle::getValueAsReal(std::string& value) 645 QPDFObjectHandle::getValueAsReal(std::string& value)
599 { 646 {
600 - if (!isReal()) { 647 + auto real = asReal();
  648 + if (real == nullptr) {
601 return false; 649 return false;
602 } 650 }
603 - value = dynamic_cast<QPDF_Real*>(obj.get())->getVal(); 651 + value = real->getVal();
604 return true; 652 return true;
605 } 653 }
606 654
@@ -609,8 +657,9 @@ QPDFObjectHandle::getValueAsReal(std::string&amp; value) @@ -609,8 +657,9 @@ QPDFObjectHandle::getValueAsReal(std::string&amp; value)
609 std::string 657 std::string
610 QPDFObjectHandle::getName() 658 QPDFObjectHandle::getName()
611 { 659 {
612 - if (isName()) {  
613 - return dynamic_cast<QPDF_Name*>(obj.get())->getName(); 660 + auto name = asName();
  661 + if (name) {
  662 + return name->getName();
614 } else { 663 } else {
615 typeWarning("name", "returning dummy name"); 664 typeWarning("name", "returning dummy name");
616 QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name"); 665 QTC::TC("qpdf", "QPDFObjectHandle name returning dummy name");
@@ -621,10 +670,11 @@ QPDFObjectHandle::getName() @@ -621,10 +670,11 @@ QPDFObjectHandle::getName()
621 bool 670 bool
622 QPDFObjectHandle::getValueAsName(std::string& value) 671 QPDFObjectHandle::getValueAsName(std::string& value)
623 { 672 {
624 - if (!isName()) { 673 + auto name = asName();
  674 + if (name == nullptr) {
625 return false; 675 return false;
626 } 676 }
627 - value = dynamic_cast<QPDF_Name*>(obj.get())->getName(); 677 + value = name->getName();
628 return true; 678 return true;
629 } 679 }
630 680
@@ -633,8 +683,9 @@ QPDFObjectHandle::getValueAsName(std::string&amp; value) @@ -633,8 +683,9 @@ QPDFObjectHandle::getValueAsName(std::string&amp; value)
633 std::string 683 std::string
634 QPDFObjectHandle::getStringValue() 684 QPDFObjectHandle::getStringValue()
635 { 685 {
636 - if (isString()) {  
637 - return dynamic_cast<QPDF_String*>(obj.get())->getVal(); 686 + auto str = asString();
  687 + if (str) {
  688 + return str->getVal();
638 } else { 689 } else {
639 typeWarning("string", "returning empty string"); 690 typeWarning("string", "returning empty string");
640 QTC::TC("qpdf", "QPDFObjectHandle string returning empty string"); 691 QTC::TC("qpdf", "QPDFObjectHandle string returning empty string");
@@ -645,18 +696,20 @@ QPDFObjectHandle::getStringValue() @@ -645,18 +696,20 @@ QPDFObjectHandle::getStringValue()
645 bool 696 bool
646 QPDFObjectHandle::getValueAsString(std::string& value) 697 QPDFObjectHandle::getValueAsString(std::string& value)
647 { 698 {
648 - if (!isString()) { 699 + auto str = asString();
  700 + if (str == nullptr) {
649 return false; 701 return false;
650 } 702 }
651 - value = dynamic_cast<QPDF_String*>(obj.get())->getVal(); 703 + value = str->getVal();
652 return true; 704 return true;
653 } 705 }
654 706
655 std::string 707 std::string
656 QPDFObjectHandle::getUTF8Value() 708 QPDFObjectHandle::getUTF8Value()
657 { 709 {
658 - if (isString()) {  
659 - return dynamic_cast<QPDF_String*>(obj.get())->getUTF8Val(); 710 + auto str = asString();
  711 + if (str) {
  712 + return str->getUTF8Val();
660 } else { 713 } else {
661 typeWarning("string", "returning empty string"); 714 typeWarning("string", "returning empty string");
662 QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8"); 715 QTC::TC("qpdf", "QPDFObjectHandle string returning empty utf8");
@@ -667,10 +720,11 @@ QPDFObjectHandle::getUTF8Value() @@ -667,10 +720,11 @@ QPDFObjectHandle::getUTF8Value()
667 bool 720 bool
668 QPDFObjectHandle::getValueAsUTF8(std::string& value) 721 QPDFObjectHandle::getValueAsUTF8(std::string& value)
669 { 722 {
670 - if (!isString()) { 723 + auto str = asString();
  724 + if (str == nullptr) {
671 return false; 725 return false;
672 } 726 }
673 - value = dynamic_cast<QPDF_String*>(obj.get())->getUTF8Val(); 727 + value = str->getUTF8Val();
674 return true; 728 return true;
675 } 729 }
676 730
@@ -679,8 +733,9 @@ QPDFObjectHandle::getValueAsUTF8(std::string&amp; value) @@ -679,8 +733,9 @@ QPDFObjectHandle::getValueAsUTF8(std::string&amp; value)
679 std::string 733 std::string
680 QPDFObjectHandle::getOperatorValue() 734 QPDFObjectHandle::getOperatorValue()
681 { 735 {
682 - if (isOperator()) {  
683 - return dynamic_cast<QPDF_Operator*>(obj.get())->getVal(); 736 + auto op = asOperator();
  737 + if (op) {
  738 + return op->getVal();
684 } else { 739 } else {
685 typeWarning("operator", "returning fake value"); 740 typeWarning("operator", "returning fake value");
686 QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value"); 741 QTC::TC("qpdf", "QPDFObjectHandle operator returning fake value");
@@ -691,18 +746,20 @@ QPDFObjectHandle::getOperatorValue() @@ -691,18 +746,20 @@ QPDFObjectHandle::getOperatorValue()
691 bool 746 bool
692 QPDFObjectHandle::getValueAsOperator(std::string& value) 747 QPDFObjectHandle::getValueAsOperator(std::string& value)
693 { 748 {
694 - if (!isOperator()) { 749 + auto op = asOperator();
  750 + if (op == nullptr) {
695 return false; 751 return false;
696 } 752 }
697 - value = dynamic_cast<QPDF_Operator*>(obj.get())->getVal(); 753 + value = op->getVal();
698 return true; 754 return true;
699 } 755 }
700 756
701 std::string 757 std::string
702 QPDFObjectHandle::getInlineImageValue() 758 QPDFObjectHandle::getInlineImageValue()
703 { 759 {
704 - if (isInlineImage()) {  
705 - return dynamic_cast<QPDF_InlineImage*>(obj.get())->getVal(); 760 + auto image = asInlineImage();
  761 + if (image) {
  762 + return image->getVal();
706 } else { 763 } else {
707 typeWarning("inlineimage", "returning empty data"); 764 typeWarning("inlineimage", "returning empty data");
708 QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data"); 765 QTC::TC("qpdf", "QPDFObjectHandle inlineimage returning empty data");
@@ -713,10 +770,11 @@ QPDFObjectHandle::getInlineImageValue() @@ -713,10 +770,11 @@ QPDFObjectHandle::getInlineImageValue()
713 bool 770 bool
714 QPDFObjectHandle::getValueAsInlineImage(std::string& value) 771 QPDFObjectHandle::getValueAsInlineImage(std::string& value)
715 { 772 {
716 - if (!isInlineImage()) { 773 + auto image = asInlineImage();
  774 + if (image == nullptr) {
717 return false; 775 return false;
718 } 776 }
719 - value = dynamic_cast<QPDF_InlineImage*>(obj.get())->getVal(); 777 + value = image->getVal();
720 return true; 778 return true;
721 } 779 }
722 780
@@ -731,8 +789,9 @@ QPDFObjectHandle::aitems() @@ -731,8 +789,9 @@ QPDFObjectHandle::aitems()
731 int 789 int
732 QPDFObjectHandle::getArrayNItems() 790 QPDFObjectHandle::getArrayNItems()
733 { 791 {
734 - if (isArray()) {  
735 - return dynamic_cast<QPDF_Array*>(obj.get())->getNItems(); 792 + auto array = asArray();
  793 + if (array) {
  794 + return array->getNItems();
736 } else { 795 } else {
737 typeWarning("array", "treating as empty"); 796 typeWarning("array", "treating as empty");
738 QTC::TC("qpdf", "QPDFObjectHandle array treating as empty"); 797 QTC::TC("qpdf", "QPDFObjectHandle array treating as empty");
@@ -744,11 +803,12 @@ QPDFObjectHandle @@ -744,11 +803,12 @@ QPDFObjectHandle
744 QPDFObjectHandle::getArrayItem(int n) 803 QPDFObjectHandle::getArrayItem(int n)
745 { 804 {
746 QPDFObjectHandle result; 805 QPDFObjectHandle result;
747 - if (isArray() && (n < getArrayNItems()) && (n >= 0)) {  
748 - result = dynamic_cast<QPDF_Array*>(obj.get())->getItem(n); 806 + auto array = asArray();
  807 + if (array && (n < array->getNItems()) && (n >= 0)) {
  808 + result = array->getItem(n);
749 } else { 809 } else {
750 result = newNull(); 810 result = newNull();
751 - if (isArray()) { 811 + if (array) {
752 objectWarning("returning null for out of bounds array access"); 812 objectWarning("returning null for out of bounds array access");
753 QTC::TC("qpdf", "QPDFObjectHandle array bounds"); 813 QTC::TC("qpdf", "QPDFObjectHandle array bounds");
754 } else { 814 } else {
@@ -757,7 +817,7 @@ QPDFObjectHandle::getArrayItem(int n) @@ -757,7 +817,7 @@ QPDFObjectHandle::getArrayItem(int n)
757 } 817 }
758 QPDF* context = nullptr; 818 QPDF* context = nullptr;
759 std::string description; 819 std::string description;
760 - if (this->obj->getDescription(context, description)) { 820 + if (obj->getDescription(context, description)) {
761 result.setObjectDescription( 821 result.setObjectDescription(
762 context, 822 context,
763 description + " -> null returned from invalid array access"); 823 description + " -> null returned from invalid array access");
@@ -769,14 +829,12 @@ QPDFObjectHandle::getArrayItem(int n) @@ -769,14 +829,12 @@ QPDFObjectHandle::getArrayItem(int n)
769 bool 829 bool
770 QPDFObjectHandle::isRectangle() 830 QPDFObjectHandle::isRectangle()
771 { 831 {
772 - if (!isArray()) {  
773 - return false;  
774 - }  
775 - if (getArrayNItems() != 4) { 832 + auto array = asArray();
  833 + if ((array == nullptr) || (array->getNItems() != 4)) {
776 return false; 834 return false;
777 } 835 }
778 for (int i = 0; i < 4; ++i) { 836 for (int i = 0; i < 4; ++i) {
779 - if (!getArrayItem(i).isNumber()) { 837 + if (!array->getItem(i).isNumber()) {
780 return false; 838 return false;
781 } 839 }
782 } 840 }
@@ -786,14 +844,12 @@ QPDFObjectHandle::isRectangle() @@ -786,14 +844,12 @@ QPDFObjectHandle::isRectangle()
786 bool 844 bool
787 QPDFObjectHandle::isMatrix() 845 QPDFObjectHandle::isMatrix()
788 { 846 {
789 - if (!isArray()) {  
790 - return false;  
791 - }  
792 - if (getArrayNItems() != 6) { 847 + auto array = asArray();
  848 + if ((array == nullptr) || (array->getNItems() != 6)) {
793 return false; 849 return false;
794 } 850 }
795 for (int i = 0; i < 6; ++i) { 851 for (int i = 0; i < 6; ++i) {
796 - if (!getArrayItem(i).isNumber()) { 852 + if (!array->getItem(i).isNumber()) {
797 return false; 853 return false;
798 } 854 }
799 } 855 }
@@ -805,13 +861,14 @@ QPDFObjectHandle::getArrayAsRectangle() @@ -805,13 +861,14 @@ QPDFObjectHandle::getArrayAsRectangle()
805 { 861 {
806 Rectangle result; 862 Rectangle result;
807 if (isRectangle()) { 863 if (isRectangle()) {
  864 + auto array = asArray();
808 // Rectangle coordinates are always supposed to be llx, lly, 865 // Rectangle coordinates are always supposed to be llx, lly,
809 // urx, ury, but files have been found in the wild where 866 // urx, ury, but files have been found in the wild where
810 // llx > urx or lly > ury. 867 // llx > urx or lly > ury.
811 - double i0 = getArrayItem(0).getNumericValue();  
812 - double i1 = getArrayItem(1).getNumericValue();  
813 - double i2 = getArrayItem(2).getNumericValue();  
814 - double i3 = getArrayItem(3).getNumericValue(); 868 + double i0 = array->getItem(0).getNumericValue();
  869 + double i1 = array->getItem(1).getNumericValue();
  870 + double i2 = array->getItem(2).getNumericValue();
  871 + double i3 = array->getItem(3).getNumericValue();
815 result = Rectangle( 872 result = Rectangle(
816 std::min(i0, i2), 873 std::min(i0, i2),
817 std::min(i1, i3), 874 std::min(i1, i3),
@@ -826,13 +883,14 @@ QPDFObjectHandle::getArrayAsMatrix() @@ -826,13 +883,14 @@ QPDFObjectHandle::getArrayAsMatrix()
826 { 883 {
827 Matrix result; 884 Matrix result;
828 if (isMatrix()) { 885 if (isMatrix()) {
  886 + auto array = asArray();
829 result = Matrix( 887 result = Matrix(
830 - getArrayItem(0).getNumericValue(),  
831 - getArrayItem(1).getNumericValue(),  
832 - getArrayItem(2).getNumericValue(),  
833 - getArrayItem(3).getNumericValue(),  
834 - getArrayItem(4).getNumericValue(),  
835 - getArrayItem(5).getNumericValue()); 888 + array->getItem(0).getNumericValue(),
  889 + array->getItem(1).getNumericValue(),
  890 + array->getItem(2).getNumericValue(),
  891 + array->getItem(3).getNumericValue(),
  892 + array->getItem(4).getNumericValue(),
  893 + array->getItem(5).getNumericValue());
836 } 894 }
837 return result; 895 return result;
838 } 896 }
@@ -841,8 +899,9 @@ std::vector&lt;QPDFObjectHandle&gt; @@ -841,8 +899,9 @@ std::vector&lt;QPDFObjectHandle&gt;
841 QPDFObjectHandle::getArrayAsVector() 899 QPDFObjectHandle::getArrayAsVector()
842 { 900 {
843 std::vector<QPDFObjectHandle> result; 901 std::vector<QPDFObjectHandle> result;
844 - if (isArray()) {  
845 - dynamic_cast<QPDF_Array*>(obj.get())->getAsVector(result); 902 + auto array = asArray();
  903 + if (array) {
  904 + array->getAsVector(result);
846 } else { 905 } else {
847 typeWarning("array", "treating as empty"); 906 typeWarning("array", "treating as empty");
848 QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector"); 907 QTC::TC("qpdf", "QPDFObjectHandle array treating as empty vector");
@@ -855,9 +914,10 @@ QPDFObjectHandle::getArrayAsVector() @@ -855,9 +914,10 @@ QPDFObjectHandle::getArrayAsVector()
855 void 914 void
856 QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item) 915 QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const& item)
857 { 916 {
858 - if (isArray()) { 917 + auto array = asArray();
  918 + if (array) {
859 checkOwnership(item); 919 checkOwnership(item);
860 - dynamic_cast<QPDF_Array*>(obj.get())->setItem(n, item); 920 + array->setItem(n, item);
861 } else { 921 } else {
862 typeWarning("array", "ignoring attempt to set item"); 922 typeWarning("array", "ignoring attempt to set item");
863 QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item"); 923 QTC::TC("qpdf", "QPDFObjectHandle array ignoring set item");
@@ -867,11 +927,12 @@ QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const&amp; item) @@ -867,11 +927,12 @@ QPDFObjectHandle::setArrayItem(int n, QPDFObjectHandle const&amp; item)
867 void 927 void
868 QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items) 928 QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
869 { 929 {
870 - if (isArray()) { 930 + auto array = asArray();
  931 + if (array) {
871 for (auto const& item: items) { 932 for (auto const& item: items) {
872 checkOwnership(item); 933 checkOwnership(item);
873 } 934 }
874 - dynamic_cast<QPDF_Array*>(obj.get())->setFromVector(items); 935 + array->setFromVector(items);
875 } else { 936 } else {
876 typeWarning("array", "ignoring attempt to replace items"); 937 typeWarning("array", "ignoring attempt to replace items");
877 QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items"); 938 QTC::TC("qpdf", "QPDFObjectHandle array ignoring replace items");
@@ -881,8 +942,9 @@ QPDFObjectHandle::setArrayFromVector(std::vector&lt;QPDFObjectHandle&gt; const&amp; items) @@ -881,8 +942,9 @@ QPDFObjectHandle::setArrayFromVector(std::vector&lt;QPDFObjectHandle&gt; const&amp; items)
881 void 942 void
882 QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item) 943 QPDFObjectHandle::insertItem(int at, QPDFObjectHandle const& item)
883 { 944 {
884 - if (isArray()) {  
885 - dynamic_cast<QPDF_Array*>(obj.get())->insertItem(at, item); 945 + auto array = asArray();
  946 + if (array) {
  947 + array->insertItem(at, item);
886 } else { 948 } else {
887 typeWarning("array", "ignoring attempt to insert item"); 949 typeWarning("array", "ignoring attempt to insert item");
888 QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item"); 950 QTC::TC("qpdf", "QPDFObjectHandle array ignoring insert item");
@@ -899,9 +961,10 @@ QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const&amp; item) @@ -899,9 +961,10 @@ QPDFObjectHandle::insertItemAndGetNew(int at, QPDFObjectHandle const&amp; item)
899 void 961 void
900 QPDFObjectHandle::appendItem(QPDFObjectHandle const& item) 962 QPDFObjectHandle::appendItem(QPDFObjectHandle const& item)
901 { 963 {
902 - if (isArray()) { 964 + auto array = asArray();
  965 + if (array) {
903 checkOwnership(item); 966 checkOwnership(item);
904 - dynamic_cast<QPDF_Array*>(obj.get())->appendItem(item); 967 + array->appendItem(item);
905 } else { 968 } else {
906 typeWarning("array", "ignoring attempt to append item"); 969 typeWarning("array", "ignoring attempt to append item");
907 QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item"); 970 QTC::TC("qpdf", "QPDFObjectHandle array ignoring append item");
@@ -918,10 +981,11 @@ QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const&amp; item) @@ -918,10 +981,11 @@ QPDFObjectHandle::appendItemAndGetNew(QPDFObjectHandle const&amp; item)
918 void 981 void
919 QPDFObjectHandle::eraseItem(int at) 982 QPDFObjectHandle::eraseItem(int at)
920 { 983 {
921 - if (isArray() && (at < getArrayNItems()) && (at >= 0)) {  
922 - dynamic_cast<QPDF_Array*>(obj.get())->eraseItem(at); 984 + auto array = asArray();
  985 + if (array && (at < array->getNItems()) && (at >= 0)) {
  986 + array->eraseItem(at);
923 } else { 987 } else {
924 - if (isArray()) { 988 + if (array) {
925 objectWarning("ignoring attempt to erase out of bounds array item"); 989 objectWarning("ignoring attempt to erase out of bounds array item");
926 QTC::TC("qpdf", "QPDFObjectHandle erase array bounds"); 990 QTC::TC("qpdf", "QPDFObjectHandle erase array bounds");
927 } else { 991 } else {
@@ -935,8 +999,9 @@ QPDFObjectHandle @@ -935,8 +999,9 @@ QPDFObjectHandle
935 QPDFObjectHandle::eraseItemAndGetOld(int at) 999 QPDFObjectHandle::eraseItemAndGetOld(int at)
936 { 1000 {
937 auto result = QPDFObjectHandle::newNull(); 1001 auto result = QPDFObjectHandle::newNull();
938 - if (isArray() && (at < getArrayNItems()) && (at >= 0)) {  
939 - result = getArrayItem(at); 1002 + auto array = asArray();
  1003 + if (array && (at < array->getNItems()) && (at >= 0)) {
  1004 + result = array->getItem(at);
940 } 1005 }
941 eraseItem(at); 1006 eraseItem(at);
942 return result; 1007 return result;
@@ -953,8 +1018,9 @@ QPDFObjectHandle::ditems() @@ -953,8 +1018,9 @@ QPDFObjectHandle::ditems()
953 bool 1018 bool
954 QPDFObjectHandle::hasKey(std::string const& key) 1019 QPDFObjectHandle::hasKey(std::string const& key)
955 { 1020 {
956 - if (isDictionary()) {  
957 - return dynamic_cast<QPDF_Dictionary*>(obj.get())->hasKey(key); 1021 + auto dict = asDictionary();
  1022 + if (dict) {
  1023 + return dict->hasKey(key);
958 } else { 1024 } else {
959 typeWarning( 1025 typeWarning(
960 "dictionary", "returning false for a key containment request"); 1026 "dictionary", "returning false for a key containment request");
@@ -967,15 +1033,16 @@ QPDFObjectHandle @@ -967,15 +1033,16 @@ QPDFObjectHandle
967 QPDFObjectHandle::getKey(std::string const& key) 1033 QPDFObjectHandle::getKey(std::string const& key)
968 { 1034 {
969 QPDFObjectHandle result; 1035 QPDFObjectHandle result;
970 - if (isDictionary()) {  
971 - result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getKey(key); 1036 + auto dict = asDictionary();
  1037 + if (dict) {
  1038 + result = dict->getKey(key);
972 } else { 1039 } else {
973 typeWarning("dictionary", "returning null for attempted key retrieval"); 1040 typeWarning("dictionary", "returning null for attempted key retrieval");
974 QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey"); 1041 QTC::TC("qpdf", "QPDFObjectHandle dictionary null for getKey");
975 result = newNull(); 1042 result = newNull();
976 QPDF* qpdf = nullptr; 1043 QPDF* qpdf = nullptr;
977 std::string description; 1044 std::string description;
978 - if (this->obj->getDescription(qpdf, description)) { 1045 + if (obj->getDescription(qpdf, description)) {
979 result.setObjectDescription( 1046 result.setObjectDescription(
980 qpdf, 1047 qpdf,
981 (description + " -> null returned from getting key " + key + 1048 (description + " -> null returned from getting key " + key +
@@ -995,8 +1062,9 @@ std::set&lt;std::string&gt; @@ -995,8 +1062,9 @@ std::set&lt;std::string&gt;
995 QPDFObjectHandle::getKeys() 1062 QPDFObjectHandle::getKeys()
996 { 1063 {
997 std::set<std::string> result; 1064 std::set<std::string> result;
998 - if (isDictionary()) {  
999 - result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getKeys(); 1065 + auto dict = asDictionary();
  1066 + if (dict) {
  1067 + result = dict->getKeys();
1000 } else { 1068 } else {
1001 typeWarning("dictionary", "treating as empty"); 1069 typeWarning("dictionary", "treating as empty");
1002 QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys"); 1070 QTC::TC("qpdf", "QPDFObjectHandle dictionary empty set for getKeys");
@@ -1008,8 +1076,9 @@ std::map&lt;std::string, QPDFObjectHandle&gt; @@ -1008,8 +1076,9 @@ std::map&lt;std::string, QPDFObjectHandle&gt;
1008 QPDFObjectHandle::getDictAsMap() 1076 QPDFObjectHandle::getDictAsMap()
1009 { 1077 {
1010 std::map<std::string, QPDFObjectHandle> result; 1078 std::map<std::string, QPDFObjectHandle> result;
1011 - if (isDictionary()) {  
1012 - result = dynamic_cast<QPDF_Dictionary*>(obj.get())->getAsMap(); 1079 + auto dict = asDictionary();
  1080 + if (dict) {
  1081 + result = dict->getAsMap();
1013 } else { 1082 } else {
1014 typeWarning("dictionary", "treating as empty"); 1083 typeWarning("dictionary", "treating as empty");
1015 QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap"); 1084 QTC::TC("qpdf", "QPDFObjectHandle dictionary empty map for asMap");
@@ -1200,9 +1269,10 @@ void @@ -1200,9 +1269,10 @@ void
1200 QPDFObjectHandle::replaceKey( 1269 QPDFObjectHandle::replaceKey(
1201 std::string const& key, QPDFObjectHandle const& value) 1270 std::string const& key, QPDFObjectHandle const& value)
1202 { 1271 {
1203 - if (isDictionary()) { 1272 + auto dict = asDictionary();
  1273 + if (dict) {
1204 checkOwnership(value); 1274 checkOwnership(value);
1205 - dynamic_cast<QPDF_Dictionary*>(obj.get())->replaceKey(key, value); 1275 + dict->replaceKey(key, value);
1206 } else { 1276 } else {
1207 typeWarning("dictionary", "ignoring key replacement request"); 1277 typeWarning("dictionary", "ignoring key replacement request");
1208 QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey"); 1278 QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring replaceKey");
@@ -1229,8 +1299,9 @@ QPDFObjectHandle::replaceKeyAndGetOld( @@ -1229,8 +1299,9 @@ QPDFObjectHandle::replaceKeyAndGetOld(
1229 void 1299 void
1230 QPDFObjectHandle::removeKey(std::string const& key) 1300 QPDFObjectHandle::removeKey(std::string const& key)
1231 { 1301 {
1232 - if (isDictionary()) {  
1233 - dynamic_cast<QPDF_Dictionary*>(obj.get())->removeKey(key); 1302 + auto dict = asDictionary();
  1303 + if (dict) {
  1304 + dict->removeKey(key);
1234 } else { 1305 } else {
1235 typeWarning("dictionary", "ignoring key removal request"); 1306 typeWarning("dictionary", "ignoring key removal request");
1236 QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey"); 1307 QTC::TC("qpdf", "QPDFObjectHandle dictionary ignoring removeKey");
@@ -1241,8 +1312,9 @@ QPDFObjectHandle @@ -1241,8 +1312,9 @@ QPDFObjectHandle
1241 QPDFObjectHandle::removeKeyAndGetOld(std::string const& key) 1312 QPDFObjectHandle::removeKeyAndGetOld(std::string const& key)
1242 { 1313 {
1243 auto result = QPDFObjectHandle::newNull(); 1314 auto result = QPDFObjectHandle::newNull();
1244 - if (isDictionary()) {  
1245 - result = getKey(key); 1315 + auto dict = asDictionary();
  1316 + if (dict) {
  1317 + result = dict->getKey(key);
1246 } 1318 }
1247 removeKey(key); 1319 removeKey(key);
1248 return result; 1320 return result;
@@ -1259,50 +1331,43 @@ QPDFObjectHandle::replaceOrRemoveKey( @@ -1259,50 +1331,43 @@ QPDFObjectHandle::replaceOrRemoveKey(
1259 QPDFObjectHandle 1331 QPDFObjectHandle
1260 QPDFObjectHandle::getDict() 1332 QPDFObjectHandle::getDict()
1261 { 1333 {
1262 - assertStream();  
1263 - return dynamic_cast<QPDF_Stream*>(obj.get())->getDict(); 1334 + return asStreamWithAssert()->getDict();
1264 } 1335 }
1265 1336
1266 void 1337 void
1267 QPDFObjectHandle::setFilterOnWrite(bool val) 1338 QPDFObjectHandle::setFilterOnWrite(bool val)
1268 { 1339 {
1269 - assertStream();  
1270 - dynamic_cast<QPDF_Stream*>(obj.get())->setFilterOnWrite(val); 1340 + asStreamWithAssert()->setFilterOnWrite(val);
1271 } 1341 }
1272 1342
1273 bool 1343 bool
1274 QPDFObjectHandle::getFilterOnWrite() 1344 QPDFObjectHandle::getFilterOnWrite()
1275 { 1345 {
1276 - assertStream();  
1277 - return dynamic_cast<QPDF_Stream*>(obj.get())->getFilterOnWrite(); 1346 + return asStreamWithAssert()->getFilterOnWrite();
1278 } 1347 }
1279 1348
1280 bool 1349 bool
1281 QPDFObjectHandle::isDataModified() 1350 QPDFObjectHandle::isDataModified()
1282 { 1351 {
1283 - assertStream();  
1284 - return dynamic_cast<QPDF_Stream*>(obj.get())->isDataModified(); 1352 + return asStreamWithAssert()->isDataModified();
1285 } 1353 }
1286 1354
1287 void 1355 void
1288 QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict) 1356 QPDFObjectHandle::replaceDict(QPDFObjectHandle const& new_dict)
1289 { 1357 {
1290 - assertStream();  
1291 - dynamic_cast<QPDF_Stream*>(obj.get())->replaceDict(new_dict); 1358 + asStreamWithAssert()->replaceDict(new_dict);
1292 } 1359 }
1293 1360
1294 std::shared_ptr<Buffer> 1361 std::shared_ptr<Buffer>
1295 QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level) 1362 QPDFObjectHandle::getStreamData(qpdf_stream_decode_level_e level)
1296 { 1363 {
1297 - assertStream();  
1298 - return dynamic_cast<QPDF_Stream*>(obj.get())->getStreamData(level); 1364 + return asStreamWithAssert()->getStreamData(level);
1299 } 1365 }
1300 1366
1301 std::shared_ptr<Buffer> 1367 std::shared_ptr<Buffer>
1302 QPDFObjectHandle::getRawStreamData() 1368 QPDFObjectHandle::getRawStreamData()
1303 { 1369 {
1304 - assertStream();  
1305 - return dynamic_cast<QPDF_Stream*>(obj.get())->getRawStreamData(); 1370 + return asStreamWithAssert()->getRawStreamData();
1306 } 1371 }
1307 1372
1308 bool 1373 bool
@@ -1314,8 +1379,7 @@ QPDFObjectHandle::pipeStreamData( @@ -1314,8 +1379,7 @@ QPDFObjectHandle::pipeStreamData(
1314 bool suppress_warnings, 1379 bool suppress_warnings,
1315 bool will_retry) 1380 bool will_retry)
1316 { 1381 {
1317 - assertStream();  
1318 - return dynamic_cast<QPDF_Stream*>(obj.get())->pipeStreamData( 1382 + return asStreamWithAssert()->pipeStreamData(
1319 p, 1383 p,
1320 filtering_attempted, 1384 filtering_attempted,
1321 encode_flags, 1385 encode_flags,
@@ -1332,9 +1396,8 @@ QPDFObjectHandle::pipeStreamData( @@ -1332,9 +1396,8 @@ QPDFObjectHandle::pipeStreamData(
1332 bool suppress_warnings, 1396 bool suppress_warnings,
1333 bool will_retry) 1397 bool will_retry)
1334 { 1398 {
1335 - assertStream();  
1336 bool filtering_attempted; 1399 bool filtering_attempted;
1337 - dynamic_cast<QPDF_Stream*>(obj.get())->pipeStreamData( 1400 + asStreamWithAssert()->pipeStreamData(
1338 p, 1401 p,
1339 &filtering_attempted, 1402 &filtering_attempted,
1340 encode_flags, 1403 encode_flags,
@@ -1368,9 +1431,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1368,9 +1431,7 @@ QPDFObjectHandle::replaceStreamData(
1368 QPDFObjectHandle const& filter, 1431 QPDFObjectHandle const& filter,
1369 QPDFObjectHandle const& decode_parms) 1432 QPDFObjectHandle const& decode_parms)
1370 { 1433 {
1371 - assertStream();  
1372 - dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(  
1373 - data, filter, decode_parms); 1434 + asStreamWithAssert()->replaceStreamData(data, filter, decode_parms);
1374 } 1435 }
1375 1436
1376 void 1437 void
@@ -1379,14 +1440,12 @@ QPDFObjectHandle::replaceStreamData( @@ -1379,14 +1440,12 @@ QPDFObjectHandle::replaceStreamData(
1379 QPDFObjectHandle const& filter, 1440 QPDFObjectHandle const& filter,
1380 QPDFObjectHandle const& decode_parms) 1441 QPDFObjectHandle const& decode_parms)
1381 { 1442 {
1382 - assertStream();  
1383 auto b = std::make_shared<Buffer>(data.length()); 1443 auto b = std::make_shared<Buffer>(data.length());
1384 unsigned char* bp = b->getBuffer(); 1444 unsigned char* bp = b->getBuffer();
1385 if (bp) { 1445 if (bp) {
1386 memcpy(bp, data.c_str(), data.length()); 1446 memcpy(bp, data.c_str(), data.length());
1387 } 1447 }
1388 - dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(  
1389 - b, filter, decode_parms); 1448 + asStreamWithAssert()->replaceStreamData(b, filter, decode_parms);
1390 } 1449 }
1391 1450
1392 void 1451 void
@@ -1395,9 +1454,7 @@ QPDFObjectHandle::replaceStreamData( @@ -1395,9 +1454,7 @@ QPDFObjectHandle::replaceStreamData(
1395 QPDFObjectHandle const& filter, 1454 QPDFObjectHandle const& filter,
1396 QPDFObjectHandle const& decode_parms) 1455 QPDFObjectHandle const& decode_parms)
1397 { 1456 {
1398 - assertStream();  
1399 - dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(  
1400 - provider, filter, decode_parms); 1457 + asStreamWithAssert()->replaceStreamData(provider, filter, decode_parms);
1401 } 1458 }
1402 1459
1403 namespace 1460 namespace
@@ -1446,11 +1503,9 @@ QPDFObjectHandle::replaceStreamData( @@ -1446,11 +1503,9 @@ QPDFObjectHandle::replaceStreamData(
1446 QPDFObjectHandle const& filter, 1503 QPDFObjectHandle const& filter,
1447 QPDFObjectHandle const& decode_parms) 1504 QPDFObjectHandle const& decode_parms)
1448 { 1505 {
1449 - assertStream();  
1450 auto sdp = 1506 auto sdp =
1451 std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); 1507 std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
1452 - dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(  
1453 - sdp, filter, decode_parms); 1508 + asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
1454 } 1509 }
1455 1510
1456 void 1511 void
@@ -1459,11 +1514,9 @@ QPDFObjectHandle::replaceStreamData( @@ -1459,11 +1514,9 @@ QPDFObjectHandle::replaceStreamData(
1459 QPDFObjectHandle const& filter, 1514 QPDFObjectHandle const& filter,
1460 QPDFObjectHandle const& decode_parms) 1515 QPDFObjectHandle const& decode_parms)
1461 { 1516 {
1462 - assertStream();  
1463 auto sdp = 1517 auto sdp =
1464 std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider)); 1518 std::shared_ptr<StreamDataProvider>(new FunctionProvider(provider));
1465 - dynamic_cast<QPDF_Stream*>(obj.get())->replaceStreamData(  
1466 - sdp, filter, decode_parms); 1519 + asStreamWithAssert()->replaceStreamData(sdp, filter, decode_parms);
1467 } 1520 }
1468 1521
1469 std::map<std::string, QPDFObjectHandle> 1522 std::map<std::string, QPDFObjectHandle>
@@ -1478,10 +1531,11 @@ QPDFObjectHandle::arrayOrStreamToStreamArray( @@ -1478,10 +1531,11 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
1478 { 1531 {
1479 all_description = description; 1532 all_description = description;
1480 std::vector<QPDFObjectHandle> result; 1533 std::vector<QPDFObjectHandle> result;
1481 - if (isArray()) {  
1482 - int n_items = getArrayNItems(); 1534 + auto array = asArray();
  1535 + if (array) {
  1536 + int n_items = array->getNItems();
1483 for (int i = 0; i < n_items; ++i) { 1537 for (int i = 0; i < n_items; ++i) {
1484 - QPDFObjectHandle item = getArrayItem(i); 1538 + QPDFObjectHandle item = array->getItem(i);
1485 if (item.isStream()) { 1539 if (item.isStream()) {
1486 result.push_back(item); 1540 result.push_back(item);
1487 } else { 1541 } else {
@@ -1648,18 +1702,16 @@ QPDFObjectHandle::unparseResolved() @@ -1648,18 +1702,16 @@ QPDFObjectHandle::unparseResolved()
1648 if (!dereference()) { 1702 if (!dereference()) {
1649 throw std::logic_error( 1703 throw std::logic_error(
1650 "attempted to dereference an uninitialized QPDFObjectHandle"); 1704 "attempted to dereference an uninitialized QPDFObjectHandle");
1651 - } else if (this->reserved) {  
1652 - throw std::logic_error(  
1653 - "QPDFObjectHandle: attempting to unparse a reserved object");  
1654 } 1705 }
1655 - return this->obj->unparse(); 1706 + return obj->unparse();
1656 } 1707 }
1657 1708
1658 std::string 1709 std::string
1659 QPDFObjectHandle::unparseBinary() 1710 QPDFObjectHandle::unparseBinary()
1660 { 1711 {
1661 - if (this->isString()) {  
1662 - return dynamic_cast<QPDF_String*>(this->obj.get())->unparse(true); 1712 + auto str = asString();
  1713 + if (str) {
  1714 + return str->unparse(true);
1663 } else { 1715 } else {
1664 return unparse(); 1716 return unparse();
1665 } 1717 }
@@ -1675,16 +1727,13 @@ QPDFObjectHandle::getJSON(bool dereference_indirect) @@ -1675,16 +1727,13 @@ QPDFObjectHandle::getJSON(bool dereference_indirect)
1675 JSON 1727 JSON
1676 QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect) 1728 QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
1677 { 1729 {
1678 - if ((!dereference_indirect) && this->isIndirect()) { 1730 + if ((!dereference_indirect) && isIndirect()) {
1679 return JSON::makeString(unparse()); 1731 return JSON::makeString(unparse());
1680 } else if (!dereference()) { 1732 } else if (!dereference()) {
1681 throw std::logic_error( 1733 throw std::logic_error(
1682 "attempted to dereference an uninitialized QPDFObjectHandle"); 1734 "attempted to dereference an uninitialized QPDFObjectHandle");
1683 - } else if (this->reserved) {  
1684 - throw std::logic_error(  
1685 - "QPDFObjectHandle: attempting to unparse a reserved object");  
1686 } else { 1735 } else {
1687 - return this->obj->getJSON(json_version); 1736 + return obj->getJSON(json_version);
1688 } 1737 }
1689 } 1738 }
1690 1739
@@ -1696,8 +1745,7 @@ QPDFObjectHandle::getStreamJSON( @@ -1696,8 +1745,7 @@ QPDFObjectHandle::getStreamJSON(
1696 Pipeline* p, 1745 Pipeline* p,
1697 std::string const& data_filename) 1746 std::string const& data_filename)
1698 { 1747 {
1699 - assertStream();  
1700 - return dynamic_cast<QPDF_Stream*>(obj.get())->getStreamJSON( 1748 + return asStreamWithAssert()->getStreamJSON(
1701 json_version, json_data, decode_level, p, data_filename); 1749 json_version, json_data, decode_level, p, data_filename);
1702 } 1750 }
1703 1751
@@ -1917,8 +1965,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr&lt;TokenFilter&gt; filter) @@ -1917,8 +1965,7 @@ QPDFObjectHandle::addContentTokenFilter(std::shared_ptr&lt;TokenFilter&gt; filter)
1917 void 1965 void
1918 QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter) 1966 QPDFObjectHandle::addTokenFilter(std::shared_ptr<TokenFilter> filter)
1919 { 1967 {
1920 - assertStream();  
1921 - return dynamic_cast<QPDF_Stream*>(obj.get())->addTokenFilter(filter); 1968 + return asStreamWithAssert()->addTokenFilter(filter);
1922 } 1969 }
1923 1970
1924 QPDFObjectHandle 1971 QPDFObjectHandle
@@ -1945,21 +1992,6 @@ QPDFObjectHandle::getParsedOffset() @@ -1945,21 +1992,6 @@ QPDFObjectHandle::getParsedOffset()
1945 } 1992 }
1946 1993
1947 QPDFObjectHandle 1994 QPDFObjectHandle
1948 -QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og)  
1949 -{  
1950 - if (!og.isIndirect()) {  
1951 - // Special case: QPDF uses objid 0 as a sentinel for direct  
1952 - // objects, and the PDF specification doesn't allow for object  
1953 - // 0. Treat indirect references to object 0 as null so that we  
1954 - // never create an indirect object with objid 0.  
1955 - QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid");  
1956 - return newNull();  
1957 - }  
1958 -  
1959 - return QPDFObjectHandle(qpdf, og);  
1960 -}  
1961 -  
1962 -QPDFObjectHandle  
1963 QPDFObjectHandle::newBool(bool value) 1995 QPDFObjectHandle::newBool(bool value)
1964 { 1996 {
1965 return QPDFObjectHandle(QPDF_Bool::create(value)); 1997 return QPDFObjectHandle(QPDF_Bool::create(value));
@@ -2128,8 +2160,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf) @@ -2128,8 +2160,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf)
2128 QPDFObjectHandle stream_dict = newDictionary(); 2160 QPDFObjectHandle stream_dict = newDictionary();
2129 QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle( 2161 QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle(
2130 QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0))); 2162 QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0)));
2131 - result.dereference();  
2132 - QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(result.obj.get()); 2163 + auto stream = result.asStream();
2133 stream->setObjGen(result.getObjGen()); 2164 stream->setObjGen(result.getObjGen());
2134 return result; 2165 return result;
2135 } 2166 }
@@ -2155,18 +2186,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const&amp; data) @@ -2155,18 +2186,7 @@ QPDFObjectHandle::newStream(QPDF* qpdf, std::string const&amp; data)
2155 QPDFObjectHandle 2186 QPDFObjectHandle
2156 QPDFObjectHandle::newReserved(QPDF* qpdf) 2187 QPDFObjectHandle::newReserved(QPDF* qpdf)
2157 { 2188 {
2158 - // Reserve a spot for this object by assigning it an object  
2159 - // number, but then return an unresolved handle to the object.  
2160 - QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved());  
2161 - QPDFObjectHandle result = newIndirect(qpdf, reserved.getObjGen());  
2162 - result.reserved = true;  
2163 - return result;  
2164 -}  
2165 -  
2166 -QPDFObjectHandle  
2167 -QPDFObjectHandle::makeReserved()  
2168 -{  
2169 - return QPDFObjectHandle(QPDF_Reserved::create()); 2189 + return qpdf->makeIndirectObject(QPDFObjectHandle(QPDF_Reserved::create()));
2170 } 2190 }
2171 2191
2172 void 2192 void
@@ -2212,12 +2232,7 @@ QPDFObjectHandle::shallowCopyInternal( @@ -2212,12 +2232,7 @@ QPDFObjectHandle::shallowCopyInternal(
2212 QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream"); 2232 QTC::TC("qpdf", "QPDFObjectHandle ERR shallow copy stream");
2213 throw std::runtime_error("attempt to make a shallow copy of a stream"); 2233 throw std::runtime_error("attempt to make a shallow copy of a stream");
2214 } 2234 }
2215 -  
2216 - if (isArray() || isDictionary()) {  
2217 - new_obj = QPDFObjectHandle(obj->shallowCopy());  
2218 - } else {  
2219 - new_obj = *this;  
2220 - } 2235 + new_obj = QPDFObjectHandle(obj->shallowCopy());
2221 2236
2222 std::set<QPDFObjGen> visited; 2237 std::set<QPDFObjGen> visited;
2223 new_obj.copyObject(visited, false, first_level_only, false); 2238 new_obj.copyObject(visited, false, first_level_only, false);
@@ -2258,9 +2273,6 @@ QPDFObjectHandle::copyObject( @@ -2258,9 +2273,6 @@ QPDFObjectHandle::copyObject(
2258 " reserved object handle direct"); 2273 " reserved object handle direct");
2259 } 2274 }
2260 2275
2261 - qpdf = nullptr;  
2262 - og = QPDFObjGen();  
2263 -  
2264 std::shared_ptr<QPDFObject> new_obj; 2276 std::shared_ptr<QPDFObject> new_obj;
2265 2277
2266 if (isBool() || isInteger() || isName() || isNull() || isReal() || 2278 if (isBool() || isInteger() || isName() || isNull() || isReal() ||
@@ -2268,9 +2280,10 @@ QPDFObjectHandle::copyObject( @@ -2268,9 +2280,10 @@ QPDFObjectHandle::copyObject(
2268 new_obj = obj->shallowCopy(); 2280 new_obj = obj->shallowCopy();
2269 } else if (isArray()) { 2281 } else if (isArray()) {
2270 std::vector<QPDFObjectHandle> items; 2282 std::vector<QPDFObjectHandle> items;
2271 - int n = getArrayNItems(); 2283 + auto array = asArray();
  2284 + int n = array->getNItems();
2272 for (int i = 0; i < n; ++i) { 2285 for (int i = 0; i < n; ++i) {
2273 - items.push_back(getArrayItem(i)); 2286 + items.push_back(array->getItem(i));
2274 if ((!first_level_only) && 2287 if ((!first_level_only) &&
2275 (cross_indirect || (!items.back().isIndirect()))) { 2288 (cross_indirect || (!items.back().isIndirect()))) {
2276 items.back().copyObject( 2289 items.back().copyObject(
@@ -2280,8 +2293,9 @@ QPDFObjectHandle::copyObject( @@ -2280,8 +2293,9 @@ QPDFObjectHandle::copyObject(
2280 new_obj = QPDF_Array::create(items); 2293 new_obj = QPDF_Array::create(items);
2281 } else if (isDictionary()) { 2294 } else if (isDictionary()) {
2282 std::map<std::string, QPDFObjectHandle> items; 2295 std::map<std::string, QPDFObjectHandle> items;
  2296 + auto dict = asDictionary();
2283 for (auto const& key: getKeys()) { 2297 for (auto const& key: getKeys()) {
2284 - items[key] = getKey(key); 2298 + items[key] = dict->getKey(key);
2285 if ((!first_level_only) && 2299 if ((!first_level_only) &&
2286 (cross_indirect || (!items[key].isIndirect()))) { 2300 (cross_indirect || (!items[key].isIndirect()))) {
2287 items[key].copyObject( 2301 items[key].copyObject(
@@ -2329,7 +2343,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams) @@ -2329,7 +2343,7 @@ QPDFObjectHandle::makeDirect(bool allow_streams)
2329 void 2343 void
2330 QPDFObjectHandle::assertInitialized() const 2344 QPDFObjectHandle::assertInitialized() const
2331 { 2345 {
2332 - if (!this->initialized) { 2346 + if (!isInitialized()) {
2333 throw std::logic_error("operation attempted on uninitialized " 2347 throw std::logic_error("operation attempted on uninitialized "
2334 "QPDFObjectHandle"); 2348 "QPDFObjectHandle");
2335 } 2349 }
@@ -2544,8 +2558,9 @@ QPDFObjectHandle::isImage(bool exclude_imagemask) @@ -2544,8 +2558,9 @@ QPDFObjectHandle::isImage(bool exclude_imagemask)
2544 void 2558 void
2545 QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const 2559 QPDFObjectHandle::checkOwnership(QPDFObjectHandle const& item) const
2546 { 2560 {
2547 - if ((this->qpdf != nullptr) && (item.qpdf != nullptr) &&  
2548 - (this->qpdf != item.qpdf)) { 2561 + auto qpdf = getOwningQPDF();
  2562 + auto item_qpdf = item.getOwningQPDF();
  2563 + if ((qpdf != nullptr) && (item_qpdf != nullptr) && (qpdf != item_qpdf)) {
2549 QTC::TC("qpdf", "QPDFObjectHandle check ownership"); 2564 QTC::TC("qpdf", "QPDFObjectHandle check ownership");
2550 throw std::logic_error( 2565 throw std::logic_error(
2551 "Attempting to add an object from a different QPDF." 2566 "Attempting to add an object from a different QPDF."
@@ -2564,28 +2579,10 @@ QPDFObjectHandle::assertPageObject() @@ -2564,28 +2579,10 @@ QPDFObjectHandle::assertPageObject()
2564 bool 2579 bool
2565 QPDFObjectHandle::dereference() 2580 QPDFObjectHandle::dereference()
2566 { 2581 {
2567 - if (!this->initialized) { 2582 + if (!isInitialized()) {
2568 return false; 2583 return false;
2569 } 2584 }
2570 - if (this->obj.get() && getObjectID() &&  
2571 - QPDF::Resolver::objectChanged(this->qpdf, getObjGen(), this->obj)) {  
2572 - this->obj = nullptr;  
2573 - }  
2574 - if (this->obj == nullptr) {  
2575 - std::shared_ptr<QPDFObject> obj =  
2576 - QPDF::Resolver::resolve(this->qpdf, getObjGen());  
2577 - if (obj == nullptr) {  
2578 - // QPDF::resolve never returns an uninitialized object, but  
2579 - // check just in case.  
2580 - this->obj = QPDF_Null::create();  
2581 - } else if (dynamic_cast<QPDF_Reserved*>(obj.get())) {  
2582 - // Do not resolve  
2583 - this->reserved = true;  
2584 - } else {  
2585 - this->reserved = false;  
2586 - this->obj = obj;  
2587 - }  
2588 - } 2585 + this->obj->resolve();
2589 return true; 2586 return true;
2590 } 2587 }
2591 2588
libqpdf/QPDFParser.cc
1 #include <qpdf/QPDFParser.hh> 1 #include <qpdf/QPDFParser.hh>
2 2
3 #include <qpdf/QPDF.hh> 3 #include <qpdf/QPDF.hh>
  4 +#include <qpdf/QPDFObjGen.hh>
4 #include <qpdf/QPDFObjectHandle.hh> 5 #include <qpdf/QPDFObjectHandle.hh>
5 -#include <qpdf/QPDF_Array.hh>  
6 #include <qpdf/QTC.hh> 6 #include <qpdf/QTC.hh>
7 #include <qpdf/QUtil.hh> 7 #include <qpdf/QUtil.hh>
8 8
@@ -55,6 +55,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -55,6 +55,7 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
55 55
56 while (!done) { 56 while (!done) {
57 bool bad = false; 57 bool bad = false;
  58 + bool indirect_ref = false;
58 is_null = false; 59 is_null = false;
59 auto& frame = stack.back(); 60 auto& frame = stack.back();
60 auto& olist = frame.olist; 61 auto& olist = frame.olist;
@@ -185,12 +186,16 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -185,12 +186,16 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
185 "QPDFObjectHandle::parse called without context" 186 "QPDFObjectHandle::parse called without context"
186 " on an object with indirect references"); 187 " on an object with indirect references");
187 } 188 }
188 - // Try to resolve indirect objects  
189 - object = QPDFObjectHandle::newIndirect(  
190 - context,  
191 - QPDFObjGen(  
192 - olist.at(size - 2).getIntValueAsInt(),  
193 - olist.back().getIntValueAsInt())); 189 + auto ref_og = QPDFObjGen(
  190 + olist.at(size - 2).getIntValueAsInt(),
  191 + olist.back().getIntValueAsInt());
  192 + if (ref_og.isIndirect()) {
  193 + object = context->getObject(ref_og);
  194 + indirect_ref = true;
  195 + } else {
  196 + QTC::TC("qpdf", "QPDFParser indirect with 0 objid");
  197 + is_null = true;
  198 + }
194 olist.pop_back(); 199 olist.pop_back();
195 olist.pop_back(); 200 olist.pop_back();
196 } else if ((value == "endobj") && (state == st_top)) { 201 } else if ((value == "endobj") && (state == st_top)) {
@@ -274,8 +279,8 @@ QPDFParser::parse(bool&amp; empty, bool content_stream) @@ -274,8 +279,8 @@ QPDFParser::parse(bool&amp; empty, bool content_stream)
274 279
275 case st_dictionary: 280 case st_dictionary:
276 case st_array: 281 case st_array:
277 - if (!object.isDirectNull()) {  
278 - // No need to set description for direct nulls- they will 282 + if (!indirect_ref && !object.isDirectNull()) {
  283 + // No need to set description for direct nulls - they will
279 // become implicit. 284 // become implicit.
280 setDescriptionFromInput(object, input->getLastOffset()); 285 setDescriptionFromInput(object, input->getLastOffset());
281 object.setParsedOffset(input->getLastOffset()); 286 object.setParsedOffset(input->getLastOffset());
libqpdf/QPDFValue.cc 0 โ†’ 100644
  1 +#include <qpdf/QPDFValue.hh>
  2 +
  3 +#include <qpdf/QPDFObject.hh>
  4 +
  5 +std::shared_ptr<QPDFObject>
  6 +QPDFValue::do_create(QPDFValue* object)
  7 +{
  8 + std::shared_ptr<QPDFObject> obj(new QPDFObject());
  9 + obj->value = std::shared_ptr<QPDFValue>(object);
  10 + return obj;
  11 +}
libqpdf/QPDF_Array.cc
@@ -4,12 +4,14 @@ @@ -4,12 +4,14 @@
4 #include <qpdf/QUtil.hh> 4 #include <qpdf/QUtil.hh>
5 #include <stdexcept> 5 #include <stdexcept>
6 6
7 -QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) 7 +QPDF_Array::QPDF_Array(std::vector<QPDFObjectHandle> const& v) :
  8 + QPDFValue(::ot_array, "array")
8 { 9 {
9 setFromVector(v); 10 setFromVector(v);
10 } 11 }
11 12
12 QPDF_Array::QPDF_Array(SparseOHArray const& items) : 13 QPDF_Array::QPDF_Array(SparseOHArray const& items) :
  14 + QPDFValue(::ot_array, "array"),
13 elements(items) 15 elements(items)
14 { 16 {
15 } 17 }
@@ -62,18 +64,6 @@ QPDF_Array::getJSON(int json_version) @@ -62,18 +64,6 @@ QPDF_Array::getJSON(int json_version)
62 return j; 64 return j;
63 } 65 }
64 66
65 -QPDFObject::object_type_e  
66 -QPDF_Array::getTypeCode() const  
67 -{  
68 - return QPDFObject::ot_array;  
69 -}  
70 -  
71 -char const*  
72 -QPDF_Array::getTypeName() const  
73 -{  
74 - return "array";  
75 -}  
76 -  
77 int 67 int
78 QPDF_Array::getNItems() const 68 QPDF_Array::getNItems() const
79 { 69 {
libqpdf/QPDF_Bool.cc
1 #include <qpdf/QPDF_Bool.hh> 1 #include <qpdf/QPDF_Bool.hh>
2 2
3 QPDF_Bool::QPDF_Bool(bool val) : 3 QPDF_Bool::QPDF_Bool(bool val) :
  4 + QPDFValue(::ot_boolean, "boolean"),
4 val(val) 5 val(val)
5 { 6 {
6 } 7 }
@@ -29,18 +30,6 @@ QPDF_Bool::getJSON(int json_version) @@ -29,18 +30,6 @@ QPDF_Bool::getJSON(int json_version)
29 return JSON::makeBool(this->val); 30 return JSON::makeBool(this->val);
30 } 31 }
31 32
32 -QPDFObject::object_type_e  
33 -QPDF_Bool::getTypeCode() const  
34 -{  
35 - return QPDFObject::ot_boolean;  
36 -}  
37 -  
38 -char const*  
39 -QPDF_Bool::getTypeName() const  
40 -{  
41 - return "boolean";  
42 -}  
43 -  
44 bool 33 bool
45 QPDF_Bool::getVal() const 34 QPDF_Bool::getVal() const
46 { 35 {
libqpdf/QPDF_Dictionary.cc
1 #include <qpdf/QPDF_Dictionary.hh> 1 #include <qpdf/QPDF_Dictionary.hh>
2 2
3 #include <qpdf/QPDF_Name.hh> 3 #include <qpdf/QPDF_Name.hh>
4 -#include <qpdf/QPDF_Null.hh>  
5 4
6 QPDF_Dictionary::QPDF_Dictionary( 5 QPDF_Dictionary::QPDF_Dictionary(
7 std::map<std::string, QPDFObjectHandle> const& items) : 6 std::map<std::string, QPDFObjectHandle> const& items) :
  7 + QPDFValue(::ot_dictionary, "dictionary"),
8 items(items) 8 items(items)
9 { 9 {
10 } 10 }
@@ -58,18 +58,6 @@ QPDF_Dictionary::getJSON(int json_version) @@ -58,18 +58,6 @@ QPDF_Dictionary::getJSON(int json_version)
58 return j; 58 return j;
59 } 59 }
60 60
61 -QPDFObject::object_type_e  
62 -QPDF_Dictionary::getTypeCode() const  
63 -{  
64 - return QPDFObject::ot_dictionary;  
65 -}  
66 -  
67 -char const*  
68 -QPDF_Dictionary::getTypeName() const  
69 -{  
70 - return "dictionary";  
71 -}  
72 -  
73 bool 61 bool
74 QPDF_Dictionary::hasKey(std::string const& key) 62 QPDF_Dictionary::hasKey(std::string const& key)
75 { 63 {
libqpdf/QPDF_InlineImage.cc
1 #include <qpdf/QPDF_InlineImage.hh> 1 #include <qpdf/QPDF_InlineImage.hh>
2 2
3 QPDF_InlineImage::QPDF_InlineImage(std::string const& val) : 3 QPDF_InlineImage::QPDF_InlineImage(std::string const& val) :
  4 + QPDFValue(::ot_inlineimage, "inline-image"),
4 val(val) 5 val(val)
5 { 6 {
6 } 7 }
@@ -29,18 +30,6 @@ QPDF_InlineImage::getJSON(int json_version) @@ -29,18 +30,6 @@ QPDF_InlineImage::getJSON(int json_version)
29 return JSON::makeNull(); 30 return JSON::makeNull();
30 } 31 }
31 32
32 -QPDFObject::object_type_e  
33 -QPDF_InlineImage::getTypeCode() const  
34 -{  
35 - return QPDFObject::ot_inlineimage;  
36 -}  
37 -  
38 -char const*  
39 -QPDF_InlineImage::getTypeName() const  
40 -{  
41 - return "inline-image";  
42 -}  
43 -  
44 std::string 33 std::string
45 QPDF_InlineImage::getVal() const 34 QPDF_InlineImage::getVal() const
46 { 35 {
libqpdf/QPDF_Integer.cc
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 #include <qpdf/QUtil.hh> 3 #include <qpdf/QUtil.hh>
4 4
5 QPDF_Integer::QPDF_Integer(long long val) : 5 QPDF_Integer::QPDF_Integer(long long val) :
  6 + QPDFValue(::ot_integer, "integer"),
6 val(val) 7 val(val)
7 { 8 {
8 } 9 }
@@ -31,18 +32,6 @@ QPDF_Integer::getJSON(int json_version) @@ -31,18 +32,6 @@ QPDF_Integer::getJSON(int json_version)
31 return JSON::makeInt(this->val); 32 return JSON::makeInt(this->val);
32 } 33 }
33 34
34 -QPDFObject::object_type_e  
35 -QPDF_Integer::getTypeCode() const  
36 -{  
37 - return QPDFObject::ot_integer;  
38 -}  
39 -  
40 -char const*  
41 -QPDF_Integer::getTypeName() const  
42 -{  
43 - return "integer";  
44 -}  
45 -  
46 long long 35 long long
47 QPDF_Integer::getVal() const 36 QPDF_Integer::getVal() const
48 { 37 {
libqpdf/QPDF_Name.cc
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 #include <string.h> 5 #include <string.h>
6 6
7 QPDF_Name::QPDF_Name(std::string const& name) : 7 QPDF_Name::QPDF_Name(std::string const& name) :
  8 + QPDFValue(::ot_name, "name"),
8 name(name) 9 name(name)
9 { 10 {
10 } 11 }
@@ -61,18 +62,6 @@ QPDF_Name::getJSON(int json_version) @@ -61,18 +62,6 @@ QPDF_Name::getJSON(int json_version)
61 } 62 }
62 } 63 }
63 64
64 -QPDFObject::object_type_e  
65 -QPDF_Name::getTypeCode() const  
66 -{  
67 - return QPDFObject::ot_name;  
68 -}  
69 -  
70 -char const*  
71 -QPDF_Name::getTypeName() const  
72 -{  
73 - return "name";  
74 -}  
75 -  
76 std::string 65 std::string
77 QPDF_Name::getName() const 66 QPDF_Name::getName() const
78 { 67 {
libqpdf/QPDF_Null.cc
1 #include <qpdf/QPDF_Null.hh> 1 #include <qpdf/QPDF_Null.hh>
2 2
  3 +QPDF_Null::QPDF_Null() :
  4 + QPDFValue(::ot_null, "null")
  5 +{
  6 +}
  7 +
3 std::shared_ptr<QPDFObject> 8 std::shared_ptr<QPDFObject>
4 QPDF_Null::create() 9 QPDF_Null::create()
5 { 10 {
@@ -23,15 +28,3 @@ QPDF_Null::getJSON(int json_version) @@ -23,15 +28,3 @@ QPDF_Null::getJSON(int json_version)
23 { 28 {
24 return JSON::makeNull(); 29 return JSON::makeNull();
25 } 30 }
26 -  
27 -QPDFObject::object_type_e  
28 -QPDF_Null::getTypeCode() const  
29 -{  
30 - return QPDFObject::ot_null;  
31 -}  
32 -  
33 -char const*  
34 -QPDF_Null::getTypeName() const  
35 -{  
36 - return "null";  
37 -}  
libqpdf/QPDF_Operator.cc
1 #include <qpdf/QPDF_Operator.hh> 1 #include <qpdf/QPDF_Operator.hh>
2 2
3 QPDF_Operator::QPDF_Operator(std::string const& val) : 3 QPDF_Operator::QPDF_Operator(std::string const& val) :
  4 + QPDFValue(::ot_operator, "operator"),
4 val(val) 5 val(val)
5 { 6 {
6 } 7 }
@@ -20,7 +21,7 @@ QPDF_Operator::shallowCopy() @@ -20,7 +21,7 @@ QPDF_Operator::shallowCopy()
20 std::string 21 std::string
21 QPDF_Operator::unparse() 22 QPDF_Operator::unparse()
22 { 23 {
23 - return this->val; 24 + return val;
24 } 25 }
25 26
26 JSON 27 JSON
@@ -29,18 +30,6 @@ QPDF_Operator::getJSON(int json_version) @@ -29,18 +30,6 @@ QPDF_Operator::getJSON(int json_version)
29 return JSON::makeNull(); 30 return JSON::makeNull();
30 } 31 }
31 32
32 -QPDFObject::object_type_e  
33 -QPDF_Operator::getTypeCode() const  
34 -{  
35 - return QPDFObject::ot_operator;  
36 -}  
37 -  
38 -char const*  
39 -QPDF_Operator::getTypeName() const  
40 -{  
41 - return "operator";  
42 -}  
43 -  
44 std::string 33 std::string
45 QPDF_Operator::getVal() const 34 QPDF_Operator::getVal() const
46 { 35 {
libqpdf/QPDF_Real.cc
@@ -3,12 +3,14 @@ @@ -3,12 +3,14 @@
3 #include <qpdf/QUtil.hh> 3 #include <qpdf/QUtil.hh>
4 4
5 QPDF_Real::QPDF_Real(std::string const& val) : 5 QPDF_Real::QPDF_Real(std::string const& val) :
  6 + QPDFValue(::ot_real, "real"),
6 val(val) 7 val(val)
7 { 8 {
8 } 9 }
9 10
10 QPDF_Real::QPDF_Real( 11 QPDF_Real::QPDF_Real(
11 double value, int decimal_places, bool trim_trailing_zeroes) : 12 double value, int decimal_places, bool trim_trailing_zeroes) :
  13 + QPDFValue(::ot_real, "real"),
12 val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes)) 14 val(QUtil::double_to_string(value, decimal_places, trim_trailing_zeroes))
13 { 15 {
14 } 16 }
@@ -60,18 +62,6 @@ QPDF_Real::getJSON(int json_version) @@ -60,18 +62,6 @@ QPDF_Real::getJSON(int json_version)
60 return JSON::makeNumber(result); 62 return JSON::makeNumber(result);
61 } 63 }
62 64
63 -QPDFObject::object_type_e  
64 -QPDF_Real::getTypeCode() const  
65 -{  
66 - return QPDFObject::ot_real;  
67 -}  
68 -  
69 -char const*  
70 -QPDF_Real::getTypeName() const  
71 -{  
72 - return "real";  
73 -}  
74 -  
75 std::string 65 std::string
76 QPDF_Real::getVal() 66 QPDF_Real::getVal()
77 { 67 {
libqpdf/QPDF_Reserved.cc
@@ -2,6 +2,11 @@ @@ -2,6 +2,11 @@
2 2
3 #include <stdexcept> 3 #include <stdexcept>
4 4
  5 +QPDF_Reserved::QPDF_Reserved() :
  6 + QPDFValue(::ot_reserved, "reserved")
  7 +{
  8 +}
  9 +
5 std::shared_ptr<QPDFObject> 10 std::shared_ptr<QPDFObject>
6 QPDF_Reserved::create() 11 QPDF_Reserved::create()
7 { 12 {
@@ -17,25 +22,15 @@ QPDF_Reserved::shallowCopy() @@ -17,25 +22,15 @@ QPDF_Reserved::shallowCopy()
17 std::string 22 std::string
18 QPDF_Reserved::unparse() 23 QPDF_Reserved::unparse()
19 { 24 {
20 - throw std::logic_error("attempt to unparse QPDF_Reserved"); 25 + throw std::logic_error(
  26 + "QPDFObjectHandle: attempting to unparse a reserved object");
21 return ""; 27 return "";
22 } 28 }
23 29
24 JSON 30 JSON
25 QPDF_Reserved::getJSON(int json_version) 31 QPDF_Reserved::getJSON(int json_version)
26 { 32 {
27 - throw std::logic_error("attempt to generate JSON from QPDF_Reserved"); 33 + throw std::logic_error(
  34 + "QPDFObjectHandle: attempting to unparse a reserved object");
28 return JSON::makeNull(); 35 return JSON::makeNull();
29 } 36 }
30 -  
31 -QPDFObject::object_type_e  
32 -QPDF_Reserved::getTypeCode() const  
33 -{  
34 - return QPDFObject::ot_reserved;  
35 -}  
36 -  
37 -char const*  
38 -QPDF_Reserved::getTypeName() const  
39 -{  
40 - return "reserved";  
41 -}  
libqpdf/QPDF_Stream.cc
@@ -114,6 +114,7 @@ QPDF_Stream::QPDF_Stream( @@ -114,6 +114,7 @@ QPDF_Stream::QPDF_Stream(
114 QPDFObjectHandle stream_dict, 114 QPDFObjectHandle stream_dict,
115 qpdf_offset_t offset, 115 qpdf_offset_t offset,
116 size_t length) : 116 size_t length) :
  117 + QPDFValue(::ot_stream, "stream"),
117 qpdf(qpdf), 118 qpdf(qpdf),
118 og(og), 119 og(og),
119 filter_on_write(true), 120 filter_on_write(true),
@@ -291,22 +292,10 @@ QPDF_Stream::getStreamJSON( @@ -291,22 +292,10 @@ QPDF_Stream::getStreamJSON(
291 return result; 292 return result;
292 } 293 }
293 294
294 -QPDFObject::object_type_e  
295 -QPDF_Stream::getTypeCode() const  
296 -{  
297 - return QPDFObject::ot_stream;  
298 -}  
299 -  
300 -char const*  
301 -QPDF_Stream::getTypeName() const  
302 -{  
303 - return "stream";  
304 -}  
305 -  
306 void 295 void
307 QPDF_Stream::setDescription(QPDF* qpdf, std::string const& description) 296 QPDF_Stream::setDescription(QPDF* qpdf, std::string const& description)
308 { 297 {
309 - this->QPDFObject::setDescription(qpdf, description); 298 + this->QPDFValue::setDescription(qpdf, description);
310 setDictDescription(); 299 setDictDescription();
311 } 300 }
312 301
libqpdf/QPDF_String.cc
@@ -21,6 +21,7 @@ is_iso_latin1_printable(char ch) @@ -21,6 +21,7 @@ is_iso_latin1_printable(char ch)
21 } 21 }
22 22
23 QPDF_String::QPDF_String(std::string const& val) : 23 QPDF_String::QPDF_String(std::string const& val) :
  24 + QPDFValue(::ot_string, "string"),
24 val(val) 25 val(val)
25 { 26 {
26 } 27 }
@@ -84,18 +85,6 @@ QPDF_String::getJSON(int json_version) @@ -84,18 +85,6 @@ QPDF_String::getJSON(int json_version)
84 return JSON::makeString(result); 85 return JSON::makeString(result);
85 } 86 }
86 87
87 -QPDFObject::object_type_e  
88 -QPDF_String::getTypeCode() const  
89 -{  
90 - return QPDFObject::ot_string;  
91 -}  
92 -  
93 -char const*  
94 -QPDF_String::getTypeName() const  
95 -{  
96 - return "string";  
97 -}  
98 -  
99 bool 88 bool
100 QPDF_String::useHexString() const 89 QPDF_String::useHexString() const
101 { 90 {
libqpdf/QPDF_Unresolved.cc 0 โ†’ 100644
  1 +#include <qpdf/QPDF_Unresolved.hh>
  2 +
  3 +#include <stdexcept>
  4 +
  5 +QPDF_Unresolved::QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og) :
  6 + QPDFValue(::ot_unresolved, "unresolved", qpdf, og)
  7 +{
  8 +}
  9 +
  10 +std::shared_ptr<QPDFObject>
  11 +QPDF_Unresolved::create(QPDF* qpdf, QPDFObjGen const& og)
  12 +{
  13 + return do_create(new QPDF_Unresolved(qpdf, og));
  14 +}
  15 +
  16 +std::shared_ptr<QPDFObject>
  17 +QPDF_Unresolved::shallowCopy()
  18 +{
  19 + throw std::logic_error(
  20 + "attempted to shallow copy unresolved QPDFObjectHandle");
  21 + return create(qpdf, og);
  22 +}
  23 +
  24 +std::string
  25 +QPDF_Unresolved::unparse()
  26 +{
  27 + throw std::logic_error(
  28 + "attempted to unparse an unresolved QPDFObjectHandle");
  29 + return "";
  30 +}
  31 +
  32 +JSON
  33 +QPDF_Unresolved::getJSON(int json_version)
  34 +{
  35 + return JSON::makeNull();
  36 +}
libqpdf/QPDF_linearization.cc
@@ -137,8 +137,7 @@ QPDF::isLinearized() @@ -137,8 +137,7 @@ QPDF::isLinearized()
137 return false; 137 return false;
138 } 138 }
139 139
140 - QPDFObjectHandle candidate = QPDFObjectHandle::Factory::newIndirect(  
141 - this, QPDFObjGen(lindict_obj, 0)); 140 + auto candidate = getObjectByID(lindict_obj, 0);
142 if (!candidate.isDictionary()) { 141 if (!candidate.isDictionary()) {
143 return false; 142 return false;
144 } 143 }
libqpdf/qpdf/QPDF_Array.hh
1 #ifndef QPDF_ARRAY_HH 1 #ifndef QPDF_ARRAY_HH
2 #define QPDF_ARRAY_HH 2 #define QPDF_ARRAY_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 #include <qpdf/SparseOHArray.hh> 6 #include <qpdf/SparseOHArray.hh>
7 #include <list> 7 #include <list>
8 #include <vector> 8 #include <vector>
9 9
10 -class QPDF_Array: public QPDFObject 10 +class QPDF_Array: public QPDFValue
11 { 11 {
12 public: 12 public:
13 virtual ~QPDF_Array() = default; 13 virtual ~QPDF_Array() = default;
@@ -17,8 +17,6 @@ class QPDF_Array: public QPDFObject @@ -17,8 +17,6 @@ class QPDF_Array: public QPDFObject
17 virtual std::shared_ptr<QPDFObject> shallowCopy(); 17 virtual std::shared_ptr<QPDFObject> shallowCopy();
18 virtual std::string unparse(); 18 virtual std::string unparse();
19 virtual JSON getJSON(int json_version); 19 virtual JSON getJSON(int json_version);
20 - virtual QPDFObject::object_type_e getTypeCode() const;  
21 - virtual char const* getTypeName() const;  
22 20
23 int getNItems() const; 21 int getNItems() const;
24 QPDFObjectHandle getItem(int n) const; 22 QPDFObjectHandle getItem(int n) const;
libqpdf/qpdf/QPDF_Bool.hh
1 #ifndef QPDF_BOOL_HH 1 #ifndef QPDF_BOOL_HH
2 #define QPDF_BOOL_HH 2 #define QPDF_BOOL_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Bool: public QPDFObject 6 +class QPDF_Bool: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Bool() = default; 9 virtual ~QPDF_Bool() = default;
@@ -11,8 +11,6 @@ class QPDF_Bool: public QPDFObject @@ -11,8 +11,6 @@ class QPDF_Bool: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 bool getVal() const; 14 bool getVal() const;
17 15
18 private: 16 private:
libqpdf/qpdf/QPDF_Dictionary.hh
1 #ifndef QPDF_DICTIONARY_HH 1 #ifndef QPDF_DICTIONARY_HH
2 #define QPDF_DICTIONARY_HH 2 #define QPDF_DICTIONARY_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 #include <map> 6 #include <map>
7 #include <set> 7 #include <set>
8 8
9 #include <qpdf/QPDFObjectHandle.hh> 9 #include <qpdf/QPDFObjectHandle.hh>
10 10
11 -class QPDF_Dictionary: public QPDFObject 11 +class QPDF_Dictionary: public QPDFValue
12 { 12 {
13 public: 13 public:
14 virtual ~QPDF_Dictionary() = default; 14 virtual ~QPDF_Dictionary() = default;
@@ -17,8 +17,6 @@ class QPDF_Dictionary: public QPDFObject @@ -17,8 +17,6 @@ class QPDF_Dictionary: public QPDFObject
17 virtual std::shared_ptr<QPDFObject> shallowCopy(); 17 virtual std::shared_ptr<QPDFObject> shallowCopy();
18 virtual std::string unparse(); 18 virtual std::string unparse();
19 virtual JSON getJSON(int json_version); 19 virtual JSON getJSON(int json_version);
20 - virtual QPDFObject::object_type_e getTypeCode() const;  
21 - virtual char const* getTypeName() const;  
22 20
23 // hasKey() and getKeys() treat keys with null values as if they 21 // hasKey() and getKeys() treat keys with null values as if they
24 // aren't there. getKey() returns null for the value of a 22 // aren't there. getKey() returns null for the value of a
libqpdf/qpdf/QPDF_InlineImage.hh
1 #ifndef QPDF_INLINEIMAGE_HH 1 #ifndef QPDF_INLINEIMAGE_HH
2 #define QPDF_INLINEIMAGE_HH 2 #define QPDF_INLINEIMAGE_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_InlineImage: public QPDFObject 6 +class QPDF_InlineImage: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_InlineImage() = default; 9 virtual ~QPDF_InlineImage() = default;
@@ -11,8 +11,6 @@ class QPDF_InlineImage: public QPDFObject @@ -11,8 +11,6 @@ class QPDF_InlineImage: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 std::string getVal() const; 14 std::string getVal() const;
17 15
18 private: 16 private:
libqpdf/qpdf/QPDF_Integer.hh
1 #ifndef QPDF_INTEGER_HH 1 #ifndef QPDF_INTEGER_HH
2 #define QPDF_INTEGER_HH 2 #define QPDF_INTEGER_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Integer: public QPDFObject 6 +class QPDF_Integer: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Integer() = default; 9 virtual ~QPDF_Integer() = default;
@@ -11,8 +11,6 @@ class QPDF_Integer: public QPDFObject @@ -11,8 +11,6 @@ class QPDF_Integer: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 long long getVal() const; 14 long long getVal() const;
17 15
18 private: 16 private:
libqpdf/qpdf/QPDF_Name.hh
1 #ifndef QPDF_NAME_HH 1 #ifndef QPDF_NAME_HH
2 #define QPDF_NAME_HH 2 #define QPDF_NAME_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Name: public QPDFObject 6 +class QPDF_Name: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Name() = default; 9 virtual ~QPDF_Name() = default;
@@ -11,8 +11,6 @@ class QPDF_Name: public QPDFObject @@ -11,8 +11,6 @@ class QPDF_Name: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 std::string getName() const; 14 std::string getName() const;
17 15
18 // Put # into strings with characters unsuitable for name token 16 // Put # into strings with characters unsuitable for name token
libqpdf/qpdf/QPDF_Null.hh
1 #ifndef QPDF_NULL_HH 1 #ifndef QPDF_NULL_HH
2 #define QPDF_NULL_HH 2 #define QPDF_NULL_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Null: public QPDFObject 6 +class QPDF_Null: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Null() = default; 9 virtual ~QPDF_Null() = default;
@@ -11,11 +11,9 @@ class QPDF_Null: public QPDFObject @@ -11,11 +11,9 @@ class QPDF_Null: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 14
17 private: 15 private:
18 - QPDF_Null() = default; 16 + QPDF_Null();
19 }; 17 };
20 18
21 #endif // QPDF_NULL_HH 19 #endif // QPDF_NULL_HH
libqpdf/qpdf/QPDF_Operator.hh
1 #ifndef QPDF_OPERATOR_HH 1 #ifndef QPDF_OPERATOR_HH
2 #define QPDF_OPERATOR_HH 2 #define QPDF_OPERATOR_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Operator: public QPDFObject 6 +class QPDF_Operator: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Operator() = default; 9 virtual ~QPDF_Operator() = default;
@@ -11,8 +11,6 @@ class QPDF_Operator: public QPDFObject @@ -11,8 +11,6 @@ class QPDF_Operator: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 std::string getVal() const; 14 std::string getVal() const;
17 15
18 private: 16 private:
libqpdf/qpdf/QPDF_Real.hh
1 #ifndef QPDF_REAL_HH 1 #ifndef QPDF_REAL_HH
2 #define QPDF_REAL_HH 2 #define QPDF_REAL_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Real: public QPDFObject 6 +class QPDF_Real: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Real() = default; 9 virtual ~QPDF_Real() = default;
@@ -13,8 +13,6 @@ class QPDF_Real: public QPDFObject @@ -13,8 +13,6 @@ class QPDF_Real: public QPDFObject
13 virtual std::shared_ptr<QPDFObject> shallowCopy(); 13 virtual std::shared_ptr<QPDFObject> shallowCopy();
14 virtual std::string unparse(); 14 virtual std::string unparse();
15 virtual JSON getJSON(int json_version); 15 virtual JSON getJSON(int json_version);
16 - virtual QPDFObject::object_type_e getTypeCode() const;  
17 - virtual char const* getTypeName() const;  
18 std::string getVal(); 16 std::string getVal();
19 17
20 private: 18 private:
libqpdf/qpdf/QPDF_Reserved.hh
1 #ifndef QPDF_RESERVED_HH 1 #ifndef QPDF_RESERVED_HH
2 #define QPDF_RESERVED_HH 2 #define QPDF_RESERVED_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 -class QPDF_Reserved: public QPDFObject 6 +class QPDF_Reserved: public QPDFValue
7 { 7 {
8 public: 8 public:
9 virtual ~QPDF_Reserved() = default; 9 virtual ~QPDF_Reserved() = default;
@@ -11,11 +11,9 @@ class QPDF_Reserved: public QPDFObject @@ -11,11 +11,9 @@ class QPDF_Reserved: public QPDFObject
11 virtual std::shared_ptr<QPDFObject> shallowCopy(); 11 virtual std::shared_ptr<QPDFObject> shallowCopy();
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 virtual JSON getJSON(int json_version); 13 virtual JSON getJSON(int json_version);
14 - virtual QPDFObject::object_type_e getTypeCode() const;  
15 - virtual char const* getTypeName() const;  
16 14
17 private: 15 private:
18 - QPDF_Reserved() = default; 16 + QPDF_Reserved();
19 }; 17 };
20 18
21 #endif // QPDF_RESERVED_HH 19 #endif // QPDF_RESERVED_HH
libqpdf/qpdf/QPDF_Stream.hh
@@ -3,9 +3,9 @@ @@ -3,9 +3,9 @@
3 3
4 #include <qpdf/Types.h> 4 #include <qpdf/Types.h>
5 5
6 -#include <qpdf/QPDFObject.hh>  
7 #include <qpdf/QPDFObjectHandle.hh> 6 #include <qpdf/QPDFObjectHandle.hh>
8 #include <qpdf/QPDFStreamFilter.hh> 7 #include <qpdf/QPDFStreamFilter.hh>
  8 +#include <qpdf/QPDFValue.hh>
9 9
10 #include <functional> 10 #include <functional>
11 #include <memory> 11 #include <memory>
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 class Pipeline; 13 class Pipeline;
14 class QPDF; 14 class QPDF;
15 15
16 -class QPDF_Stream: public QPDFObject 16 +class QPDF_Stream: public QPDFValue
17 { 17 {
18 public: 18 public:
19 virtual ~QPDF_Stream() = default; 19 virtual ~QPDF_Stream() = default;
@@ -26,8 +26,6 @@ class QPDF_Stream: public QPDFObject @@ -26,8 +26,6 @@ class QPDF_Stream: public QPDFObject
26 virtual std::shared_ptr<QPDFObject> shallowCopy(); 26 virtual std::shared_ptr<QPDFObject> shallowCopy();
27 virtual std::string unparse(); 27 virtual std::string unparse();
28 virtual JSON getJSON(int json_version); 28 virtual JSON getJSON(int json_version);
29 - virtual QPDFObject::object_type_e getTypeCode() const;  
30 - virtual char const* getTypeName() const;  
31 virtual void setDescription(QPDF*, std::string const&); 29 virtual void setDescription(QPDF*, std::string const&);
32 QPDFObjectHandle getDict() const; 30 QPDFObjectHandle getDict() const;
33 bool isDataModified() const; 31 bool isDataModified() const;
libqpdf/qpdf/QPDF_String.hh
1 #ifndef QPDF_STRING_HH 1 #ifndef QPDF_STRING_HH
2 #define QPDF_STRING_HH 2 #define QPDF_STRING_HH
3 3
4 -#include <qpdf/QPDFObject.hh> 4 +#include <qpdf/QPDFValue.hh>
5 5
6 // QPDF_Strings may included embedded null characters. 6 // QPDF_Strings may included embedded null characters.
7 7
8 -class QPDF_String: public QPDFObject 8 +class QPDF_String: public QPDFValue
9 { 9 {
10 friend class QPDFWriter; 10 friend class QPDFWriter;
11 11
@@ -16,8 +16,6 @@ class QPDF_String: public QPDFObject @@ -16,8 +16,6 @@ class QPDF_String: public QPDFObject
16 create_utf16(std::string const& utf8_val); 16 create_utf16(std::string const& utf8_val);
17 virtual std::shared_ptr<QPDFObject> shallowCopy(); 17 virtual std::shared_ptr<QPDFObject> shallowCopy();
18 virtual std::string unparse(); 18 virtual std::string unparse();
19 - virtual QPDFObject::object_type_e getTypeCode() const;  
20 - virtual char const* getTypeName() const;  
21 std::string unparse(bool force_binary); 19 std::string unparse(bool force_binary);
22 virtual JSON getJSON(int json_version); 20 virtual JSON getJSON(int json_version);
23 std::string getVal() const; 21 std::string getVal() const;
libqpdf/qpdf/QPDF_Unresolved.hh 0 โ†’ 100644
  1 +#ifndef QPDF_UNRESOLVED_HH
  2 +#define QPDF_UNRESOLVED_HH
  3 +
  4 +#include <qpdf/QPDFValue.hh>
  5 +
  6 +class QPDF_Unresolved: public QPDFValue
  7 +{
  8 + public:
  9 + virtual ~QPDF_Unresolved() = default;
  10 + static std::shared_ptr<QPDFObject> create(QPDF* qpdf, QPDFObjGen const& og);
  11 + virtual std::shared_ptr<QPDFObject> shallowCopy();
  12 + virtual std::string unparse();
  13 + virtual JSON getJSON(int json_version);
  14 +
  15 + private:
  16 + QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og);
  17 +};
  18 +
  19 +#endif // QPDF_UNRESOLVED_HH
qpdf/qpdf.testcov
@@ -254,7 +254,7 @@ QPDFWriter standard deterministic ID 1 @@ -254,7 +254,7 @@ QPDFWriter standard deterministic ID 1
254 QPDFWriter linearized deterministic ID 1 254 QPDFWriter linearized deterministic ID 1
255 QPDFWriter deterministic with no data 0 255 QPDFWriter deterministic with no data 0
256 qpdf-c called qpdf_set_deterministic_ID 0 256 qpdf-c called qpdf_set_deterministic_ID 0
257 -QPDFObjectHandle indirect with 0 objid 0 257 +QPDFParser indirect with 0 objid 0
258 QPDF object id 0 0 258 QPDF object id 0 0
259 QPDF recursion loop in resolve 0 259 QPDF recursion loop in resolve 0
260 QPDFParser treat word as string 0 260 QPDFParser treat word as string 0
qpdf/qtest/qpdf/issue-51.out
@@ -9,7 +9,6 @@ WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary @@ -9,7 +9,6 @@ WARNING: issue-51.pdf (object 2 0, offset 26): /Length key in stream dictionary
9 WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length 9 WARNING: issue-51.pdf (object 2 0, offset 71): attempting to recover stream length
10 WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty 10 WARNING: issue-51.pdf (object 2 0, offset 71): unable to recover stream data; treating stream as empty
11 WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj 11 WARNING: issue-51.pdf (object 2 0, offset 977): expected endobj
12 -WARNING: issue-51.pdf (object 2 0, offset 977): EOF after endobj  
13 WARNING: issue-51.pdf (object 3 0): object has offset 0 12 WARNING: issue-51.pdf (object 3 0): object has offset 0
14 WARNING: issue-51.pdf (object 4 0): object has offset 0 13 WARNING: issue-51.pdf (object 4 0): object has offset 0
15 WARNING: issue-51.pdf (object 5 0): object has offset 0 14 WARNING: issue-51.pdf (object 5 0): object has offset 0
qpdf/qtest/type-checks.test
@@ -14,7 +14,7 @@ cleanup(); @@ -14,7 +14,7 @@ cleanup();
14 14
15 my $td = new TestDriver('type-checks'); 15 my $td = new TestDriver('type-checks');
16 16
17 -my $n_tests = 5; 17 +my $n_tests = 6;
18 18
19 # Whenever object-types.pdf is edited, object-types-os.pdf should be 19 # Whenever object-types.pdf is edited, object-types-os.pdf should be
20 # regenerated. 20 # regenerated.
@@ -43,6 +43,10 @@ $td-&gt;runtest(&quot;compound type checks&quot;, @@ -43,6 +43,10 @@ $td-&gt;runtest(&quot;compound type checks&quot;,
43 {$td->COMMAND => "test_driver 82 object-types-os.pdf"}, 43 {$td->COMMAND => "test_driver 82 object-types-os.pdf"},
44 {$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0}, 44 {$td->STRING => "test 82 done\n", $td->EXIT_STATUS => 0},
45 $td->NORMALIZE_NEWLINES); 45 $td->NORMALIZE_NEWLINES);
  46 +$td->runtest("indirect objects belonging to destroyed QPDF",
  47 + {$td->COMMAND => "test_driver 92 -"},
  48 + {$td->STRING => "test 92 done\n", $td->EXIT_STATUS => 0},
  49 + $td->NORMALIZE_NEWLINES);
46 50
47 cleanup(); 51 cleanup();
48 $td->report($n_tests); 52 $td->report($n_tests);
qpdf/test_driver.cc
@@ -3258,6 +3258,20 @@ test_91(QPDF&amp; pdf, char const* arg2) @@ -3258,6 +3258,20 @@ test_91(QPDF&amp; pdf, char const* arg2)
3258 2, &p, qpdf_dl_none, qpdf_sj_inline, "", std::set<std::string>()); 3258 2, &p, qpdf_dl_none, qpdf_sj_inline, "", std::set<std::string>());
3259 } 3259 }
3260 3260
  3261 +static void
  3262 +test_92(QPDF& pdf, char const* arg2)
  3263 +{
  3264 + // Exercise indirect objects owned by destroyed QPDF object.
  3265 + QPDF* qpdf = new QPDF();
  3266 + qpdf->emptyPDF();
  3267 + auto root = qpdf->getRoot();
  3268 + assert(root.getOwningQPDF() != nullptr);
  3269 + assert(root.isIndirect());
  3270 + delete qpdf;
  3271 + assert(root.getOwningQPDF() == nullptr);
  3272 + assert(!root.isIndirect());
  3273 +}
  3274 +
3261 void 3275 void
3262 runtest(int n, char const* filename1, char const* arg2) 3276 runtest(int n, char const* filename1, char const* arg2)
3263 { 3277 {
@@ -3265,7 +3279,7 @@ runtest(int n, char const* filename1, char const* arg2) @@ -3265,7 +3279,7 @@ runtest(int n, char const* filename1, char const* arg2)
3265 // the test suite to see how the test is invoked to find the file 3279 // the test suite to see how the test is invoked to find the file
3266 // that the test is supposed to operate on. 3280 // that the test is supposed to operate on.
3267 3281
3268 - std::set<int> ignore_filename = {61, 81, 83, 84, 85, 86, 87}; 3282 + std::set<int> ignore_filename = {61, 81, 83, 84, 85, 86, 87, 92};
3269 3283
3270 if (n == 0) { 3284 if (n == 0) {
3271 // Throw in some random test cases that don't fit anywhere 3285 // Throw in some random test cases that don't fit anywhere
@@ -3362,7 +3376,8 @@ runtest(int n, char const* filename1, char const* arg2) @@ -3362,7 +3376,8 @@ runtest(int n, char const* filename1, char const* arg2)
3362 {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79}, 3376 {76, test_76}, {77, test_77}, {78, test_78}, {79, test_79},
3363 {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83}, 3377 {80, test_80}, {81, test_81}, {82, test_82}, {83, test_83},
3364 {84, test_84}, {85, test_85}, {86, test_86}, {87, test_87}, 3378 {84, test_84}, {85, test_85}, {86, test_86}, {87, test_87},
3365 - {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91}}; 3379 + {88, test_88}, {89, test_89}, {90, test_90}, {91, test_91},
  3380 + {92, test_92}};
3366 3381
3367 auto fn = test_functions.find(n); 3382 auto fn = test_functions.find(n);
3368 if (fn == test_functions.end()) { 3383 if (fn == test_functions.end()) {