Commit 5696a507b6dacf34d066810a3f2fca3525eb02f5

Authored by Jay Berkenbilt
Committed by GitHub
2 parents 6f1041af 8b4afa42

Merge pull request #731 from m-holger/og_unparse

Tidy QPDFObjGen related code
examples/pdf-create.cc
... ... @@ -29,8 +29,7 @@ class ImageProvider: public QPDFObjectHandle::StreamDataProvider
29 29 public:
30 30 ImageProvider(std::string const& color_space, std::string const& filter);
31 31 virtual ~ImageProvider() = default;
32   - virtual void
33   - provideStreamData(int objid, int generation, Pipeline* pipeline);
  32 + virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
34 33 size_t getWidth() const;
35 34 size_t getHeight() const;
36 35  
... ... @@ -93,7 +92,7 @@ ImageProvider::getHeight() const
93 92 }
94 93  
95 94 void
96   -ImageProvider::provideStreamData(int objid, int generation, Pipeline* pipeline)
  95 +ImageProvider::provideStreamData(QPDFObjGen const&, Pipeline* pipeline)
97 96 {
98 97 std::vector<std::shared_ptr<Pipeline>> to_delete;
99 98 Pipeline* p = pipeline;
... ... @@ -292,7 +291,7 @@ check(
292 291 ImageProvider* p = new ImageProvider(desired_color_space, "null");
293 292 std::shared_ptr<QPDFObjectHandle::StreamDataProvider> provider(p);
294 293 Pl_Buffer b_p("get image data");
295   - provider->provideStreamData(0, 0, &b_p);
  294 + provider->provideStreamData(QPDFObjGen(), &b_p);
296 295 std::shared_ptr<Buffer> desired_data(b_p.getBuffer());
297 296  
298 297 if (desired_data->getSize() != actual_data->getSize()) {
... ...
examples/pdf-custom-filter.cc
... ... @@ -201,7 +201,7 @@ class StreamReplacer: public QPDFObjectHandle::StreamDataProvider
201 201 StreamReplacer(QPDF* pdf);
202 202 virtual ~StreamReplacer() = default;
203 203 virtual void
204   - provideStreamData(int objid, int generation, Pipeline* pipeline) override;
  204 + provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override;
205 205  
206 206 void registerStream(
207 207 QPDFObjectHandle stream,
... ... @@ -384,9 +384,8 @@ StreamReplacer::registerStream(
384 384 }
385 385  
386 386 void
387   -StreamReplacer::provideStreamData(int objid, int generation, Pipeline* pipeline)
  387 +StreamReplacer::provideStreamData(QPDFObjGen const& og, Pipeline* pipeline)
388 388 {
389   - QPDFObjGen og(objid, generation);
390 389 QPDFObjectHandle orig = this->copied_streams[og];
391 390 // call maybeReplace again, this time with the pipeline and no
392 391 // dict_updates. In this mode, maybeReplace doesn't make any
... ...
examples/pdf-invert-images.cc
... ... @@ -35,7 +35,7 @@ class ImageInverter: public QPDFObjectHandle::StreamDataProvider
35 35 public:
36 36 virtual ~ImageInverter() = default;
37 37 virtual void
38   - provideStreamData(int objid, int generation, Pipeline* pipeline) override;
  38 + provideStreamData(QPDFObjGen const& og, Pipeline* pipeline) override;
39 39  
40 40 void registerImage(
41 41 QPDFObjectHandle image,
... ... @@ -82,12 +82,11 @@ ImageInverter::registerImage(
82 82 }
83 83  
84 84 void
85   -ImageInverter::provideStreamData(int objid, int generation, Pipeline* pipeline)
  85 +ImageInverter::provideStreamData(QPDFObjGen const& og, Pipeline* pipeline)
86 86 {
87 87 // Use the object and generation number supplied to look up the
88 88 // image data. Then invert the image data and write the inverted
89 89 // data to the pipeline.
90   - QPDFObjGen og(objid, generation);
91 90 std::shared_ptr<Buffer> data =
92 91 this->copied_images[og].getStreamData(qpdf_dl_all);
93 92 size_t size = data->getSize();
... ...
include/qpdf/QPDF.hh
... ... @@ -815,9 +815,9 @@ class QPDF
815 815  
816 816 private:
817 817 static std::shared_ptr<QPDFObject>
818   - resolve(QPDF* qpdf, int objid, int generation)
  818 + resolve(QPDF* qpdf, QPDFObjGen const& og)
819 819 {
820   - return qpdf->resolve(objid, generation);
  820 + return qpdf->resolve(og);
821 821 }
822 822 static bool
823 823 objectChanged(
... ... @@ -879,8 +879,7 @@ class QPDF
879 879 static bool
880 880 pipeStreamData(
881 881 QPDF* qpdf,
882   - int objid,
883   - int generation,
  882 + QPDFObjGen const& og,
884 883 qpdf_offset_t offset,
885 884 size_t length,
886 885 QPDFObjectHandle dict,
... ... @@ -889,8 +888,7 @@ class QPDF
889 888 bool will_retry)
890 889 {
891 890 return qpdf->pipeStreamData(
892   - objid,
893   - generation,
  891 + og,
894 892 offset,
895 893 length,
896 894 dict,
... ... @@ -959,8 +957,7 @@ class QPDF
959 957 std::string user_password;
960 958 std::string encryption_key;
961 959 std::string cached_object_encryption_key;
962   - int cached_key_objid;
963   - int cached_key_generation;
  960 + QPDFObjGen cached_key_og;
964 961 bool user_password_matched;
965 962 bool owner_password_matched;
966 963 };
... ... @@ -973,8 +970,7 @@ class QPDF
973 970 ForeignStreamData(
974 971 std::shared_ptr<EncryptionParameters> encp,
975 972 std::shared_ptr<InputSource> file,
976   - int foreign_objid,
977   - int foreign_generation,
  973 + QPDFObjGen const& foreign_og,
978 974 qpdf_offset_t offset,
979 975 size_t length,
980 976 QPDFObjectHandle local_dict);
... ... @@ -982,8 +978,7 @@ class QPDF
982 978 private:
983 979 std::shared_ptr<EncryptionParameters> encp;
984 980 std::shared_ptr<InputSource> file;
985   - int foreign_objid;
986   - int foreign_generation;
  981 + QPDFObjGen foreign_og;
987 982 qpdf_offset_t offset;
988 983 size_t length;
989 984 QPDFObjectHandle local_dict;
... ... @@ -995,8 +990,7 @@ class QPDF
995 990 CopiedStreamDataProvider(QPDF& destination_qpdf);
996 991 virtual ~CopiedStreamDataProvider() = default;
997 992 virtual bool provideStreamData(
998   - int objid,
999   - int generation,
  993 + QPDFObjGen const& og,
1000 994 Pipeline* pipeline,
1001 995 bool suppress_warnings,
1002 996 bool will_retry) override;
... ... @@ -1017,14 +1011,13 @@ class QPDF
1017 1011 friend class QPDF;
1018 1012  
1019 1013 public:
1020   - StringDecrypter(QPDF* qpdf, int objid, int gen);
  1014 + StringDecrypter(QPDF* qpdf, QPDFObjGen const& og);
1021 1015 virtual ~StringDecrypter() = default;
1022 1016 virtual void decryptString(std::string& val);
1023 1017  
1024 1018 private:
1025 1019 QPDF* qpdf;
1026   - int objid;
1027   - int gen;
  1020 + QPDFObjGen og;
1028 1021 };
1029 1022  
1030 1023 class ResolveRecorder
... ... @@ -1127,17 +1120,15 @@ class QPDF
1127 1120 void insertXrefEntry(
1128 1121 int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite = false);
1129 1122 void setLastObjectDescription(
1130   - std::string const& description, int objid, int generation);
  1123 + std::string const& description, QPDFObjGen const& og);
1131 1124 QPDFObjectHandle readObject(
1132 1125 std::shared_ptr<InputSource>,
1133 1126 std::string const& description,
1134   - int objid,
1135   - int generation,
  1127 + QPDFObjGen const& og,
1136 1128 bool in_object_stream);
1137 1129 size_t recoverStreamLength(
1138 1130 std::shared_ptr<InputSource> input,
1139   - int objid,
1140   - int generation,
  1131 + QPDFObjGen const& og,
1141 1132 qpdf_offset_t stream_offset);
1142 1133 QPDFTokenizer::Token
1143 1134 readToken(std::shared_ptr<InputSource>, size_t max_len = 0);
... ... @@ -1146,21 +1137,18 @@ class QPDF
1146 1137 bool attempt_recovery,
1147 1138 qpdf_offset_t offset,
1148 1139 std::string const& description,
1149   - int exp_objid,
1150   - int exp_generation,
1151   - int& act_objid,
1152   - int& act_generation);
  1140 + QPDFObjGen const& exp_og,
  1141 + QPDFObjGen& og);
1153 1142 bool objectChanged(QPDFObjGen const& og, std::shared_ptr<QPDFObject>& oph);
1154   - std::shared_ptr<QPDFObject> resolve(int objid, int generation);
  1143 + std::shared_ptr<QPDFObject> resolve(QPDFObjGen const& og);
1155 1144 void resolveObjectsInStream(int obj_stream_number);
1156 1145 void stopOnError(std::string const& message);
1157   - QPDFObjectHandle reserveObjectIfNotExists(int objid, int gen);
1158   - QPDFObjectHandle reserveStream(int objid, int gen);
  1146 + QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
  1147 + QPDFObjectHandle reserveStream(QPDFObjGen const& og);
1159 1148  
1160 1149 // Calls finish() on the pipeline when done but does not delete it
1161 1150 bool pipeStreamData(
1162   - int objid,
1163   - int generation,
  1151 + QPDFObjGen const& og,
1164 1152 qpdf_offset_t offset,
1165 1153 size_t length,
1166 1154 QPDFObjectHandle dict,
... ... @@ -1176,8 +1164,7 @@ class QPDF
1176 1164 std::shared_ptr<QPDF::EncryptionParameters> encp,
1177 1165 std::shared_ptr<InputSource> file,
1178 1166 QPDF& qpdf_for_warning,
1179   - int objid,
1180   - int generation,
  1167 + QPDFObjGen const& og,
1181 1168 qpdf_offset_t offset,
1182 1169 size_t length,
1183 1170 QPDFObjectHandle dict,
... ... @@ -1230,10 +1217,9 @@ class QPDF
1230 1217 void initializeEncryption();
1231 1218 static std::string getKeyForObject(
1232 1219 std::shared_ptr<EncryptionParameters> encp,
1233   - int objid,
1234   - int generation,
  1220 + QPDFObjGen const& og,
1235 1221 bool use_aes);
1236   - void decryptString(std::string&, int objid, int generation);
  1222 + void decryptString(std::string&, QPDFObjGen const& og);
1237 1223 static std::string compute_encryption_key_from_password(
1238 1224 std::string const& password, EncryptionData const& data);
1239 1225 static std::string recover_encryption_key_with_password(
... ... @@ -1247,8 +1233,7 @@ class QPDF
1247 1233 std::shared_ptr<InputSource> file,
1248 1234 QPDF& qpdf_for_warning,
1249 1235 Pipeline*& pipeline,
1250   - int objid,
1251   - int generation,
  1236 + QPDFObjGen const& og,
1252 1237 QPDFObjectHandle& stream_dict,
1253 1238 std::vector<std::shared_ptr<Pipeline>>& heap);
1254 1239  
... ... @@ -1571,7 +1556,6 @@ class QPDF
1571 1556 void dumpHSharedObject();
1572 1557 void dumpHGeneric(HGeneric&);
1573 1558 qpdf_offset_t adjusted_offset(qpdf_offset_t offset);
1574   - QPDFObjectHandle objGenToIndirect(QPDFObjGen const&);
1575 1559 void
1576 1560 calculateLinearizationData(std::map<int, int> const& object_stream_data);
1577 1561 void pushOutlinesToPart(
... ...
include/qpdf/QPDFObjGen.hh
... ... @@ -23,7 +23,6 @@
23 23 #define QPDFOBJGEN_HH
24 24  
25 25 #include <qpdf/DLL.h>
26   -#include <qpdf/QUtil.hh>
27 26 #include <iostream>
28 27  
29 28 // This class represents an object ID and generation pair. It is
... ... @@ -39,7 +38,7 @@ class QPDFObjGen
39 38 {
40 39 }
41 40 QPDF_DLL
42   - QPDFObjGen(int obj, int gen) :
  41 + explicit QPDFObjGen(int obj, int gen) :
43 42 obj(obj),
44 43 gen(gen)
45 44 {
... ... @@ -48,13 +47,19 @@ class QPDFObjGen
48 47 bool
49 48 operator<(QPDFObjGen const& rhs) const
50 49 {
51   - return ((obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen)));
  50 + return (obj < rhs.obj) || ((obj == rhs.obj) && (gen < rhs.gen));
52 51 }
53 52 QPDF_DLL
54 53 bool
55 54 operator==(QPDFObjGen const& rhs) const
56 55 {
57   - return ((obj == rhs.obj) && (gen == rhs.gen));
  56 + return (obj == rhs.obj) && (gen == rhs.gen);
  57 + }
  58 + QPDF_DLL
  59 + bool
  60 + operator!=(QPDFObjGen const& rhs) const
  61 + {
  62 + return (obj != rhs.obj) || (gen != rhs.gen);
58 63 }
59 64 QPDF_DLL
60 65 int
... ... @@ -69,18 +74,15 @@ class QPDFObjGen
69 74 return gen;
70 75 }
71 76 QPDF_DLL
72   - std::string
73   - unparse() const
  77 + bool
  78 + isIndirect() const
74 79 {
75   - return QUtil::int_to_string(obj) + "," + QUtil::int_to_string(gen);
  80 + return obj != 0;
76 81 }
77 82 QPDF_DLL
78   - friend std::ostream&
79   - operator<<(std::ostream& os, const QPDFObjGen& og)
80   - {
81   - os << og.obj << "," << og.gen;
82   - return os;
83   - }
  83 + std::string unparse(char separator = ',') const;
  84 + QPDF_DLL
  85 + friend std::ostream& operator<<(std::ostream& os, const QPDFObjGen& og);
84 86  
85 87 private:
86 88 // This class does not use the Members pattern to avoid a memory
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -116,9 +116,16 @@ class QPDFObjectHandle
116 116 // indicating whether it ran without errors.
117 117 QPDF_DLL
118 118 virtual void
119   - provideStreamData(int objid, int generation, Pipeline* pipeline);
  119 + provideStreamData(QPDFObjGen const& og, Pipeline* pipeline);
120 120 QPDF_DLL
121 121 virtual bool provideStreamData(
  122 + QPDFObjGen const& og,
  123 + Pipeline* pipeline,
  124 + bool suppress_warnings,
  125 + bool will_retry);
  126 + QPDF_DLL virtual void
  127 + provideStreamData(int objid, int generation, Pipeline* pipeline);
  128 + QPDF_DLL virtual bool provideStreamData(
122 129 int objid,
123 130 int generation,
124 131 Pipeline* pipeline,
... ... @@ -1429,21 +1436,20 @@ class QPDFObjectHandle
1429 1436  
1430 1437 private:
1431 1438 static QPDFObjectHandle
1432   - newIndirect(QPDF* qpdf, int objid, int generation)
  1439 + newIndirect(QPDF* qpdf, QPDFObjGen const& og)
1433 1440 {
1434   - return QPDFObjectHandle::newIndirect(qpdf, objid, generation);
  1441 + return QPDFObjectHandle::newIndirect(qpdf, og);
1435 1442 }
1436 1443 static QPDFObjectHandle
1437 1444 newStream(
1438 1445 QPDF* qpdf,
1439   - int objid,
1440   - int generation,
  1446 + QPDFObjGen const& og,
1441 1447 QPDFObjectHandle stream_dict,
1442 1448 qpdf_offset_t offset,
1443 1449 size_t length)
1444 1450 {
1445 1451 return QPDFObjectHandle::newStream(
1446   - qpdf, objid, generation, stream_dict, offset, length);
  1452 + qpdf, og, stream_dict, offset, length);
1447 1453 }
1448 1454 // Reserve an object with a specific ID
1449 1455 static QPDFObjectHandle
... ... @@ -1550,7 +1556,7 @@ class QPDFObjectHandle
1550 1556 bool isImage(bool exclude_imagemask = true);
1551 1557  
1552 1558 private:
1553   - QPDFObjectHandle(QPDF*, int objid, int generation);
  1559 + QPDFObjectHandle(QPDF*, QPDFObjGen const& og);
1554 1560 QPDFObjectHandle(std::shared_ptr<QPDFObject> const&);
1555 1561  
1556 1562 enum parser_state_e {
... ... @@ -1563,11 +1569,10 @@ class QPDFObjectHandle
1563 1569 };
1564 1570  
1565 1571 // Private object factory methods
1566   - static QPDFObjectHandle newIndirect(QPDF*, int objid, int generation);
  1572 + static QPDFObjectHandle newIndirect(QPDF*, QPDFObjGen const& og);
1567 1573 static QPDFObjectHandle newStream(
1568 1574 QPDF* qpdf,
1569   - int objid,
1570   - int generation,
  1575 + QPDFObjGen const& og,
1571 1576 QPDFObjectHandle stream_dict,
1572 1577 qpdf_offset_t offset,
1573 1578 size_t length);
... ... @@ -1584,7 +1589,6 @@ class QPDFObjectHandle
1584 1589 bool stop_at_streams);
1585 1590 void shallowCopyInternal(QPDFObjectHandle& oh, bool first_level_only);
1586 1591 void releaseResolved();
1587   - std::string getObjGenAsStr() const;
1588 1592 static void setObjectDescriptionFromInput(
1589 1593 QPDFObjectHandle,
1590 1594 QPDF*,
... ... @@ -1618,8 +1622,7 @@ class QPDFObjectHandle
1618 1622 // a substantial performance penalty since QPDFObjectHandle
1619 1623 // objects are copied around so frequently.
1620 1624 QPDF* qpdf;
1621   - int objid; // 0 for direct object
1622   - int generation;
  1625 + QPDFObjGen og;
1623 1626 std::shared_ptr<QPDFObject> obj;
1624 1627 bool reserved;
1625 1628 };
... ...
libqpdf/CMakeLists.txt
... ... @@ -74,6 +74,7 @@ set(libqpdf_SOURCES
74 74 QPDFNumberTreeObjectHelper.cc
75 75 QPDFObject.cc
76 76 QPDFObjectHandle.cc
  77 + QPDFObjGen.cc
77 78 QPDFOutlineDocumentHelper.cc
78 79 QPDFOutlineObjectHelper.cc
79 80 QPDFPageDocumentHelper.cc
... ...
libqpdf/QPDF.cc
... ... @@ -113,15 +113,13 @@ namespace
113 113 QPDF::ForeignStreamData::ForeignStreamData(
114 114 std::shared_ptr<EncryptionParameters> encp,
115 115 std::shared_ptr<InputSource> file,
116   - int foreign_objid,
117   - int foreign_generation,
  116 + QPDFObjGen const& foreign_og,
118 117 qpdf_offset_t offset,
119 118 size_t length,
120 119 QPDFObjectHandle local_dict) :
121 120 encp(encp),
122 121 file(file),
123   - foreign_objid(foreign_objid),
124   - foreign_generation(foreign_generation),
  122 + foreign_og(foreign_og),
125 123 offset(offset),
126 124 length(length),
127 125 local_dict(local_dict)
... ... @@ -137,22 +135,19 @@ QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider(
137 135  
138 136 bool
139 137 QPDF::CopiedStreamDataProvider::provideStreamData(
140   - int objid,
141   - int generation,
  138 + QPDFObjGen const& og,
142 139 Pipeline* pipeline,
143 140 bool suppress_warnings,
144 141 bool will_retry)
145 142 {
146   - std::shared_ptr<ForeignStreamData> foreign_data =
147   - this->foreign_stream_data[QPDFObjGen(objid, generation)];
  143 + std::shared_ptr<ForeignStreamData> foreign_data = foreign_stream_data[og];
148 144 bool result = false;
149 145 if (foreign_data.get()) {
150 146 result = destination_qpdf.pipeForeignStreamData(
151 147 foreign_data, pipeline, suppress_warnings, will_retry);
152 148 QTC::TC("qpdf", "QPDF copy foreign with data", result ? 0 : 1);
153 149 } else {
154   - QPDFObjectHandle foreign_stream =
155   - this->foreign_streams[QPDFObjGen(objid, generation)];
  150 + auto foreign_stream = foreign_streams[og];
156 151 result = foreign_stream.pipeStreamData(
157 152 pipeline, nullptr, 0, qpdf_dl_none, suppress_warnings, will_retry);
158 153 QTC::TC(
... ... @@ -176,17 +171,16 @@ QPDF::CopiedStreamDataProvider::registerForeignStream(
176 171 this->foreign_stream_data[local_og] = foreign_stream;
177 172 }
178 173  
179   -QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, int objid, int gen) :
  174 +QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, QPDFObjGen const& og) :
180 175 qpdf(qpdf),
181   - objid(objid),
182   - gen(gen)
  176 + og(og)
183 177 {
184 178 }
185 179  
186 180 void
187 181 QPDF::StringDecrypter::decryptString(std::string& val)
188 182 {
189   - qpdf->decryptString(val, objid, gen);
  183 + qpdf->decryptString(val, og);
190 184 }
191 185  
192 186 std::string const&
... ... @@ -205,8 +199,6 @@ QPDF::EncryptionParameters::EncryptionParameters() :
205 199 cf_stream(e_none),
206 200 cf_string(e_none),
207 201 cf_file(e_none),
208   - cached_key_objid(0),
209   - cached_key_generation(0),
210 202 user_password_matched(false),
211 203 owner_password_matched(false)
212 204 {
... ... @@ -631,7 +623,7 @@ QPDF::reconstruct_xref(QPDFExc&amp; e)
631 623 (!this->m->trailer.isInitialized()) &&
632 624 (t1 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "trailer"))) {
633 625 QPDFObjectHandle t =
634   - readObject(this->m->file, "trailer", 0, 0, false);
  626 + readObject(this->m->file, "trailer", QPDFObjGen(), false);
635 627 if (!t.isDictionary()) {
636 628 // Oh well. It was worth a try.
637 629 } else {
... ... @@ -969,7 +961,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
969 961  
970 962 // Set offset to previous xref table if any
971 963 QPDFObjectHandle cur_trailer =
972   - readObject(this->m->file, "trailer", 0, 0, false);
  964 + readObject(this->m->file, "trailer", QPDFObjGen(), false);
973 965 if (!cur_trailer.isDictionary()) {
974 966 QTC::TC("qpdf", "QPDF missing trailer");
975 967 throw QPDFExc(
... ... @@ -1055,12 +1047,11 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset)
1055 1047 {
1056 1048 bool found = false;
1057 1049 if (!this->m->ignore_xref_streams) {
1058   - int xobj;
1059   - int xgen;
  1050 + QPDFObjGen x_og;
1060 1051 QPDFObjectHandle xref_obj;
1061 1052 try {
1062 1053 xref_obj = readObjectAtOffset(
1063   - false, xref_offset, "xref stream", 0, 0, xobj, xgen);
  1054 + false, xref_offset, "xref stream", QPDFObjGen(0, 0), x_og);
1064 1055 } catch (QPDFExc&) {
1065 1056 // ignore -- report error below
1066 1057 }
... ... @@ -1363,7 +1354,7 @@ QPDF::showXRefTable()
1363 1354 for (auto const& iter: this->m->xref_table) {
1364 1355 QPDFObjGen const& og = iter.first;
1365 1356 QPDFXRefEntry const& entry = iter.second;
1366   - cout << og.getObj() << "/" << og.getGen() << ": ";
  1357 + cout << og.unparse('/') << ": ";
1367 1358 switch (entry.getType()) {
1368 1359 case 1:
1369 1360 cout << "uncompressed; offset = " << entry.getOffset();
... ... @@ -1405,9 +1396,8 @@ QPDF::fixDanglingReferences(bool force)
1405 1396 // For each non-scalar item to process, put it in the queue.
1406 1397 std::list<QPDFObjectHandle> queue;
1407 1398 queue.push_back(this->m->trailer);
1408   - for (auto const& iter: to_process) {
1409   - QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect(
1410   - this, iter.getObj(), iter.getGen());
  1399 + for (auto const& og: to_process) {
  1400 + QPDFObjectHandle obj = QPDFObjectHandle::Factory::newIndirect(this, og);
1411 1401 if (obj.isDictionary() || obj.isArray()) {
1412 1402 queue.push_back(obj);
1413 1403 } else if (obj.isStream()) {
... ... @@ -1473,29 +1463,24 @@ QPDF::getAllObjects()
1473 1463 std::vector<QPDFObjectHandle> result;
1474 1464 for (auto const& iter: this->m->obj_cache) {
1475 1465 QPDFObjGen const& og = iter.first;
1476   - result.push_back(
1477   - // line-break
1478   - QPDFObjectHandle::Factory::newIndirect(
1479   - this, og.getObj(), og.getGen()));
  1466 + result.push_back(QPDFObjectHandle::Factory::newIndirect(this, og));
1480 1467 }
1481 1468 return result;
1482 1469 }
1483 1470  
1484 1471 void
1485 1472 QPDF::setLastObjectDescription(
1486   - std::string const& description, int objid, int generation)
  1473 + std::string const& description, QPDFObjGen const& og)
1487 1474 {
1488 1475 this->m->last_object_description.clear();
1489 1476 if (!description.empty()) {
1490 1477 this->m->last_object_description += description;
1491   - if (objid > 0) {
  1478 + if (og.isIndirect()) {
1492 1479 this->m->last_object_description += ": ";
1493 1480 }
1494 1481 }
1495   - if (objid > 0) {
1496   - this->m->last_object_description += "object " +
1497   - QUtil::int_to_string(objid) + " " +
1498   - QUtil::int_to_string(generation);
  1482 + if (og.isIndirect()) {
  1483 + this->m->last_object_description += "object " + og.unparse(' ');
1499 1484 }
1500 1485 }
1501 1486  
... ... @@ -1503,19 +1488,17 @@ QPDFObjectHandle
1503 1488 QPDF::readObject(
1504 1489 std::shared_ptr<InputSource> input,
1505 1490 std::string const& description,
1506   - int objid,
1507   - int generation,
  1491 + QPDFObjGen const& og,
1508 1492 bool in_object_stream)
1509 1493 {
1510   - setLastObjectDescription(description, objid, generation);
  1494 + setLastObjectDescription(description, og);
1511 1495 qpdf_offset_t offset = input->tell();
1512 1496  
1513 1497 bool empty = false;
1514 1498 std::shared_ptr<StringDecrypter> decrypter_ph;
1515 1499 StringDecrypter* decrypter = 0;
1516 1500 if (this->m->encp->encrypted && (!in_object_stream)) {
1517   - decrypter_ph =
1518   - std::make_shared<StringDecrypter>(this, objid, generation);
  1501 + decrypter_ph = std::make_shared<StringDecrypter>(this, og);
1519 1502 decrypter = decrypter_ph.get();
1520 1503 }
1521 1504 QPDFObjectHandle object = QPDFObjectHandle::parse(
... ... @@ -1657,14 +1640,13 @@ QPDF::readObject(
1657 1640 } catch (QPDFExc& e) {
1658 1641 if (this->m->attempt_recovery) {
1659 1642 warn(e);
1660   - length = recoverStreamLength(
1661   - input, objid, generation, stream_offset);
  1643 + length = recoverStreamLength(input, og, stream_offset);
1662 1644 } else {
1663 1645 throw e;
1664 1646 }
1665 1647 }
1666 1648 object = QPDFObjectHandle::Factory::newStream(
1667   - this, objid, generation, object, stream_offset, length);
  1649 + this, og, object, stream_offset, length);
1668 1650 } else {
1669 1651 input->seek(cur_offset, SEEK_SET);
1670 1652 }
... ... @@ -1692,8 +1674,7 @@ QPDF::findEndstream()
1692 1674 size_t
1693 1675 QPDF::recoverStreamLength(
1694 1676 std::shared_ptr<InputSource> input,
1695   - int objid,
1696   - int generation,
  1677 + QPDFObjGen const& og,
1697 1678 qpdf_offset_t stream_offset)
1698 1679 {
1699 1680 // Try to reconstruct stream length by looking for
... ... @@ -1718,11 +1699,10 @@ QPDF::recoverStreamLength(
1718 1699  
1719 1700 if (length) {
1720 1701 qpdf_offset_t this_obj_offset = 0;
1721   - QPDFObjGen this_obj(0, 0);
  1702 + QPDFObjGen this_og;
1722 1703  
1723 1704 // Make sure this is inside this object
1724 1705 for (auto const& iter: this->m->xref_table) {
1725   - QPDFObjGen const& og = iter.first;
1726 1706 QPDFXRefEntry const& entry = iter.second;
1727 1707 if (entry.getType() == 1) {
1728 1708 qpdf_offset_t obj_offset = entry.getOffset();
... ... @@ -1730,12 +1710,11 @@ QPDF::recoverStreamLength(
1730 1710 ((this_obj_offset == 0) ||
1731 1711 (this_obj_offset > obj_offset))) {
1732 1712 this_obj_offset = obj_offset;
1733   - this_obj = og;
  1713 + this_og = iter.first;
1734 1714 }
1735 1715 }
1736 1716 }
1737   - if (this_obj_offset && (this_obj.getObj() == objid) &&
1738   - (this_obj.getGen() == generation)) {
  1717 + if (this_obj_offset && (this_og == og)) {
1739 1718 // Well, we found endstream\nendobj within the space
1740 1719 // allowed for this object, so we're probably in good
1741 1720 // shape.
... ... @@ -1777,13 +1756,11 @@ QPDF::readObjectAtOffset(
1777 1756 bool try_recovery,
1778 1757 qpdf_offset_t offset,
1779 1758 std::string const& description,
1780   - int exp_objid,
1781   - int exp_generation,
1782   - int& objid,
1783   - int& generation)
  1759 + QPDFObjGen const& exp_og,
  1760 + QPDFObjGen& og)
1784 1761 {
1785 1762 bool check_og = true;
1786   - if (exp_objid == 0) {
  1763 + if (exp_og.getObj() == 0) {
1787 1764 // This method uses an expect object ID of 0 to indicate that
1788 1765 // we don't know or don't care what the actual object ID is at
1789 1766 // this offset. This is true when we read the xref stream and
... ... @@ -1795,7 +1772,7 @@ QPDF::readObjectAtOffset(
1795 1772 check_og = false;
1796 1773 try_recovery = false;
1797 1774 } else {
1798   - setLastObjectDescription(description, exp_objid, exp_generation);
  1775 + setLastObjectDescription(description, exp_og);
1799 1776 }
1800 1777  
1801 1778 if (!this->m->attempt_recovery) {
... ... @@ -1841,9 +1818,9 @@ QPDF::readObjectAtOffset(
1841 1818 offset,
1842 1819 "expected n n obj");
1843 1820 }
1844   - objid = QUtil::string_to_int(tobjid.getValue().c_str());
1845   - generation = QUtil::string_to_int(tgen.getValue().c_str());
1846   -
  1821 + int objid = QUtil::string_to_int(tobjid.getValue().c_str());
  1822 + int generation = QUtil::string_to_int(tgen.getValue().c_str());
  1823 + og = QPDFObjGen(objid, generation);
1847 1824 if (objid == 0) {
1848 1825 QTC::TC("qpdf", "QPDF object id 0");
1849 1826 throw QPDFExc(
... ... @@ -1853,17 +1830,14 @@ QPDF::readObjectAtOffset(
1853 1830 offset,
1854 1831 "object with ID 0");
1855 1832 }
1856   -
1857   - if (check_og &&
1858   - (!((objid == exp_objid) && (generation == exp_generation)))) {
  1833 + if (check_og && (exp_og != og)) {
1859 1834 QTC::TC("qpdf", "QPDF err wrong objid/generation");
1860 1835 QPDFExc e(
1861 1836 qpdf_e_damaged_pdf,
1862 1837 this->m->file->getName(),
1863 1838 this->m->last_object_description,
1864 1839 offset,
1865   - (std::string("expected ") + QUtil::int_to_string(exp_objid) +
1866   - " " + QUtil::int_to_string(exp_generation) + " obj"));
  1840 + (std::string("expected ") + exp_og.unparse(' ') + " obj"));
1867 1841 if (try_recovery) {
1868 1842 // Will be retried below
1869 1843 throw e;
... ... @@ -1877,18 +1851,12 @@ QPDF::readObjectAtOffset(
1877 1851 if (try_recovery) {
1878 1852 // Try again after reconstructing xref table
1879 1853 reconstruct_xref(e);
1880   - QPDFObjGen og(exp_objid, exp_generation);
1881   - if (this->m->xref_table.count(og) &&
1882   - (this->m->xref_table[og].getType() == 1)) {
1883   - qpdf_offset_t new_offset = this->m->xref_table[og].getOffset();
  1854 + if (this->m->xref_table.count(exp_og) &&
  1855 + (this->m->xref_table[exp_og].getType() == 1)) {
  1856 + qpdf_offset_t new_offset =
  1857 + this->m->xref_table[exp_og].getOffset();
1884 1858 QPDFObjectHandle result = readObjectAtOffset(
1885   - false,
1886   - new_offset,
1887   - description,
1888   - exp_objid,
1889   - exp_generation,
1890   - objid,
1891   - generation);
  1859 + false, new_offset, description, exp_og, og);
1892 1860 QTC::TC("qpdf", "QPDF recovered in readObjectAtOffset");
1893 1861 return result;
1894 1862 } else {
... ... @@ -1898,8 +1866,7 @@ QPDF::readObjectAtOffset(
1898 1866 "",
1899 1867 0,
1900 1868 std::string(
1901   - "object " + QUtil::int_to_string(exp_objid) + " " +
1902   - QUtil::int_to_string(exp_generation) +
  1869 + "object " + exp_og.unparse(' ') +
1903 1870 " not found in file after regenerating"
1904 1871 " cross reference table"));
1905 1872 return QPDFObjectHandle::newNull();
... ... @@ -1909,8 +1876,7 @@ QPDF::readObjectAtOffset(
1909 1876 }
1910 1877 }
1911 1878  
1912   - QPDFObjectHandle oh =
1913   - readObject(this->m->file, description, objid, generation, false);
  1879 + QPDFObjectHandle oh = readObject(this->m->file, description, og, false);
1914 1880  
1915 1881 if (!(readToken(this->m->file) ==
1916 1882 QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) {
... ... @@ -1922,7 +1888,6 @@ QPDF::readObjectAtOffset(
1922 1888 "expected endobj");
1923 1889 }
1924 1890  
1925   - QPDFObjGen og(objid, generation);
1926 1891 if (!this->m->obj_cache.count(og)) {
1927 1892 // Store the object in the cache here so it gets cached
1928 1893 // whether we first know the offset or whether we first know
... ... @@ -1987,12 +1952,11 @@ QPDF::objectChanged(QPDFObjGen const&amp; og, std::shared_ptr&lt;QPDFObject&gt;&amp; oph)
1987 1952 }
1988 1953  
1989 1954 std::shared_ptr<QPDFObject>
1990   -QPDF::resolve(int objid, int generation)
  1955 +QPDF::resolve(QPDFObjGen const& og)
1991 1956 {
1992 1957 // Check object cache before checking xref table. This allows us
1993 1958 // to insert things into the object cache that don't actually
1994 1959 // exist in the file.
1995   - QPDFObjGen og(objid, generation);
1996 1960 if (this->m->resolving.count(og)) {
1997 1961 // This can happen if an object references itself directly or
1998 1962 // indirectly in some key that has to be resolved during
... ... @@ -2002,8 +1966,7 @@ QPDF::resolve(int objid, int generation)
2002 1966 qpdf_e_damaged_pdf,
2003 1967 "",
2004 1968 this->m->file->getLastOffset(),
2005   - ("loop detected resolving object " + QUtil::int_to_string(objid) +
2006   - " " + QUtil::int_to_string(generation)));
  1969 + ("loop detected resolving object " + og.unparse(' ')));
2007 1970 return QPDF_Null::create();
2008 1971 }
2009 1972 ResolveRecorder rr(this, og);
... ... @@ -2016,16 +1979,9 @@ QPDF::resolve(int objid, int generation)
2016 1979 {
2017 1980 qpdf_offset_t offset = entry.getOffset();
2018 1981 // Object stored in cache by readObjectAtOffset
2019   - int aobjid;
2020   - int ageneration;
2021   - QPDFObjectHandle oh = readObjectAtOffset(
2022   - true,
2023   - offset,
2024   - "",
2025   - objid,
2026   - generation,
2027   - aobjid,
2028   - ageneration);
  1982 + QPDFObjGen a_og;
  1983 + QPDFObjectHandle oh =
  1984 + readObjectAtOffset(true, offset, "", og, a_og);
2029 1985 }
2030 1986 break;
2031 1987  
... ... @@ -2039,8 +1995,7 @@ QPDF::resolve(int objid, int generation)
2039 1995 this->m->file->getName(),
2040 1996 "",
2041 1997 0,
2042   - ("object " + QUtil::int_to_string(objid) + "/" +
2043   - QUtil::int_to_string(generation) +
  1998 + ("object " + og.unparse('/') +
2044 1999 " has unexpected xref entry type"));
2045 2000 }
2046 2001 } catch (QPDFExc& e) {
... ... @@ -2050,8 +2005,7 @@ QPDF::resolve(int objid, int generation)
2050 2005 qpdf_e_damaged_pdf,
2051 2006 "",
2052 2007 0,
2053   - ("object " + QUtil::int_to_string(objid) + "/" +
2054   - QUtil::int_to_string(generation) +
  2008 + ("object " + og.unparse('/') +
2055 2009 ": error reading object: " + e.what()));
2056 2010 }
2057 2011 }
... ... @@ -2065,10 +2019,7 @@ QPDF::resolve(int objid, int generation)
2065 2019  
2066 2020 std::shared_ptr<QPDFObject> result(this->m->obj_cache[og].object);
2067 2021 if (!result->hasDescription()) {
2068   - result->setDescription(
2069   - this,
2070   - ("object " + QUtil::int_to_string(objid) + " " +
2071   - QUtil::int_to_string(generation)));
  2022 + result->setDescription(this, ("object " + og.unparse(' ')));
2072 2023 }
2073 2024 return result;
2074 2025 }
... ... @@ -2165,7 +2116,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
2165 2116 (entry.getObjStreamNumber() == obj_stream_number)) {
2166 2117 int offset = iter.second;
2167 2118 input->seek(offset, SEEK_SET);
2168   - QPDFObjectHandle oh = readObject(input, "", obj, 0, true);
  2119 + QPDFObjectHandle oh = readObject(input, "", og, true);
2169 2120 this->m->obj_cache[og] = ObjCache(
2170 2121 QPDFObjectHandle::ObjAccessor::getObject(oh),
2171 2122 end_before_space,
... ... @@ -2187,48 +2138,46 @@ QPDF::makeIndirectObject(QPDFObjectHandle oh)
2187 2138 QPDFObjGen next(max_objid + 1, 0);
2188 2139 this->m->obj_cache[next] =
2189 2140 ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
2190   - return QPDFObjectHandle::Factory::newIndirect(
2191   - this, next.getObj(), next.getGen());
  2141 + return QPDFObjectHandle::Factory::newIndirect(this, next);
2192 2142 }
2193 2143  
2194 2144 QPDFObjectHandle
2195   -QPDF::reserveObjectIfNotExists(int objid, int gen)
  2145 +QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
2196 2146 {
2197   - QPDFObjGen og(objid, gen);
2198 2147 if ((!this->m->obj_cache.count(og)) && (!this->m->xref_table.count(og))) {
2199   - resolve(objid, gen);
2200   - replaceObject(objid, gen, QPDFObjectHandle::Factory::makeReserved());
  2148 + resolve(og);
  2149 + replaceObject(og, QPDFObjectHandle::Factory::makeReserved());
2201 2150 }
2202   - return getObjectByID(objid, gen);
  2151 + return getObjectByObjGen(og);
2203 2152 }
2204 2153  
2205 2154 QPDFObjectHandle
2206   -QPDF::reserveStream(int objid, int gen)
  2155 +QPDF::reserveStream(QPDFObjGen const& og)
2207 2156 {
2208 2157 return QPDFObjectHandle::Factory::newStream(
2209   - this, objid, gen, QPDFObjectHandle::newDictionary(), 0, 0);
  2158 + this, og, QPDFObjectHandle::newDictionary(), 0, 0);
2210 2159 }
2211 2160  
2212 2161 QPDFObjectHandle
2213 2162 QPDF::getObjectByObjGen(QPDFObjGen const& og)
2214 2163 {
2215   - return getObjectByID(og.getObj(), og.getGen());
  2164 + return QPDFObjectHandle::Factory::newIndirect(this, og);
2216 2165 }
2217 2166  
2218 2167 QPDFObjectHandle
2219 2168 QPDF::getObjectByID(int objid, int generation)
2220 2169 {
2221   - return QPDFObjectHandle::Factory::newIndirect(this, objid, generation);
  2170 + return getObjectByObjGen(QPDFObjGen(objid, generation));
2222 2171 }
2223 2172  
2224 2173 void
2225   -QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
  2174 +QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
2226 2175 {
2227   - replaceObject(og.getObj(), og.getGen(), oh);
  2176 + replaceObject(QPDFObjGen(objid, generation), oh);
2228 2177 }
2229 2178  
2230 2179 void
2231   -QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
  2180 +QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
2232 2181 {
2233 2182 if (oh.isIndirect()) {
2234 2183 QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
... ... @@ -2237,10 +2186,9 @@ QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
2237 2186 }
2238 2187  
2239 2188 // Force new object to appear in the cache
2240   - resolve(objid, generation);
  2189 + resolve(og);
2241 2190  
2242 2191 // Replace the object in the object cache
2243   - QPDFObjGen og(objid, generation);
2244 2192 this->m->ever_replaced_objects = true;
2245 2193 this->m->obj_cache[og] =
2246 2194 ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
... ... @@ -2540,8 +2488,7 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
2540 2488 auto foreign_stream_data = std::make_shared<ForeignStreamData>(
2541 2489 foreign_stream_qpdf->m->encp,
2542 2490 foreign_stream_qpdf->m->file,
2543   - foreign.getObjectID(),
2544   - foreign.getGeneration(),
  2491 + foreign.getObjGen(),
2545 2492 stream->getOffset(),
2546 2493 stream->getLength(),
2547 2494 dict);
... ... @@ -2555,20 +2502,19 @@ QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign)
2555 2502 }
2556 2503  
2557 2504 void
2558   -QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2)
  2505 +QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
2559 2506 {
2560   - swapObjects(og1.getObj(), og1.getGen(), og2.getObj(), og2.getGen());
  2507 + swapObjects(
  2508 + QPDFObjGen(objid1, generation1), QPDFObjGen(objid2, generation2));
2561 2509 }
2562 2510  
2563 2511 void
2564   -QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
  2512 +QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2)
2565 2513 {
2566 2514 // Force objects to be loaded into cache; then swap them in the
2567 2515 // cache.
2568   - resolve(objid1, generation1);
2569   - resolve(objid2, generation2);
2570   - QPDFObjGen og1(objid1, generation1);
2571   - QPDFObjGen og2(objid2, generation2);
  2516 + resolve(og1);
  2517 + resolve(og2);
2572 2518 ObjCache t = this->m->obj_cache[og1];
2573 2519 this->m->ever_replaced_objects = true;
2574 2520 this->m->obj_cache[og1] = this->m->obj_cache[og2];
... ... @@ -2752,8 +2698,7 @@ QPDF::pipeStreamData(
2752 2698 std::shared_ptr<EncryptionParameters> encp,
2753 2699 std::shared_ptr<InputSource> file,
2754 2700 QPDF& qpdf_for_warning,
2755   - int objid,
2756   - int generation,
  2701 + QPDFObjGen const& og,
2757 2702 qpdf_offset_t offset,
2758 2703 size_t length,
2759 2704 QPDFObjectHandle stream_dict,
... ... @@ -2764,14 +2709,7 @@ QPDF::pipeStreamData(
2764 2709 std::vector<std::shared_ptr<Pipeline>> to_delete;
2765 2710 if (encp->encrypted) {
2766 2711 decryptStream(
2767   - encp,
2768   - file,
2769   - qpdf_for_warning,
2770   - pipeline,
2771   - objid,
2772   - generation,
2773   - stream_dict,
2774   - to_delete);
  2712 + encp, file, qpdf_for_warning, pipeline, og, stream_dict, to_delete);
2775 2713 }
2776 2714  
2777 2715 bool success = false;
... ... @@ -2809,8 +2747,7 @@ QPDF::pipeStreamData(
2809 2747 "",
2810 2748 file->getLastOffset(),
2811 2749 ("error decoding stream data for object " +
2812   - QUtil::int_to_string(objid) + " " +
2813   - QUtil::int_to_string(generation) + ": " + e.what())));
  2750 + og.unparse(' ') + ": " + e.what())));
2814 2751 if (will_retry) {
2815 2752 qpdf_for_warning.warn(
2816 2753 // line-break
... ... @@ -2836,8 +2773,7 @@ QPDF::pipeStreamData(
2836 2773  
2837 2774 bool
2838 2775 QPDF::pipeStreamData(
2839   - int objid,
2840   - int generation,
  2776 + QPDFObjGen const& og,
2841 2777 qpdf_offset_t offset,
2842 2778 size_t length,
2843 2779 QPDFObjectHandle stream_dict,
... ... @@ -2849,8 +2785,7 @@ QPDF::pipeStreamData(
2849 2785 this->m->encp,
2850 2786 this->m->file,
2851 2787 *this,
2852   - objid,
2853   - generation,
  2788 + og,
2854 2789 offset,
2855 2790 length,
2856 2791 stream_dict,
... ... @@ -2873,8 +2808,7 @@ QPDF::pipeForeignStreamData(
2873 2808 foreign->encp,
2874 2809 foreign->file,
2875 2810 *this,
2876   - foreign->foreign_objid,
2877   - foreign->foreign_generation,
  2811 + foreign->foreign_og,
2878 2812 foreign->offset,
2879 2813 foreign->length,
2880 2814 foreign->local_dict,
... ...
libqpdf/QPDFAcroFormDocumentHelper.cc
... ... @@ -991,8 +991,8 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
991 991 } else {
992 992 parent.warnIfPossible(
993 993 "while traversing field " +
994   - obj.getObjGen().unparse() + ", found parent (" +
995   - parent_og.unparse() +
  994 + obj.getObjGen().unparse(',') + ", found parent (" +
  995 + parent_og.unparse(',') +
996 996 ") that had not been seen, indicating likely"
997 997 " invalid field structure");
998 998 }
... ...
libqpdf/QPDFJob.cc
... ... @@ -49,8 +49,7 @@ namespace
49 49 size_t oi_min_area,
50 50 QPDFObjectHandle& image);
51 51 virtual ~ImageOptimizer() = default;
52   - virtual void
53   - provideStreamData(int objid, int generation, Pipeline* pipeline);
  52 + virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
54 53 std::shared_ptr<Pipeline>
55 54 makePipeline(std::string const& description, Pipeline* next);
56 55 bool evaluate(std::string const& description);
... ... @@ -250,7 +249,7 @@ ImageOptimizer::evaluate(std::string const&amp; description)
250 249 }
251 250  
252 251 void
253   -ImageOptimizer::provideStreamData(int, int, Pipeline* pipeline)
  252 +ImageOptimizer::provideStreamData(QPDFObjGen const&, Pipeline* pipeline)
254 253 {
255 254 std::shared_ptr<Pipeline> p = makePipeline("", pipeline);
256 255 if (p.get() == nullptr) {
... ... @@ -947,7 +946,7 @@ QPDFJob::doShowObj(QPDF&amp; pdf)
947 946 }
948 947 if (error) {
949 948 throw std::runtime_error(
950   - "unable to get object " + obj.getObjGen().unparse());
  949 + "unable to get object " + obj.getObjGen().unparse(','));
951 950 }
952 951 }
953 952  
... ... @@ -995,7 +994,8 @@ QPDFJob::doListAttachments(QPDF&amp; pdf)
995 994 auto efoh = i.second;
996 995 *this->m->log->getInfo()
997 996 << key << " -> "
998   - << efoh->getEmbeddedFileStream().getObjGen().unparse() << "\n";
  997 + << efoh->getEmbeddedFileStream().getObjGen().unparse(',')
  998 + << "\n";
999 999 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
1000 1000 auto desc = efoh->getDescription();
1001 1001 if (!desc.empty()) {
... ... @@ -1010,7 +1010,7 @@ QPDFJob::doListAttachments(QPDF&amp; pdf)
1010 1010 for (auto i2: efoh->getEmbeddedFileStreams().ditems()) {
1011 1011 auto efs = QPDFEFStreamObjectHelper(i2.second);
1012 1012 v << " " << i2.first << " -> "
1013   - << efs.getObjectHandle().getObjGen().unparse() << "\n";
  1013 + << efs.getObjectHandle().getObjGen().unparse(',') << "\n";
1014 1014 v << " creation date: " << efs.getCreationDate()
1015 1015 << "\n"
1016 1016 << " modification date: " << efs.getModDate() << "\n"
... ... @@ -2463,7 +2463,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF&amp; pdf)
2463 2463 QTC::TC("qpdf", "QPDFJob found resources in non-leaf");
2464 2464 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
2465 2465 v << " found resources in non-leaf page node "
2466   - << og.getObj() << " " << og.getGen() << "\n";
  2466 + << og.unparse(' ') << "\n";
2467 2467 });
2468 2468 return true;
2469 2469 }
... ... @@ -2480,9 +2480,8 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF&amp; pdf)
2480 2480 QTC::TC("qpdf", "QPDFJob found shared resources in leaf");
2481 2481 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
2482 2482 v << " found shared resources in leaf node "
2483   - << og.getObj() << " " << og.getGen() << ": "
2484   - << resources_og.getObj() << " "
2485   - << resources_og.getGen() << "\n";
  2483 + << og.unparse(' ') << ": "
  2484 + << resources_og.unparse(' ') << "\n";
2486 2485 });
2487 2486 return true;
2488 2487 }
... ... @@ -2497,8 +2496,7 @@ QPDFJob::shouldRemoveUnreferencedResources(QPDF&amp; pdf)
2497 2496 QTC::TC("qpdf", "QPDFJob found shared xobject in leaf");
2498 2497 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
2499 2498 v << " found shared xobject in leaf node "
2500   - << og.getObj() << " " << og.getGen() << ": "
2501   - << xobject_og.getObj() << " " << xobject_og.getGen()
  2499 + << og.unparse(' ') << ": " << xobject_og.unparse(' ')
2502 2500 << "\n";
2503 2501 });
2504 2502 return true;
... ... @@ -3375,7 +3373,7 @@ QPDFJob::writeJSON(QPDF&amp; pdf)
3375 3373 auto wanted = getWantedJSONObjects();
3376 3374 for (auto const& og: wanted) {
3377 3375 std::ostringstream s;
3378   - s << "obj:" << og.getObj() << " " << og.getGen() << " R";
  3376 + s << "obj:" << og.unparse(' ') << " R";
3379 3377 json_objects.insert(s.str());
3380 3378 }
3381 3379 pdf.writeJSON(
... ...
libqpdf/QPDFObjGen.cc 0 โ†’ 100644
  1 +#include <qpdf/QPDFObjGen.hh>
  2 +
  3 +#include <qpdf/QUtil.hh>
  4 +
  5 +std::ostream&
  6 +operator<<(std::ostream& os, const QPDFObjGen& og)
  7 +{
  8 + os << og.obj << "," << og.gen;
  9 + return os;
  10 +}
  11 +
  12 +std::string
  13 +QPDFObjGen::unparse(char separator) const
  14 +{
  15 + return QUtil::int_to_string(this->obj) + separator +
  16 + QUtil::int_to_string(this->gen);
  17 +}
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -53,6 +53,24 @@ QPDFObjectHandle::StreamDataProvider::~StreamDataProvider()
53 53  
54 54 void
55 55 QPDFObjectHandle::StreamDataProvider::provideStreamData(
  56 + QPDFObjGen const& og, Pipeline* pipeline)
  57 +{
  58 + return provideStreamData(og.getObj(), og.getGen(), pipeline);
  59 +}
  60 +
  61 +bool
  62 +QPDFObjectHandle::StreamDataProvider::provideStreamData(
  63 + QPDFObjGen const& og,
  64 + Pipeline* pipeline,
  65 + bool suppress_warnings,
  66 + bool will_retry)
  67 +{
  68 + return provideStreamData(
  69 + og.getObj(), og.getGen(), pipeline, suppress_warnings, will_retry);
  70 +}
  71 +
  72 +void
  73 +QPDFObjectHandle::StreamDataProvider::provideStreamData(
56 74 int objid, int generation, Pipeline* pipeline)
57 75 {
58 76 throw std::logic_error(
... ... @@ -90,8 +108,7 @@ namespace
90 108 {
91 109 }
92 110 virtual ~CoalesceProvider() = default;
93   - virtual void
94   - provideStreamData(int objid, int generation, Pipeline* pipeline);
  111 + virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
95 112  
96 113 private:
97 114 QPDFObjectHandle containing_page;
... ... @@ -100,12 +117,11 @@ namespace
100 117 } // namespace
101 118  
102 119 void
103   -CoalesceProvider::provideStreamData(int, int, Pipeline* p)
  120 +CoalesceProvider::provideStreamData(QPDFObjGen const&, Pipeline* p)
104 121 {
105 122 QTC::TC("qpdf", "QPDFObjectHandle coalesce provide stream data");
106   - std::string description = "page object " +
107   - QUtil::int_to_string(containing_page.getObjectID()) + " " +
108   - QUtil::int_to_string(containing_page.getGeneration());
  123 + std::string description =
  124 + "page object " + containing_page.getObjGen().unparse(' ');
109 125 std::string all_description;
110 126 old_contents.pipeContentStreams(p, description, all_description);
111 127 }
... ... @@ -219,27 +235,22 @@ LastChar::getLastChar()
219 235  
220 236 QPDFObjectHandle::QPDFObjectHandle() :
221 237 initialized(false),
222   - qpdf(0),
223   - objid(0),
224   - generation(0),
  238 + qpdf(nullptr),
225 239 reserved(false)
226 240 {
227 241 }
228 242  
229   -QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, int objid, int generation) :
  243 +QPDFObjectHandle::QPDFObjectHandle(QPDF* qpdf, QPDFObjGen const& og) :
230 244 initialized(true),
231 245 qpdf(qpdf),
232   - objid(objid),
233   - generation(generation),
  246 + og(og),
234 247 reserved(false)
235 248 {
236 249 }
237 250  
238 251 QPDFObjectHandle::QPDFObjectHandle(std::shared_ptr<QPDFObject> const& data) :
239 252 initialized(true),
240   - qpdf(0),
241   - objid(0),
242   - generation(0),
  253 + qpdf(nullptr),
243 254 obj(data),
244 255 reserved(false)
245 256 {
... ... @@ -1431,15 +1442,14 @@ namespace
1431 1442 }
1432 1443  
1433 1444 virtual void
1434   - provideStreamData(int, int, Pipeline* pipeline) override
  1445 + provideStreamData(QPDFObjGen const&, Pipeline* pipeline) override
1435 1446 {
1436 1447 p1(pipeline);
1437 1448 }
1438 1449  
1439 1450 virtual bool
1440 1451 provideStreamData(
1441   - int,
1442   - int,
  1452 + QPDFObjGen const&,
1443 1453 Pipeline* pipeline,
1444 1454 bool suppress_warnings,
1445 1455 bool will_retry) override
... ... @@ -1482,26 +1492,19 @@ QPDFObjectHandle::replaceStreamData(
1482 1492 QPDFObjGen
1483 1493 QPDFObjectHandle::getObjGen() const
1484 1494 {
1485   - return QPDFObjGen(this->objid, this->generation);
1486   -}
1487   -
1488   -std::string
1489   -QPDFObjectHandle::getObjGenAsStr() const
1490   -{
1491   - return QUtil::int_to_string(this->objid) + " " +
1492   - QUtil::int_to_string(this->generation);
  1495 + return og;
1493 1496 }
1494 1497  
1495 1498 int
1496 1499 QPDFObjectHandle::getObjectID() const
1497 1500 {
1498   - return this->objid;
  1501 + return og.getObj();
1499 1502 }
1500 1503  
1501 1504 int
1502 1505 QPDFObjectHandle::getGeneration() const
1503 1506 {
1504   - return this->generation;
  1507 + return og.getGen();
1505 1508 }
1506 1509  
1507 1510 std::map<std::string, QPDFObjectHandle>
... ... @@ -1556,7 +1559,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
1556 1559 } else {
1557 1560 all_description += ",";
1558 1561 }
1559   - all_description += " stream " + item.getObjGenAsStr();
  1562 + all_description += " stream " + item.getObjGen().unparse(' ');
1560 1563 }
1561 1564  
1562 1565 return result;
... ... @@ -1565,7 +1568,7 @@ QPDFObjectHandle::arrayOrStreamToStreamArray(
1565 1568 std::vector<QPDFObjectHandle>
1566 1569 QPDFObjectHandle::getPageContents()
1567 1570 {
1568   - std::string description = "page object " + getObjGenAsStr();
  1571 + std::string description = "page object " + getObjGen().unparse(' ');
1569 1572 std::string all_description;
1570 1573 return this->getKey("/Contents")
1571 1574 .arrayOrStreamToStreamArray(description, all_description);
... ... @@ -1674,7 +1677,7 @@ QPDFObjectHandle::unparse()
1674 1677 {
1675 1678 std::string result;
1676 1679 if (this->isIndirect()) {
1677   - result = getObjGenAsStr() + " R";
  1680 + result = getObjGen().unparse(' ') + " R";
1678 1681 } else {
1679 1682 result = unparseResolved();
1680 1683 }
... ... @@ -1789,7 +1792,7 @@ QPDFObjectHandle::parse(
1789 1792 void
1790 1793 QPDFObjectHandle::pipePageContents(Pipeline* p)
1791 1794 {
1792   - std::string description = "page object " + getObjGenAsStr();
  1795 + std::string description = "page object " + getObjGen().unparse(' ');
1793 1796 std::string all_description;
1794 1797 this->getKey("/Contents")
1795 1798 .pipeContentStreams(p, description, all_description);
... ... @@ -1813,7 +1816,7 @@ QPDFObjectHandle::pipeContentStreams(
1813 1816 throw QPDFExc(
1814 1817 qpdf_e_damaged_pdf,
1815 1818 "content stream",
1816   - "content stream object " + stream.getObjGenAsStr(),
  1819 + "content stream object " + stream.getObjGen().unparse(' '),
1817 1820 0,
1818 1821 "errors while decoding content stream");
1819 1822 }
... ... @@ -1829,7 +1832,7 @@ QPDFObjectHandle::pipeContentStreams(
1829 1832 void
1830 1833 QPDFObjectHandle::parsePageContents(ParserCallbacks* callbacks)
1831 1834 {
1832   - std::string description = "page object " + getObjGenAsStr();
  1835 + std::string description = "page object " + getObjGen().unparse(' ');
1833 1836 this->getKey("/Contents")
1834 1837 .parseContentStream_internal(description, callbacks);
1835 1838 }
... ... @@ -1837,14 +1840,15 @@ QPDFObjectHandle::parsePageContents(ParserCallbacks* callbacks)
1837 1840 void
1838 1841 QPDFObjectHandle::parseAsContents(ParserCallbacks* callbacks)
1839 1842 {
1840   - std::string description = "object " + getObjGenAsStr();
  1843 + std::string description = "object " + getObjGen().unparse(' ');
1841 1844 this->parseContentStream_internal(description, callbacks);
1842 1845 }
1843 1846  
1844 1847 void
1845 1848 QPDFObjectHandle::filterPageContents(TokenFilter* filter, Pipeline* next)
1846 1849 {
1847   - auto description = "token filter for page object " + getObjGenAsStr();
  1850 + auto description =
  1851 + "token filter for page object " + getObjGen().unparse(' ');
1848 1852 Pl_QPDFTokenizer token_pipeline(description.c_str(), filter, next);
1849 1853 this->pipePageContents(&token_pipeline);
1850 1854 }
... ... @@ -1852,7 +1856,7 @@ QPDFObjectHandle::filterPageContents(TokenFilter* filter, Pipeline* next)
1852 1856 void
1853 1857 QPDFObjectHandle::filterAsContents(TokenFilter* filter, Pipeline* next)
1854 1858 {
1855   - auto description = "token filter for object " + getObjGenAsStr();
  1859 + auto description = "token filter for object " + getObjGen().unparse(' ');
1856 1860 Pl_QPDFTokenizer token_pipeline(description.c_str(), filter, next);
1857 1861 this->pipeStreamData(&token_pipeline, 0, qpdf_dl_specialized);
1858 1862 }
... ... @@ -2192,8 +2196,9 @@ QPDFObjectHandle::parseInternal(
2192 2196 // Try to resolve indirect objects
2193 2197 object = newIndirect(
2194 2198 context,
2195   - olist.at(olist.size() - 2).getIntValueAsInt(),
2196   - olist.at(olist.size() - 1).getIntValueAsInt());
  2199 + QPDFObjGen(
  2200 + olist.at(olist.size() - 2).getIntValueAsInt(),
  2201 + olist.at(olist.size() - 1).getIntValueAsInt()));
2197 2202 olist.remove_last();
2198 2203 olist.remove_last();
2199 2204 } else if ((value == "endobj") && (state == st_top)) {
... ... @@ -2481,9 +2486,9 @@ QPDFObjectHandle::setParsedOffset(qpdf_offset_t offset)
2481 2486 }
2482 2487  
2483 2488 QPDFObjectHandle
2484   -QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation)
  2489 +QPDFObjectHandle::newIndirect(QPDF* qpdf, QPDFObjGen const& og)
2485 2490 {
2486   - if (objid == 0) {
  2491 + if (!og.isIndirect()) {
2487 2492 // Special case: QPDF uses objid 0 as a sentinel for direct
2488 2493 // objects, and the PDF specification doesn't allow for object
2489 2494 // 0. Treat indirect references to object 0 as null so that we
... ... @@ -2492,7 +2497,7 @@ QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation)
2492 2497 return newNull();
2493 2498 }
2494 2499  
2495   - return QPDFObjectHandle(qpdf, objid, generation);
  2500 + return QPDFObjectHandle(qpdf, og);
2496 2501 }
2497 2502  
2498 2503 QPDFObjectHandle
... ... @@ -2640,14 +2645,13 @@ QPDFObjectHandle::newDictionary(
2640 2645 QPDFObjectHandle
2641 2646 QPDFObjectHandle::newStream(
2642 2647 QPDF* qpdf,
2643   - int objid,
2644   - int generation,
  2648 + QPDFObjGen const& og,
2645 2649 QPDFObjectHandle stream_dict,
2646 2650 qpdf_offset_t offset,
2647 2651 size_t length)
2648 2652 {
2649   - QPDFObjectHandle result = QPDFObjectHandle(QPDF_Stream::create(
2650   - qpdf, objid, generation, stream_dict, offset, length));
  2653 + QPDFObjectHandle result = QPDFObjectHandle(
  2654 + QPDF_Stream::create(qpdf, og, stream_dict, offset, length));
2651 2655 if (offset) {
2652 2656 result.setParsedOffset(offset);
2653 2657 }
... ... @@ -2663,11 +2667,11 @@ QPDFObjectHandle::newStream(QPDF* qpdf)
2663 2667 }
2664 2668 QTC::TC("qpdf", "QPDFObjectHandle newStream");
2665 2669 QPDFObjectHandle stream_dict = newDictionary();
2666   - QPDFObjectHandle result = qpdf->makeIndirectObject(
2667   - QPDFObjectHandle(QPDF_Stream::create(qpdf, 0, 0, stream_dict, 0, 0)));
  2670 + QPDFObjectHandle result = qpdf->makeIndirectObject(QPDFObjectHandle(
  2671 + QPDF_Stream::create(qpdf, QPDFObjGen(), stream_dict, 0, 0)));
2668 2672 result.dereference();
2669 2673 QPDF_Stream* stream = dynamic_cast<QPDF_Stream*>(result.obj.get());
2670   - stream->setObjGen(result.getObjectID(), result.getGeneration());
  2674 + stream->setObjGen(result.getObjGen());
2671 2675 return result;
2672 2676 }
2673 2677  
... ... @@ -2695,8 +2699,7 @@ QPDFObjectHandle::newReserved(QPDF* qpdf)
2695 2699 // Reserve a spot for this object by assigning it an object
2696 2700 // number, but then return an unresolved handle to the object.
2697 2701 QPDFObjectHandle reserved = qpdf->makeIndirectObject(makeReserved());
2698   - QPDFObjectHandle result =
2699   - newIndirect(qpdf, reserved.objid, reserved.generation);
  2702 + QPDFObjectHandle result = newIndirect(qpdf, reserved.getObjGen());
2700 2703 result.reserved = true;
2701 2704 return result;
2702 2705 }
... ... @@ -2796,9 +2799,8 @@ QPDFObjectHandle::copyObject(
2796 2799 " reserved object handle direct");
2797 2800 }
2798 2801  
2799   - this->qpdf = 0;
2800   - this->objid = 0;
2801   - this->generation = 0;
  2802 + qpdf = nullptr;
  2803 + og = QPDFObjGen();
2802 2804  
2803 2805 std::shared_ptr<QPDFObject> new_obj;
2804 2806  
... ... @@ -3112,7 +3114,7 @@ QPDFObjectHandle::dereference()
3112 3114 }
3113 3115 if (this->obj.get() == 0) {
3114 3116 std::shared_ptr<QPDFObject> obj =
3115   - QPDF::Resolver::resolve(this->qpdf, getObjectID(), getGeneration());
  3117 + QPDF::Resolver::resolve(this->qpdf, getObjGen());
3116 3118 if (obj.get() == 0) {
3117 3119 // QPDF::resolve never returns an uninitialized object, but
3118 3120 // check just in case.
... ...
libqpdf/QPDFPageObjectHelper.cc
... ... @@ -21,8 +21,7 @@ namespace
21 21 {
22 22 }
23 23 virtual ~ContentProvider() = default;
24   - virtual void
25   - provideStreamData(int objid, int generation, Pipeline* pipeline);
  24 + virtual void provideStreamData(QPDFObjGen const&, Pipeline* pipeline);
26 25  
27 26 private:
28 27 QPDFObjectHandle from_page;
... ... @@ -30,12 +29,11 @@ namespace
30 29 } // namespace
31 30  
32 31 void
33   -ContentProvider::provideStreamData(int, int, Pipeline* p)
  32 +ContentProvider::provideStreamData(QPDFObjGen const&, Pipeline* p)
34 33 {
35 34 Pl_Concatenate concat("concatenate", p);
36   - std::string description = "contents from page object " +
37   - QUtil::int_to_string(from_page.getObjectID()) + " " +
38   - QUtil::int_to_string(from_page.getGeneration());
  35 + std::string description =
  36 + "contents from page object " + from_page.getObjGen().unparse(' ');
39 37 std::string all_description;
40 38 from_page.getKey("/Contents")
41 39 .pipeContentStreams(&concat, description, all_description);
... ...
libqpdf/QPDFWriter.cc
... ... @@ -1990,9 +1990,8 @@ QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index)
1990 1990 if (object_stream_index == -1) {
1991 1991 if (this->m->qdf_mode && (!this->m->suppress_original_object_ids)) {
1992 1992 writeString(
1993   - "%% Original object ID: " +
1994   - QUtil::int_to_string(object.getObjectID()) + " " +
1995   - QUtil::int_to_string(object.getGeneration()) + "\n");
  1993 + "%% Original object ID: " + object.getObjGen().unparse(' ') +
  1994 + "\n");
1996 1995 }
1997 1996 openObject(new_id);
1998 1997 setDataKey(new_id);
... ...
libqpdf/QPDF_Stream.cc
... ... @@ -110,14 +110,12 @@ StreamBlobProvider::operator()(Pipeline* p)
110 110  
111 111 QPDF_Stream::QPDF_Stream(
112 112 QPDF* qpdf,
113   - int objid,
114   - int generation,
  113 + QPDFObjGen const& og,
115 114 QPDFObjectHandle stream_dict,
116 115 qpdf_offset_t offset,
117 116 size_t length) :
118 117 qpdf(qpdf),
119   - objid(objid),
120   - generation(generation),
  118 + og(og),
121 119 filter_on_write(true),
122 120 stream_dict(stream_dict),
123 121 offset(offset),
... ... @@ -128,23 +126,18 @@ QPDF_Stream::QPDF_Stream(
128 126 "object for dictionary");
129 127 }
130 128 setDescription(
131   - this->qpdf,
132   - this->qpdf->getFilename() + ", stream object " +
133   - QUtil::int_to_string(this->objid) + " " +
134   - QUtil::int_to_string(this->generation));
  129 + qpdf, qpdf->getFilename() + ", stream object " + og.unparse(' '));
135 130 }
136 131  
137 132 std::shared_ptr<QPDFObject>
138 133 QPDF_Stream::create(
139 134 QPDF* qpdf,
140   - int objid,
141   - int generation,
  135 + QPDFObjGen const& og,
142 136 QPDFObjectHandle stream_dict,
143 137 qpdf_offset_t offset,
144 138 size_t length)
145 139 {
146   - return do_create(
147   - new QPDF_Stream(qpdf, objid, generation, stream_dict, offset, length));
  140 + return do_create(new QPDF_Stream(qpdf, og, stream_dict, offset, length));
148 141 }
149 142  
150 143 std::shared_ptr<QPDFObject>
... ... @@ -181,23 +174,21 @@ QPDF_Stream::releaseResolved()
181 174 }
182 175  
183 176 void
184   -QPDF_Stream::setObjGen(int objid, int generation)
  177 +QPDF_Stream::setObjGen(QPDFObjGen const& og)
185 178 {
186   - if (!((this->objid == 0) && (this->generation == 0))) {
  179 + if (this->og.isIndirect()) {
187 180 throw std::logic_error(
188 181 "attempt to set object ID and generation of a stream"
189 182 " that already has them");
190 183 }
191   - this->objid = objid;
192   - this->generation = generation;
  184 + this->og = og;
193 185 }
194 186  
195 187 std::string
196 188 QPDF_Stream::unparse()
197 189 {
198 190 // Unparse stream objects as indirect references
199   - return QUtil::int_to_string(this->objid) + " " +
200   - QUtil::int_to_string(this->generation) + " R";
  191 + return og.unparse(' ') + " R";
201 192 }
202 193  
203 194 JSON
... ... @@ -619,17 +610,12 @@ QPDF_Stream::pipeStreamData(
619 610 Pl_Count count("stream provider count", pipeline);
620 611 if (this->stream_provider->supportsRetry()) {
621 612 if (!this->stream_provider->provideStreamData(
622   - this->objid,
623   - this->generation,
624   - &count,
625   - suppress_warnings,
626   - will_retry)) {
  613 + og, &count, suppress_warnings, will_retry)) {
627 614 filter = false;
628 615 success = false;
629 616 }
630 617 } else {
631   - this->stream_provider->provideStreamData(
632   - this->objid, this->generation, &count);
  618 + this->stream_provider->provideStreamData(og, &count);
633 619 }
634 620 qpdf_offset_t actual_length = count.getCount();
635 621 qpdf_offset_t desired_length = 0;
... ... @@ -642,10 +628,8 @@ QPDF_Stream::pipeStreamData(
642 628 // This would be caused by programmer error on the
643 629 // part of a library user, not by invalid input data.
644 630 throw std::runtime_error(
645   - "stream data provider for " +
646   - QUtil::int_to_string(this->objid) + " " +
647   - QUtil::int_to_string(this->generation) + " provided " +
648   - QUtil::int_to_string(actual_length) +
  631 + "stream data provider for " + og.unparse(' ') +
  632 + " provided " + QUtil::int_to_string(actual_length) +
649 633 " bytes instead of expected " +
650 634 QUtil::int_to_string(desired_length) + " bytes");
651 635 }
... ... @@ -661,8 +645,7 @@ QPDF_Stream::pipeStreamData(
661 645 QTC::TC("qpdf", "QPDF_Stream pipe original stream data");
662 646 if (!QPDF::Pipe::pipeStreamData(
663 647 this->qpdf,
664   - this->objid,
665   - this->generation,
  648 + og,
666 649 this->offset,
667 650 this->length,
668 651 this->stream_dict,
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -1075,8 +1075,7 @@ QPDF::initializeEncryption()
1075 1075 std::string
1076 1076 QPDF::getKeyForObject(
1077 1077 std::shared_ptr<EncryptionParameters> encp,
1078   - int objid,
1079   - int generation,
  1078 + QPDFObjGen const& og,
1080 1079 bool use_aes)
1081 1080 {
1082 1081 if (!encp->encrypted) {
... ... @@ -1084,26 +1083,24 @@ QPDF::getKeyForObject(
1084 1083 "request for encryption key in non-encrypted PDF");
1085 1084 }
1086 1085  
1087   - if (!((objid == encp->cached_key_objid) &&
1088   - (generation == encp->cached_key_generation))) {
  1086 + if (og != encp->cached_key_og) {
1089 1087 encp->cached_object_encryption_key = compute_data_key(
1090 1088 encp->encryption_key,
1091   - objid,
1092   - generation,
  1089 + og.getObj(),
  1090 + og.getGen(),
1093 1091 use_aes,
1094 1092 encp->encryption_V,
1095 1093 encp->encryption_R);
1096   - encp->cached_key_objid = objid;
1097   - encp->cached_key_generation = generation;
  1094 + encp->cached_key_og = og;
1098 1095 }
1099 1096  
1100 1097 return encp->cached_object_encryption_key;
1101 1098 }
1102 1099  
1103 1100 void
1104   -QPDF::decryptString(std::string& str, int objid, int generation)
  1101 +QPDF::decryptString(std::string& str, QPDFObjGen const& og)
1105 1102 {
1106   - if (objid == 0) {
  1103 + if (!og.isIndirect()) {
1107 1104 return;
1108 1105 }
1109 1106 bool use_aes = false;
... ... @@ -1139,8 +1136,7 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation)
1139 1136 }
1140 1137 }
1141 1138  
1142   - std::string key =
1143   - getKeyForObject(this->m->encp, objid, generation, use_aes);
  1139 + std::string key = getKeyForObject(this->m->encp, og, use_aes);
1144 1140 try {
1145 1141 if (use_aes) {
1146 1142 QTC::TC("qpdf", "QPDF_encryption aes decode string");
... ... @@ -1175,9 +1171,8 @@ QPDF::decryptString(std::string&amp; str, int objid, int generation)
1175 1171 this->m->file->getName(),
1176 1172 this->m->last_object_description,
1177 1173 this->m->file->getLastOffset(),
1178   - "error decrypting string for object " +
1179   - QUtil::int_to_string(objid) + " " +
1180   - QUtil::int_to_string(generation) + ": " + e.what());
  1174 + "error decrypting string for object " + og.unparse() + ": " +
  1175 + e.what());
1181 1176 }
1182 1177 }
1183 1178  
... ... @@ -1187,8 +1182,7 @@ QPDF::decryptStream(
1187 1182 std::shared_ptr<InputSource> file,
1188 1183 QPDF& qpdf_for_warning,
1189 1184 Pipeline*& pipeline,
1190   - int objid,
1191   - int generation,
  1185 + QPDFObjGen const& og,
1192 1186 QPDFObjectHandle& stream_dict,
1193 1187 std::vector<std::shared_ptr<Pipeline>>& heap)
1194 1188 {
... ... @@ -1283,7 +1277,7 @@ QPDF::decryptStream(
1283 1277 break;
1284 1278 }
1285 1279 }
1286   - std::string key = getKeyForObject(encp, objid, generation, use_aes);
  1280 + std::string key = getKeyForObject(encp, og, use_aes);
1287 1281 std::shared_ptr<Pipeline> new_pipeline;
1288 1282 if (use_aes) {
1289 1283 QTC::TC("qpdf", "QPDF_encryption aes decode stream");
... ...
libqpdf/QPDF_json.cc
... ... @@ -371,9 +371,10 @@ QPDF::JSONReactor::containerEnd(JSON const&amp; value)
371 371 QPDFObjectHandle
372 372 QPDF::JSONReactor::reserveObject(int obj, int gen)
373 373 {
374   - auto oh = pdf.reserveObjectIfNotExists(obj, gen);
  374 + QPDFObjGen og(obj, gen);
  375 + auto oh = pdf.reserveObjectIfNotExists(og);
375 376 if (oh.isReserved()) {
376   - this->reserved.insert(QPDFObjGen(obj, gen));
  377 + this->reserved.insert(og);
377 378 }
378 379 return oh;
379 380 }
... ... @@ -495,8 +496,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
495 496 QTC::TC("qpdf", "QPDF_json updating existing stream");
496 497 } else {
497 498 this->this_stream_needs_data = true;
498   - replacement =
499   - pdf.reserveStream(tos.getObjectID(), tos.getGeneration());
  499 + replacement = pdf.reserveStream(tos.getObjGen());
500 500 replaceObject(tos, replacement, value);
501 501 }
502 502 } else {
... ...
libqpdf/QPDF_linearization.cc
... ... @@ -137,8 +137,8 @@ QPDF::isLinearized()
137 137 return false;
138 138 }
139 139  
140   - QPDFObjectHandle candidate =
141   - QPDFObjectHandle::Factory::newIndirect(this, lindict_obj, 0);
  140 + QPDFObjectHandle candidate = QPDFObjectHandle::Factory::newIndirect(
  141 + this, QPDFObjGen(lindict_obj, 0));
142 142 if (!candidate.isDictionary()) {
143 143 return false;
144 144 }
... ... @@ -325,11 +325,10 @@ QPDF::readLinearizationData()
325 325 QPDFObjectHandle
326 326 QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length)
327 327 {
328   - int obj;
329   - int gen;
  328 + QPDFObjGen og;
330 329 QPDFObjectHandle H = readObjectAtOffset(
331   - false, offset, "linearization hint stream", 0, 0, obj, gen);
332   - ObjCache& oc = this->m->obj_cache[QPDFObjGen(obj, gen)];
  330 + false, offset, "linearization hint stream", QPDFObjGen(0, 0), og);
  331 + ObjCache& oc = this->m->obj_cache[og];
333 332 qpdf_offset_t min_end_offset = oc.end_before_space;
334 333 qpdf_offset_t max_end_offset = oc.end_after_space;
335 334 if (!H.isStream()) {
... ... @@ -707,7 +706,7 @@ QPDF::getUncompressedObject(
707 706 return obj;
708 707 } else {
709 708 int repl = (*(object_stream_data.find(obj.getObjectID()))).second;
710   - return objGenToIndirect(QPDFObjGen(repl, 0));
  709 + return getObjectByObjGen(QPDFObjGen(repl, 0));
711 710 }
712 711 }
713 712  
... ... @@ -1144,12 +1143,6 @@ QPDF::dumpHGeneric(HGeneric&amp; t)
1144 1143 << "group_length: " << t.group_length << "\n";
1145 1144 }
1146 1145  
1147   -QPDFObjectHandle
1148   -QPDF::objGenToIndirect(QPDFObjGen const& og)
1149   -{
1150   - return getObjectByID(og.getObj(), og.getGen());
1151   -}
1152   -
1153 1146 void
1154 1147 QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
1155 1148 {
... ... @@ -1388,9 +1381,9 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1388 1381 stopOnError("found other than one root while"
1389 1382 " calculating linearization data");
1390 1383 }
1391   - this->m->part4.push_back(objGenToIndirect(*(lc_root.begin())));
  1384 + this->m->part4.push_back(getObjectByObjGen(*(lc_root.begin())));
1392 1385 for (auto const& og: lc_open_document) {
1393   - this->m->part4.push_back(objGenToIndirect(og));
  1386 + this->m->part4.push_back(getObjectByObjGen(og));
1394 1387 }
1395 1388  
1396 1389 // Part 6: first page objects. Note: implementation note 124
... ... @@ -1419,11 +1412,11 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1419 1412 // hint tables.
1420 1413  
1421 1414 for (auto const& og: lc_first_page_private) {
1422   - this->m->part6.push_back(objGenToIndirect(og));
  1415 + this->m->part6.push_back(getObjectByObjGen(og));
1423 1416 }
1424 1417  
1425 1418 for (auto const& og: lc_first_page_shared) {
1426   - this->m->part6.push_back(objGenToIndirect(og));
  1419 + this->m->part6.push_back(getObjectByObjGen(og));
1427 1420 }
1428 1421  
1429 1422 // Place the outline dictionary if it goes in the first page section.
... ... @@ -1469,7 +1462,7 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1469 1462 for (auto const& og: this->m->obj_user_to_objects[ou]) {
1470 1463 if (lc_other_page_private.count(og)) {
1471 1464 lc_other_page_private.erase(og);
1472   - this->m->part7.push_back(objGenToIndirect(og));
  1465 + this->m->part7.push_back(getObjectByObjGen(og));
1473 1466 ++this->m->c_page_offset_data.entries.at(i).nobjects;
1474 1467 }
1475 1468 }
... ... @@ -1486,7 +1479,7 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1486 1479  
1487 1480 // Order is unimportant.
1488 1481 for (auto const& og: lc_other_page_shared) {
1489   - this->m->part8.push_back(objGenToIndirect(og));
  1482 + this->m->part8.push_back(getObjectByObjGen(og));
1490 1483 }
1491 1484  
1492 1485 // Part 9: other objects
... ... @@ -1508,7 +1501,7 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1508 1501 for (auto const& og: pages_ogs) {
1509 1502 if (lc_other.count(og)) {
1510 1503 lc_other.erase(og);
1511   - this->m->part9.push_back(objGenToIndirect(og));
  1504 + this->m->part9.push_back(getObjectByObjGen(og));
1512 1505 }
1513 1506 }
1514 1507  
... ... @@ -1538,7 +1531,7 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1538 1531 for (auto const& og: ogs) {
1539 1532 if (lc_thumbnail_private.count(og)) {
1540 1533 lc_thumbnail_private.erase(og);
1541   - this->m->part9.push_back(objGenToIndirect(og));
  1534 + this->m->part9.push_back(getObjectByObjGen(og));
1542 1535 }
1543 1536 }
1544 1537 }
... ... @@ -1551,7 +1544,7 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1551 1544  
1552 1545 // Place shared thumbnail objects
1553 1546 for (auto const& og: lc_thumbnail_shared) {
1554   - this->m->part9.push_back(objGenToIndirect(og));
  1547 + this->m->part9.push_back(getObjectByObjGen(og));
1555 1548 }
1556 1549  
1557 1550 // Place outlines unless in first page
... ... @@ -1561,7 +1554,7 @@ QPDF::calculateLinearizationData(std::map&lt;int, int&gt; const&amp; object_stream_data)
1561 1554  
1562 1555 // Place all remaining objects
1563 1556 for (auto const& og: lc_other) {
1564   - this->m->part9.push_back(objGenToIndirect(og));
  1557 + this->m->part9.push_back(getObjectByObjGen(og));
1565 1558 }
1566 1559  
1567 1560 // Make sure we got everything exactly once.
... ... @@ -1663,7 +1656,7 @@ QPDF::pushOutlinesToPart(
1663 1656 lc_outlines.erase(outlines_og);
1664 1657 part.push_back(outlines);
1665 1658 for (auto const& og: lc_outlines) {
1666   - part.push_back(objGenToIndirect(og));
  1659 + part.push_back(getObjectByObjGen(og));
1667 1660 ++this->m->c_outline_data.nobjects;
1668 1661 }
1669 1662 }
... ...
libqpdf/QPDF_optimization.cc
... ... @@ -252,9 +252,7 @@ QPDF::pushInheritedAttributesToPageInternal(
252 252 if ((warn_skipped_keys) && (cur_pages.hasKey("/Parent"))) {
253 253 QTC::TC("qpdf", "QPDF unknown key not inherited");
254 254 setLastObjectDescription(
255   - "Pages object",
256   - cur_pages.getObjectID(),
257   - cur_pages.getGeneration());
  255 + "Pages object", cur_pages.getObjGen());
258 256 warn(
259 257 qpdf_e_pages,
260 258 this->m->last_object_description,
... ...
libqpdf/QPDF_pages.cc
... ... @@ -207,8 +207,7 @@ QPDF::insertPageobjToPage(
207 207 // that causes this to happen.
208 208 setLastObjectDescription(
209 209 "page " + QUtil::int_to_string(pos) + " (numbered from zero)",
210   - og.getObj(),
211   - og.getGen());
  210 + og);
212 211 throw QPDFExc(
213 212 qpdf_e_pages,
214 213 this->m->file->getName(),
... ... @@ -334,7 +333,7 @@ QPDF::findPage(QPDFObjGen const&amp; og)
334 333 auto it = this->m->pageobj_to_pages_pos.find(og);
335 334 if (it == this->m->pageobj_to_pages_pos.end()) {
336 335 QTC::TC("qpdf", "QPDF_pages findPage not found");
337   - setLastObjectDescription("page object", og.getObj(), og.getGen());
  336 + setLastObjectDescription("page object", og);
338 337 throw QPDFExc(
339 338 qpdf_e_pages,
340 339 this->m->file->getName(),
... ...
libqpdf/qpdf/QPDF_Stream.hh
... ... @@ -19,8 +19,7 @@ class QPDF_Stream: public QPDFObject
19 19 virtual ~QPDF_Stream() = default;
20 20 static std::shared_ptr<QPDFObject> create(
21 21 QPDF*,
22   - int objid,
23   - int generation,
  22 + QPDFObjGen const& og,
24 23 QPDFObjectHandle stream_dict,
25 24 qpdf_offset_t offset,
26 25 size_t length);
... ... @@ -78,7 +77,7 @@ class QPDF_Stream: public QPDFObject
78 77 // Replace object ID and generation. This may only be called if
79 78 // object ID and generation are 0. It is used by QPDFObjectHandle
80 79 // when adding streams to files.
81   - void setObjGen(int objid, int generation);
  80 + void setObjGen(QPDFObjGen const& og);
82 81  
83 82 protected:
84 83 virtual void releaseResolved();
... ... @@ -86,8 +85,7 @@ class QPDF_Stream: public QPDFObject
86 85 private:
87 86 QPDF_Stream(
88 87 QPDF*,
89   - int objid,
90   - int generation,
  88 + QPDFObjGen const& og,
91 89 QPDFObjectHandle stream_dict,
92 90 qpdf_offset_t offset,
93 91 size_t length);
... ... @@ -111,8 +109,7 @@ class QPDF_Stream: public QPDFObject
111 109 void setDictDescription();
112 110  
113 111 QPDF* qpdf;
114   - int objid;
115   - int generation;
  112 + QPDFObjGen og;
116 113 bool filter_on_write;
117 114 QPDFObjectHandle stream_dict;
118 115 qpdf_offset_t offset;
... ...
qpdf/test_driver.cc
... ... @@ -56,6 +56,8 @@ class Provider: public QPDFObjectHandle::StreamDataProvider
56 56 virtual void
57 57 provideStreamData(int objid, int generation, Pipeline* p)
58 58 {
  59 + // Don't change signature to use QPDFObjGen const& to detect
  60 + // problems forwarding to legacy implementations.
59 61 p->write(b->getBuffer(), b->getSize());
60 62 if (this->bad_length) {
61 63 unsigned char ch = ' ';
... ...