Commit f4589458370dc9dd9ed8ade3e4c25d4262f65e52

Authored by m-holger
Committed by GitHub
2 parents e50ee3b6 4aa6ee8d

Merge pull request #1537 from m-holger/oh_int

Add new private-API class Integer
include/qpdf/ObjectHandle.hh
... ... @@ -27,7 +27,6 @@
27 27 #include <qpdf/JSON.hh>
28 28 #include <qpdf/QPDFExc.hh>
29 29 #include <qpdf/QPDFObjGen.hh>
30   -#include <qpdf/Types.h>
31 30  
32 31 #include <cstdint>
33 32 #include <memory>
... ... @@ -42,6 +41,7 @@ namespace qpdf
42 41 class Array;
43 42 class BaseDictionary;
44 43 class Dictionary;
  44 + class Integer;
45 45 class Stream;
46 46  
47 47 enum typed : std::uint8_t { strict = 0, any_flag = 1, optional = 2, any = 3, error = 4 };
... ... @@ -127,6 +127,7 @@ namespace qpdf
127 127 inline void assign(qpdf_object_type_e required, BaseHandle&& other);
128 128  
129 129 std::string description() const;
  130 + std::invalid_argument invalid_error(std::string const& method) const;
130 131 std::runtime_error type_error(char const* expected_type) const;
131 132 QPDFExc type_error(char const* expected_type, std::string const& message) const;
132 133 char const* type_name() const;
... ...
include/qpdf/QPDF.hh
... ... @@ -46,10 +46,15 @@
46 46 #include <qpdf/QPDFWriter.hh>
47 47 #include <qpdf/QPDFXRefEntry.hh>
48 48  
49   -namespace qpdf::is
  49 +namespace qpdf
50 50 {
51   - class OffsetBuffer;
52   -}
  51 + class Dictionary;
  52 +
  53 + namespace is
  54 + {
  55 + class OffsetBuffer;
  56 + }
  57 +} // namespace qpdf
53 58  
54 59 class QPDF_Stream;
55 60 class BitStream;
... ... @@ -1006,7 +1011,7 @@ class QPDF
1006 1011 void checkLinearizationInternal();
1007 1012 void dumpLinearizationDataInternal();
1008 1013 void linearizationWarning(std::string_view);
1009   - QPDFObjectHandle readHintStream(Pipeline&, qpdf_offset_t offset, size_t length);
  1014 + qpdf::Dictionary readHintStream(Pipeline&, qpdf_offset_t offset, size_t length);
1010 1015 void readHPageOffset(BitStream);
1011 1016 void readHSharedObject(BitStream);
1012 1017 void readHGeneric(BitStream, HGeneric&);
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -806,16 +806,36 @@ QPDFObjectHandle::getValueAsBool(bool&amp; value) const
806 806 return false;
807 807 }
808 808  
809   -// Integer accessors
  809 +// Integer methods
  810 +
  811 +Integer::Integer(long long value) :
  812 + BaseHandle(QPDFObject::create<QPDF_Integer>(value))
  813 +{
  814 +}
  815 +
  816 +QPDFObjectHandle
  817 +QPDFObjectHandle::newInteger(long long value)
  818 +{
  819 + return {QPDFObject::create<QPDF_Integer>(value)};
  820 +}
  821 +
  822 +int64_t
  823 +Integer::value() const
  824 +{
  825 + auto* i = as<QPDF_Integer>();
  826 + if (!i) {
  827 + throw invalid_error("Integer");
  828 + }
  829 + return i->val;
  830 +}
810 831  
811 832 long long
812 833 QPDFObjectHandle::getIntValue() const
813 834 {
814   - if (auto integer = as<QPDF_Integer>()) {
815   - return integer->val;
  835 + if (auto const integer = Integer(*this)) {
  836 + return integer;
816 837 } else {
817 838 typeWarning("integer", "returning 0");
818   - QTC::TC("qpdf", "QPDFObjectHandle integer returning 0");
819 839 return 0;
820 840 }
821 841 }
... ... @@ -823,8 +843,8 @@ QPDFObjectHandle::getIntValue() const
823 843 bool
824 844 QPDFObjectHandle::getValueAsInt(long long& value) const
825 845 {
826   - if (auto integer = as<QPDF_Integer>()) {
827   - value = integer->val;
  846 + if (auto const integer = Integer(*this)) {
  847 + value = integer;
828 848 return true;
829 849 }
830 850 return false;
... ... @@ -833,16 +853,18 @@ QPDFObjectHandle::getValueAsInt(long long&amp; value) const
833 853 int
834 854 QPDFObjectHandle::getIntValueAsInt() const
835 855 {
836   - long long v = getIntValue();
837   - if (v < INT_MIN) {
  856 + try {
  857 + return Integer(*this);
  858 + } catch (std::underflow_error&) {
838 859 warn("requested value of integer is too small; returning INT_MIN");
839 860 return INT_MIN;
840   - }
841   - if (v > INT_MAX) {
  861 + } catch (std::overflow_error&) {
842 862 warn("requested value of integer is too big; returning INT_MAX");
843 863 return INT_MAX;
  864 + } catch (std::invalid_argument&) {
  865 + typeWarning("integer", "returning 0");
  866 + return 0;
844 867 }
845   - return static_cast<int>(v);
846 868 }
847 869  
848 870 bool
... ... @@ -858,12 +880,14 @@ QPDFObjectHandle::getValueAsInt(int&amp; value) const
858 880 unsigned long long
859 881 QPDFObjectHandle::getUIntValue() const
860 882 {
861   - long long v = getIntValue();
862   - if (v < 0) {
  883 + try {
  884 + return Integer(*this);
  885 + } catch (std::underflow_error&) {
863 886 warn("unsigned value request for negative number; returning 0");
864 887 return 0;
865   - } else {
866   - return static_cast<unsigned long long>(v);
  888 + } catch (std::invalid_argument&) {
  889 + typeWarning("integer", "returning 0");
  890 + return 0;
867 891 }
868 892 }
869 893  
... ... @@ -880,16 +904,18 @@ QPDFObjectHandle::getValueAsUInt(unsigned long long&amp; value) const
880 904 unsigned int
881 905 QPDFObjectHandle::getUIntValueAsUInt() const
882 906 {
883   - long long v = getIntValue();
884   - if (v < 0) {
  907 + try {
  908 + return Integer(*this);
  909 + } catch (std::underflow_error&) {
885 910 warn("unsigned integer value request for negative number; returning 0");
886 911 return 0;
887   - }
888   - if (v > UINT_MAX) {
  912 + } catch (std::overflow_error&) {
889 913 warn("requested value of unsigned integer is too big; returning UINT_MAX");
890 914 return UINT_MAX;
  915 + } catch (std::invalid_argument&) {
  916 + typeWarning("integer", "returning 0");
  917 + return 0;
891 918 }
892   - return static_cast<unsigned int>(v);
893 919 }
894 920  
895 921 bool
... ... @@ -1329,7 +1355,7 @@ QPDFObjectHandle::rotatePage(int angle, bool relative)
1329 1355 }
1330 1356 new_angle = (new_angle + 360) % 360;
1331 1357 // Make this explicit even with new_angle == 0 since /Rotate can be inherited.
1332   - replaceKey("/Rotate", QPDFObjectHandle::newInteger(new_angle));
  1358 + replaceKey("/Rotate", Integer(new_angle));
1333 1359 }
1334 1360  
1335 1361 void
... ... @@ -1595,12 +1621,11 @@ QPDFObjectHandle::parseContentStream_data(
1595 1621 QTC::TC("qpdf", "QPDFObjectHandle EOF in inline image");
1596 1622 warn(
1597 1623 context,
1598   - QPDFExc(
1599   - qpdf_e_damaged_pdf,
1600   - description,
1601   - "stream data",
1602   - input.tell(),
1603   - "EOF found while reading inline image"));
  1624 + {qpdf_e_damaged_pdf,
  1625 + description,
  1626 + "stream data",
  1627 + input.tell(),
  1628 + "EOF found while reading inline image"});
1604 1629 } else {
1605 1630 QTC::TC("qpdf", "QPDFObjectHandle inline image token");
1606 1631 if (callbacks) {
... ... @@ -1658,12 +1683,6 @@ QPDFObjectHandle::newNull()
1658 1683 }
1659 1684  
1660 1685 QPDFObjectHandle
1661   -QPDFObjectHandle::newInteger(long long value)
1662   -{
1663   - return {QPDFObject::create<QPDF_Integer>(value)};
1664   -}
1665   -
1666   -QPDFObjectHandle
1667 1686 QPDFObjectHandle::newReal(std::string const& value)
1668 1687 {
1669 1688 return {QPDFObject::create<QPDF_Real>(value)};
... ... @@ -1932,6 +1951,11 @@ QPDFObjectHandle::assertInitialized() const
1932 1951 }
1933 1952 }
1934 1953  
  1954 +std::invalid_argument
  1955 +BaseHandle::invalid_error(std::string const& method) const
  1956 +{
  1957 + return std::invalid_argument(method + " operation attempted on invalid object");
  1958 +}
1935 1959 std::runtime_error
1936 1960 BaseHandle::type_error(char const* expected_type) const
1937 1961 {
... ... @@ -1976,9 +2000,7 @@ void
1976 2000 QPDFObjectHandle::assertType(char const* type_name, bool istype) const
1977 2001 {
1978 2002 if (!istype) {
1979   - throw std::runtime_error(
1980   - std::string("operation for ") + type_name + " attempted on object of type " +
1981   - QPDFObjectHandle(*this).getTypeName());
  2003 + throw type_error(type_name);
1982 2004 }
1983 2005 }
1984 2006  
... ...
libqpdf/QPDF_linearization.cc
... ... @@ -122,27 +122,18 @@ QPDF::isLinearized()
122 122 continue;
123 123 }
124 124  
125   - auto candidate = getObject(toI(QUtil::string_to_ll(t1.getValue().data())), 0);
126   - if (!candidate.isDictionary()) {
127   - return false;
128   - }
129   -
130   - auto linkey = candidate.getKey("/Linearized");
  125 + Dictionary candidate = getObject(toI(QUtil::string_to_ll(t1.getValue().data())), 0);
  126 + auto linkey = candidate["/Linearized"];
131 127 if (!(linkey.isNumber() && toI(floor(linkey.getNumericValue())) == 1)) {
132 128 return false;
133 129 }
134 130  
135   - auto L = candidate.getKey("/L");
136   - if (!L.isInteger()) {
137   - return false;
138   - }
139   - qpdf_offset_t Li = L.getIntValue();
140 131 m->file->seek(0, SEEK_END);
141   - if (Li != m->file->tell()) {
142   - QTC::TC("qpdf", "QPDF /L mismatch");
  132 + Integer L = candidate["/L"];
  133 + if (L != m->file->tell()) {
143 134 return false;
144 135 }
145   - m->linp.file_size = Li;
  136 + m->linp.file_size = L;
146 137 m->lindict = candidate;
147 138 return true;
148 139 }
... ... @@ -159,80 +150,57 @@ QPDF::readLinearizationData()
159 150 }
160 151  
161 152 // /L is read and stored in linp by isLinearized()
162   - QPDFObjectHandle H = m->lindict.getKey("/H");
163   - QPDFObjectHandle O = m->lindict.getKey("/O");
164   - QPDFObjectHandle E = m->lindict.getKey("/E");
165   - QPDFObjectHandle N = m->lindict.getKey("/N");
166   - QPDFObjectHandle T = m->lindict.getKey("/T");
167   - QPDFObjectHandle P = m->lindict.getKey("/P");
168   -
169   - if (!(H.isArray() && O.isInteger() && E.isInteger() && N.isInteger() && T.isInteger() &&
170   - (P.isInteger() || P.null()))) {
  153 + Array H = m->lindict["/H"]; // hint table offset/length for primary and overflow hint tables
  154 + auto H_size = H.size();
  155 + Integer H_0 = H[0]; // hint table offset
  156 + Integer H_1 = H[1]; // hint table length
  157 + Integer H_2 = H[2]; // hint table offset for overflow hint table
  158 + Integer H_3 = H[3]; // hint table length for overflow hint table
  159 + Integer O = m->lindict["/O"];
  160 + Integer E = m->lindict["/E"];
  161 + Integer N = m->lindict["/N"];
  162 + Integer T = m->lindict["/T"];
  163 + auto P_oh = m->lindict["/P"];
  164 + Integer P = P_oh; // first page number
  165 + QTC::TC("qpdf", "QPDF P absent in lindict", P ? 0 : 1);
  166 +
  167 + if (!(H && O && E && N && T && (P || P_oh.null()))) {
171 168 throw damagedPDF(
172 169 "linearization dictionary",
173 170 "some keys in linearization dictionary are of the wrong type");
174 171 }
175 172  
176   - // Hint table array: offset length [ offset length ]
177   - size_t n_H_items = H.size();
178   - if (!(n_H_items == 2 || n_H_items == 4)) {
  173 + if (!(H_size == 2 || H_size == 4)) {
179 174 throw damagedPDF("linearization dictionary", "H has the wrong number of items");
180 175 }
181 176  
182   - std::vector<int> H_items;
183   - for (auto const& oh: H.as_array()) {
184   - if (oh.isInteger()) {
185   - H_items.push_back(oh.getIntValueAsInt());
186   - } else {
187   - throw damagedPDF("linearization dictionary", "some H items are of the wrong type");
188   - }
189   - }
190   -
191   - // H: hint table offset/length for primary and overflow hint tables
192   - int H0_offset = H_items.at(0);
193   - int H0_length = H_items.at(1);
194   - int H1_offset = 0;
195   - int H1_length = 0;
196   - if (H_items.size() == 4) {
197   - // Acrobat doesn't read or write these (as PDF 1.4), so we don't have a way to generate a
198   - // test case.
199   - // QTC::TC("qpdf", "QPDF overflow hint table");
200   - H1_offset = H_items.at(2);
201   - H1_length = H_items.at(3);
202   - }
203   -
204   - // P: first page number
205   - int first_page = 0;
206   - if (P.isInteger()) {
207   - QTC::TC("qpdf", "QPDF P present in lindict");
208   - first_page = P.getIntValueAsInt();
209   - } else {
210   - QTC::TC("qpdf", "QPDF P absent in lindict");
  177 + if (!(H_0 && H_1 && (H_size == 2 || (H_2 && H_3)))) {
  178 + throw damagedPDF("linearization dictionary", "some H items are of the wrong type");
211 179 }
212 180  
213 181 // Store linearization parameter data
214 182  
215 183 // Various places in the code use linp.npages, which is initialized from N, to pre-allocate
216 184 // memory, so make sure it's accurate and bail right now if it's not.
217   - if (N.getIntValue() != static_cast<long long>(getAllPages().size())) {
  185 + if (N != getAllPages().size()) {
218 186 throw damagedPDF("linearization hint table", "/N does not match number of pages");
219 187 }
220 188  
221 189 // file_size initialized by isLinearized()
222   - m->linp.first_page_object = O.getIntValueAsInt();
223   - m->linp.first_page_end = E.getIntValue();
224   - m->linp.npages = N.getUIntValueAsUInt();
225   - m->linp.xref_zero_offset = T.getIntValue();
226   - m->linp.first_page = first_page;
227   - m->linp.H_offset = H0_offset;
228   - m->linp.H_length = H0_length;
  190 + m->linp.first_page_object = O;
  191 + m->linp.first_page_end = E;
  192 + m->linp.npages = N;
  193 + m->linp.xref_zero_offset = T;
  194 + m->linp.first_page = P ? P : 0;
  195 + m->linp.H_offset = H_0;
  196 + m->linp.H_length = H_1;
229 197  
230 198 // Read hint streams
231 199  
232 200 Pl_Buffer pb("hint buffer");
233   - QPDFObjectHandle H0 = readHintStream(pb, H0_offset, toS(H0_length));
234   - if (H1_offset) {
235   - (void)readHintStream(pb, H1_offset, toS(H1_length));
  201 + auto H0 = readHintStream(pb, H_0, H_1);
  202 + if (H_2) {
  203 + (void)readHintStream(pb, H_2, H_3);
236 204 }
237 205  
238 206 // PDF 1.4 hint tables that we ignore:
... ... @@ -246,8 +214,8 @@ QPDF::readLinearizationData()
246 214 // /L page label
247 215  
248 216 // Individual hint table offsets
249   - QPDFObjectHandle HS = H0.getKey("/S"); // shared object
250   - QPDFObjectHandle HO = H0.getKey("/O"); // outline
  217 + Integer HS = H0["/S"]; // shared object
  218 + Integer HO = H0["/O"]; // outline
251 219  
252 220 auto hbp = pb.getBufferSharedPointer();
253 221 Buffer* hb = hbp.get();
... ... @@ -256,22 +224,22 @@ QPDF::readLinearizationData()
256 224  
257 225 readHPageOffset(BitStream(h_buf, h_size));
258 226  
259   - int HSi = HS.getIntValueAsInt();
260   - if ((HSi < 0) || (toS(HSi) >= h_size)) {
  227 + size_t HSi = HS;
  228 + if (HSi < 0 || HSi >= h_size) {
261 229 throw damagedPDF("linearization hint table", "/S (shared object) offset is out of bounds");
262 230 }
263   - readHSharedObject(BitStream(h_buf + HSi, h_size - toS(HSi)));
  231 + readHSharedObject(BitStream(h_buf + HSi, h_size - HSi));
264 232  
265   - if (HO.isInteger()) {
266   - int HOi = HO.getIntValueAsInt();
267   - if ((HOi < 0) || (toS(HOi) >= h_size)) {
  233 + if (HO) {
  234 + if (HO < 0 || HO >= h_size) {
268 235 throw damagedPDF("linearization hint table", "/O (outline) offset is out of bounds");
269 236 }
270   - readHGeneric(BitStream(h_buf + HOi, h_size - toS(HOi)), m->outline_hints);
  237 + size_t HOi = HO;
  238 + readHGeneric(BitStream(h_buf + HO, h_size - HOi), m->outline_hints);
271 239 }
272 240 }
273 241  
274   -QPDFObjectHandle
  242 +Dictionary
275 243 QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length)
276 244 {
277 245 auto H = readObjectAtOffset(offset, "linearization hint stream", false);
... ... @@ -282,18 +250,14 @@ QPDF::readHintStream(Pipeline&amp; pl, qpdf_offset_t offset, size_t length)
282 250 throw damagedPDF("linearization dictionary", "hint table is not a stream");
283 251 }
284 252  
285   - QPDFObjectHandle Hdict = H.getDict();
  253 + Dictionary Hdict = H.getDict();
286 254  
287 255 // Some versions of Acrobat make /Length indirect and place it immediately after the stream,
288 256 // increasing length to cover it, even though the specification says all objects in the
289 257 // linearization parameter dictionary must be direct. We have to get the file position of the
290 258 // end of length in this case.
291   - QPDFObjectHandle length_obj = Hdict.getKey("/Length");
292   - if (length_obj.isIndirect()) {
293   - QTC::TC("qpdf", "QPDF hint table length indirect");
294   - // Force resolution
295   - (void)length_obj.getIntValue();
296   - ObjCache& oc2 = m->obj_cache[length_obj.getObjGen()];
  259 + if (Hdict["/Length"].indirect()) {
  260 + ObjCache& oc2 = m->obj_cache[Hdict["/Length"]];
297 261 min_end_offset = oc2.end_before_space;
298 262 max_end_offset = oc2.end_after_space;
299 263 } else {
... ...
libqpdf/qpdf/QPDFObjectHandle_private.hh
... ... @@ -7,6 +7,11 @@
7 7 #include <qpdf/QPDF_private.hh>
8 8 #include <qpdf/QUtil.hh>
9 9  
  10 +#include <concepts>
  11 +#include <utility>
  12 +
  13 +using namespace std::literals;
  14 +
10 15 namespace qpdf
11 16 {
12 17 class Array final: public BaseHandle
... ... @@ -285,6 +290,97 @@ namespace qpdf
285 290 ~Dictionary() = default;
286 291 };
287 292  
  293 + class Integer final: public BaseHandle
  294 + {
  295 + public:
  296 + Integer() = default;
  297 + Integer(Integer const&) = default;
  298 + Integer(Integer&&) = default;
  299 + Integer& operator=(Integer const&) = default;
  300 + Integer& operator=(Integer&&) = default;
  301 + ~Integer() = default;
  302 +
  303 + explicit Integer(long long value);
  304 +
  305 + explicit Integer(std::integral auto value) :
  306 + Integer(static_cast<long long>(value))
  307 + {
  308 + if constexpr (
  309 + std::numeric_limits<decltype(value)>::max() >
  310 + std::numeric_limits<long long>::max()) {
  311 + if (value > std::numeric_limits<long long>::max()) {
  312 + throw std::overflow_error("overflow constructing Integer");
  313 + }
  314 + }
  315 + }
  316 +
  317 + Integer(QPDFObjectHandle const& oh) :
  318 + BaseHandle(oh.type_code() == ::ot_integer ? oh : QPDFObjectHandle())
  319 + {
  320 + }
  321 +
  322 + Integer(QPDFObjectHandle&& oh) :
  323 + BaseHandle(oh.type_code() == ::ot_integer ? std::move(oh) : QPDFObjectHandle())
  324 + {
  325 + }
  326 +
  327 + // Return the integer value. If the object is not a valid integer, throw a
  328 + // std::invalid_argument exception. If the object is out of range for the target type,
  329 + // throw a std::overflow_error or std::underflow_error exception.
  330 + template <std::integral T>
  331 + operator T() const
  332 + {
  333 + auto v = value();
  334 +
  335 + if (std::cmp_greater(v, std::numeric_limits<T>::max())) {
  336 + throw std::overflow_error("Integer conversion overflow");
  337 + }
  338 + if (std::cmp_less(v, std::numeric_limits<T>::min())) {
  339 + throw std::underflow_error("Integer conversion underflow");
  340 + }
  341 + return static_cast<T>(v);
  342 + }
  343 +
  344 + // Return the integer value. If the object is not a valid integer, throw a
  345 + // std::invalid_argument exception.
  346 + int64_t value() const;
  347 +
  348 + // Return true if object value is equal to the 'rhs' value. Return false if the object is
  349 + // not a valid Integer.
  350 + friend bool
  351 + operator==(Integer const& lhs, std::integral auto rhs)
  352 + {
  353 + return lhs && std::cmp_equal(lhs.value(), rhs);
  354 + }
  355 +
  356 + // Compare the object value to the 'rhs' value. Throw a std::invalid_argument exception if
  357 + // the object is not a valid Integer.
  358 + friend std::strong_ordering
  359 + operator<=>(Integer const& lhs, std::integral auto rhs)
  360 + {
  361 + if (!lhs) {
  362 + throw lhs.invalid_error("Integer");
  363 + }
  364 + if (std::cmp_less(lhs.value(), rhs)) {
  365 + return std::strong_ordering::less;
  366 + }
  367 + return std::cmp_greater(lhs.value(), rhs) ? std::strong_ordering::greater
  368 + : std::strong_ordering::equal;
  369 + }
  370 + };
  371 +
  372 + bool
  373 + operator==(std::integral auto lhs, Integer const& rhs)
  374 + {
  375 + return rhs == lhs;
  376 + }
  377 +
  378 + std::strong_ordering
  379 + operator<=>(std::integral auto lhs, Integer const& rhs)
  380 + {
  381 + return rhs <=> lhs;
  382 + }
  383 +
288 384 class Name final: public BaseHandle
289 385 {
290 386 public:
... ...
libqpdf/qpdf/QPDFObject_private.hh
... ... @@ -27,6 +27,7 @@ namespace qpdf
27 27 class Array;
28 28 class BaseDictionary;
29 29 class Dictionary;
  30 + class Integer;
30 31 class Stream;
31 32 } // namespace qpdf
32 33  
... ... @@ -123,6 +124,7 @@ class QPDF_Integer final
123 124 {
124 125 friend class QPDFObject;
125 126 friend class qpdf::BaseHandle;
  127 + friend class qpdf::Integer;
126 128 friend class QPDFObjectHandle;
127 129  
128 130 QPDF_Integer(long long val) :
... ...
qpdf/qpdf.testcov
... ... @@ -7,12 +7,9 @@ QPDF check obj 1
7 7 QPDF object stream offsets not increasing 0
8 8 QPDF ignore self-referential object stream 0
9 9 QPDF object stream contains id < 1 0
10   -QPDF hint table length indirect 0
11 10 QPDF hint table length direct 0
12   -QPDF P absent in lindict 0
13   -QPDF P present in lindict 0
  11 +QPDF P absent in lindict 1
14 12 QPDF expected n n obj 0
15   -QPDF /L mismatch 0
16 13 QPDF err /T mismatch 0
17 14 QPDF err /O mismatch 0
18 15 QPDF opt direct pages resource 1
... ... @@ -277,7 +274,6 @@ QPDFParser bad token in parseRemainder 0
277 274 QPDFParser eof in parse 0
278 275 QPDFParser eof in parseRemainder 0
279 276 QPDFObjectHandle boolean returning false 0
280   -QPDFObjectHandle integer returning 0 0
281 277 QPDFObjectHandle real returning 0.0 0
282 278 QPDFObjectHandle name returning dummy name 0
283 279 QPDFObjectHandle string returning empty string 0
... ...