Commit 5a8ba44bea776212d5b9f79fa7c826e6a9a944fc

Authored by m-holger
Committed by GitHub
2 parents 4ba6377f 306e8093

Merge pull request #1558 from m-holger/qpdf_hh

Remove implementation detail from QPDF header file
include/qpdf/QPDF.hh
... ... @@ -787,18 +787,6 @@ class QPDF
787 787 bool is_root_metadata,
788 788 std::unique_ptr<Pipeline>& heap);
789 789  
790   - struct HPageOffsetEntry;
791   - struct HPageOffset;
792   - struct HSharedObjectEntry;
793   - struct HSharedObject;
794   - struct HGeneric;
795   - struct LinParameters;
796   - struct CHPageOffsetEntry;
797   - struct CHPageOffset;
798   - struct CHSharedObjectEntry;
799   - struct CHSharedObject;
800   - class ObjUser;
801   - struct UpdateObjectMapsFrame;
802 790 class PatternFinder;
803 791  
804 792 // Methods to support pattern finding
... ...
include/qpdf/QPDFJob.hh
... ... @@ -460,7 +460,6 @@ class QPDFJob
460 460 bool main_input);
461 461  
462 462 // Transformations
463   - void setQPDFOptions(QPDF& pdf);
464 463 void handlePageSpecs(QPDF& pdf);
465 464 bool shouldRemoveUnreferencedResources(QPDF& pdf);
466 465 void handleRotations(QPDF& pdf);
... ...
libqpdf/QPDF.cc
... ... @@ -27,9 +27,9 @@
27 27 using namespace qpdf;
28 28 using namespace std::literals;
29 29  
30   -using Doc = QPDF::Doc;
31   -using Common = Doc::Common;
32   -using Objects = Doc::Objects;
  30 +using QDoc = QPDF::Doc;
  31 +using Common = QDoc::Common;
  32 +using Objects = QDoc::Objects;
33 33 using Foreign = Objects::Foreign;
34 34 using Streams = Objects::Streams;
35 35  
... ... @@ -133,7 +133,6 @@ QPDF::Members::Members(QPDF&amp; qpdf) :
133 133 lin(*this),
134 134 objects(*this),
135 135 pages(*this),
136   - log(QPDFLogger::defaultLogger()),
137 136 file(std::make_shared<InvalidInputSource>()),
138 137 encp(std::make_shared<EncryptionParameters>())
139 138 {
... ... @@ -232,7 +231,7 @@ QPDF::closeInputSource()
232 231 void
233 232 QPDF::setPasswordIsHexKey(bool val)
234 233 {
235   - m->provided_password_is_hex_key = val;
  234 + m->cf.password_is_hex_key(val);
236 235 }
237 236  
238 237 void
... ... @@ -251,56 +250,56 @@ QPDF::registerStreamFilter(
251 250 void
252 251 QPDF::setIgnoreXRefStreams(bool val)
253 252 {
254   - m->ignore_xref_streams = val;
  253 + (void)m->cf.ignore_xref_streams(val);
255 254 }
256 255  
257 256 std::shared_ptr<QPDFLogger>
258 257 QPDF::getLogger()
259 258 {
260   - return m->log;
  259 + return m->cf.log();
261 260 }
262 261  
263 262 void
264 263 QPDF::setLogger(std::shared_ptr<QPDFLogger> l)
265 264 {
266   - m->log = l;
  265 + m->cf.log(l);
267 266 }
268 267  
269 268 void
270 269 QPDF::setOutputStreams(std::ostream* out, std::ostream* err)
271 270 {
272 271 setLogger(QPDFLogger::create());
273   - m->log->setOutputStreams(out, err);
  272 + m->cf.log()->setOutputStreams(out, err);
274 273 }
275 274  
276 275 void
277 276 QPDF::setSuppressWarnings(bool val)
278 277 {
279   - m->suppress_warnings = val;
  278 + (void)m->cf.suppress_warnings(val);
280 279 }
281 280  
282 281 void
283 282 QPDF::setMaxWarnings(size_t val)
284 283 {
285   - m->max_warnings = val;
  284 + (void)m->cf.max_warnings(val);
286 285 }
287 286  
288 287 void
289 288 QPDF::setAttemptRecovery(bool val)
290 289 {
291   - m->attempt_recovery = val;
  290 + (void)m->cf.surpress_recovery(!val);
292 291 }
293 292  
294 293 void
295 294 QPDF::setImmediateCopyFrom(bool val)
296 295 {
297   - m->immediate_copy_from = val;
  296 + (void)m->cf.immediate_copy_from(val);
298 297 }
299 298  
300 299 std::vector<QPDFExc>
301 300 QPDF::getWarnings()
302 301 {
303   - std::vector<QPDFExc> result = m->warnings;
  302 + std::vector<QPDFExc> result = std::move(m->warnings);
304 303 m->warnings.clear();
305 304 return result;
306 305 }
... ... @@ -372,12 +371,12 @@ QPDF::warn(QPDFExc const&amp; e)
372 371 void
373 372 Common::warn(QPDFExc const& e)
374 373 {
375   - if (m->max_warnings > 0 && m->warnings.size() >= m->max_warnings) {
  374 + if (cf.max_warnings() > 0 && m->warnings.size() >= cf.max_warnings()) {
376 375 stopOnError("Too many warnings - file is too badly damaged");
377 376 }
378   - m->warnings.push_back(e);
379   - if (!m->suppress_warnings) {
380   - *m->log->getWarn() << "WARNING: " << m->warnings.back().what() << "\n";
  377 + m->warnings.emplace_back(e);
  378 + if (!cf.suppress_warnings()) {
  379 + *cf.log()->getWarn() << "WARNING: " << m->warnings.back().what() << "\n";
381 380 }
382 381 }
383 382  
... ... @@ -715,7 +714,7 @@ QPDF::getRoot()
715 714 } else if (
716 715 // Check_mode is an interim solution to request #810 pending a more comprehensive review of
717 716 // the approach to more extensive checks and warning levels.
718   - m->check_mode && !root.getKey("/Type").isNameAndEquals("/Catalog")) {
  717 + m->cf.check_mode() && !root.getKey("/Type").isNameAndEquals("/Catalog")) {
719 718 warn(m->c.damagedPDF("", -1, "catalog /Type entry missing or invalid"));
720 719 root.replaceKey("/Type", "/Catalog"_qpdf);
721 720 }
... ...
libqpdf/QPDFJob.cc
... ... @@ -30,20 +30,8 @@
30 30  
31 31 using namespace qpdf;
32 32  
33   -using Doc = QPDF::Doc;
34   -using Pages = Doc::Pages;
35   -
36   -// JobSetter class is restricted to QPDFJob.
37   -class Doc::JobSetter
38   -{
39   - public:
40   - // Enable enhanced warnings for pdf file checking.
41   - static void
42   - setCheckMode(QPDF& qpdf, bool val)
43   - {
44   - qpdf.m->check_mode = val;
45   - }
46   -};
  33 +using QDoc = QPDF::Doc;
  34 +using Pages = QDoc::Pages;
47 35  
48 36 namespace
49 37 {
... ... @@ -489,7 +477,7 @@ QPDFJob::writeQPDF(QPDF&amp; pdf)
489 477 if (!pdf.getWarnings().empty()) {
490 478 m->warnings = true;
491 479 }
492   - if (m->warnings && (!m->suppress_warnings)) {
  480 + if (m->warnings && !m->qcf.suppress_warnings()) {
493 481 if (createsOutput()) {
494 482 *m->log->getWarn()
495 483 << m->message_prefix
... ... @@ -647,24 +635,6 @@ QPDFJob::getEncryptionStatus()
647 635 return m->encryption_status;
648 636 }
649 637  
650   -void
651   -QPDFJob::setQPDFOptions(QPDF& pdf)
652   -{
653   - pdf.setLogger(m->log);
654   - if (m->ignore_xref_streams) {
655   - pdf.setIgnoreXRefStreams(true);
656   - }
657   - if (m->suppress_recovery) {
658   - pdf.setAttemptRecovery(false);
659   - }
660   - if (m->password_is_hex_key) {
661   - pdf.setPasswordIsHexKey(true);
662   - }
663   - if (m->suppress_warnings) {
664   - pdf.setSuppressWarnings(true);
665   - }
666   -}
667   -
668 638 static std::string
669 639 show_bool(bool v)
670 640 {
... ... @@ -749,7 +719,6 @@ QPDFJob::doCheck(QPDF&amp; pdf)
749 719 bool okay = true;
750 720 auto& cout = *m->log->getInfo();
751 721 cout << "checking " << m->infile_name() << "\n";
752   - Doc::JobSetter::setCheckMode(pdf, true);
753 722 try {
754 723 int extension_level = pdf.getExtensionLevel();
755 724 cout << "PDF Version: " << pdf.getPDFVersion();
... ... @@ -1740,7 +1709,7 @@ QPDFJob::doProcessOnce(
1740 1709 bool main_input)
1741 1710 {
1742 1711 pdf = std::make_unique<QPDF>();
1743   - setQPDFOptions(*pdf);
  1712 + pdf->doc().config(m->qcf.log(m->log));
1744 1713 if (empty) {
1745 1714 pdf->emptyPDF();
1746 1715 } else if (main_input && m->json_input) {
... ... @@ -1770,16 +1739,15 @@ QPDFJob::doProcess(
1770 1739 // was incorrectly encoded, there's a good chance we'd succeed here.
1771 1740  
1772 1741 std::string ptemp;
1773   - if (password && (!m->password_is_hex_key)) {
  1742 + if (password && !m->qcf.password_is_hex_key()) {
1774 1743 if (m->password_mode == QPDFJob::pm_hex_bytes) {
1775 1744 // Special case: handle --password-mode=hex-bytes for input password as well as output
1776 1745 // password
1777   - QTC::TC("qpdf", "QPDFJob input password hex-bytes");
1778 1746 ptemp = QUtil::hex_decode(password);
1779 1747 password = ptemp.c_str();
1780 1748 }
1781 1749 }
1782   - if ((password == nullptr) || empty || m->password_is_hex_key || m->suppress_password_recovery) {
  1750 + if (!password || empty || m->qcf.password_is_hex_key() || m->suppress_password_recovery) {
1783 1751 // There is no password, or we're not doing recovery, so just do the normal processing with
1784 1752 // the supplied password.
1785 1753 doProcessOnce(pdf, fn, password, empty, used_for_input, main_input);
... ... @@ -3046,12 +3014,10 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3046 3014 last = num_pages;
3047 3015 }
3048 3016 QPDF outpdf;
  3017 + outpdf.doc().config(m->qcf);
3049 3018 outpdf.emptyPDF();
3050 3019 QPDFAcroFormDocumentHelper* out_afdh =
3051 3020 afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr;
3052   - if (m->suppress_warnings) {
3053   - outpdf.setSuppressWarnings(true);
3054   - }
3055 3021 for (size_t pageno = first; pageno <= last; ++pageno) {
3056 3022 QPDFObjectHandle page = pages.at(pageno - 1);
3057 3023 outpdf.addPage(page, false);
... ...
libqpdf/QPDFJob_config.cc
... ... @@ -68,6 +68,7 @@ QPDFJob::Config*
68 68 QPDFJob::Config::check()
69 69 {
70 70 o.m->check = true;
  71 + o.m->qcf.check_mode(true);
71 72 o.m->require_outfile = false;
72 73 return this;
73 74 }
... ... @@ -233,7 +234,7 @@ QPDFJob::Config::generateAppearances()
233 234 QPDFJob::Config*
234 235 QPDFJob::Config::ignoreXrefStreams()
235 236 {
236   - o.m->ignore_xref_streams = true;
  237 + o.m->qcf.ignore_xref_streams(true);
237 238 return this;
238 239 }
239 240  
... ... @@ -415,7 +416,7 @@ QPDFJob::Config::noOriginalObjectIds()
415 416 QPDFJob::Config*
416 417 QPDFJob::Config::noWarn()
417 418 {
418   - o.m->suppress_warnings = true;
  419 + o.m->qcf.suppress_warnings(true);
419 420 return this;
420 421 }
421 422  
... ... @@ -465,7 +466,7 @@ QPDFJob::Config::password(std::string const&amp; parameter)
465 466 QPDFJob::Config*
466 467 QPDFJob::Config::passwordIsHexKey()
467 468 {
468   - o.m->password_is_hex_key = true;
  469 + o.m->qcf.password_is_hex_key(true);
469 470 return this;
470 471 }
471 472  
... ... @@ -662,7 +663,7 @@ QPDFJob::Config::suppressPasswordRecovery()
662 663 QPDFJob::Config*
663 664 QPDFJob::Config::suppressRecovery()
664 665 {
665   - o.m->suppress_recovery = true;
  666 + o.m->qcf.surpress_recovery(true);
666 667 return this;
667 668 }
668 669  
... ...
libqpdf/QPDFWriter.cc
... ... @@ -27,8 +27,8 @@
27 27 using namespace std::literals;
28 28 using namespace qpdf;
29 29  
30   -using Doc = QPDF::Doc;
31   -using Encryption = Doc::Encryption;
  30 +using QDoc = QPDF::Doc;
  31 +using Encryption = QDoc::Encryption;
32 32  
33 33 QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default)
34 34 {
... ... @@ -263,7 +263,7 @@ Pl_stack::Popper::pop()
263 263 }
264 264  
265 265 // Writer class is restricted to QPDFWriter so that only it can call certain methods.
266   -class Doc::Writer: Doc::Common
  266 +class QPDF::Doc::Writer: QPDF::Doc::Common
267 267 {
268 268 friend class QPDFWriter;
269 269 Writer(QPDF& qpdf) :
... ...
libqpdf/QPDF_Stream.cc
... ... @@ -27,12 +27,6 @@ using namespace qpdf;
27 27  
28 28 using Streams = QPDF::Doc::Objects::Streams;
29 29  
30   -bool
31   -Streams::immediate_copy_from() const
32   -{
33   - return qpdf.m->immediate_copy_from;
34   -}
35   -
36 30 class Streams::Copier final: public QPDFObjectHandle::StreamDataProvider
37 31 {
38 32 class Data
... ... @@ -308,14 +302,13 @@ Stream::copy_data_to(Stream&amp; dest)
308 302 {
309 303 qpdf_expect(dest);
310 304 auto s = stream();
311   - auto& streams = qpdf()->doc().objects().streams();
312 305 auto& d_streams = dest.qpdf()->doc().objects().streams();
313 306  
314 307 auto dict = dest.getDict();
315 308  
316 309 // Copy information from the foreign stream so we can pipe its data later without keeping the
317 310 // original QPDF object around.
318   - if (streams.immediate_copy_from() && !s->stream_data) {
  311 + if (qpdf()->doc().config().immediate_copy_from() && !s->stream_data) {
319 312 // Pull the stream data into a buffer before attempting the copy operation. Do it on the
320 313 // source stream so that if the source stream is copied multiple times, we don't have to
321 314 // keep duplicating the memory.
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -904,7 +904,7 @@ QPDF::EncryptionParameters::initialize(QPDF&amp; qpdf)
904 904 }
905 905  
906 906 Encryption data(V, R, Length / 8, p, O, U, OE, UE, Perms, id1, encrypt_metadata);
907   - if (qm.provided_password_is_hex_key) {
  907 + if (qm.cf.password_is_hex_key()) {
908 908 // ignore passwords in file
909 909 encryption_key = QUtil::hex_decode(provided_password);
910 910 return;
... ...
libqpdf/QPDF_linearization.cc
... ... @@ -69,20 +69,20 @@ load_vector_vector(
69 69 bit_stream.skipToNextByte();
70 70 }
71 71  
72   -QPDF::ObjUser::ObjUser(user_e type) :
  72 +Lin::ObjUser::ObjUser(user_e type) :
73 73 ou_type(type)
74 74 {
75 75 qpdf_expect(type == ou_root);
76 76 }
77 77  
78   -QPDF::ObjUser::ObjUser(user_e type, size_t pageno) :
  78 +Lin::ObjUser::ObjUser(user_e type, size_t pageno) :
79 79 ou_type(type),
80 80 pageno(pageno)
81 81 {
82 82 qpdf_expect(type == ou_page || type == ou_thumb);
83 83 }
84 84  
85   -QPDF::ObjUser::ObjUser(user_e type, std::string const& key) :
  85 +Lin::ObjUser::ObjUser(user_e type, std::string const& key) :
86 86 ou_type(type),
87 87 key(key)
88 88 {
... ... @@ -90,7 +90,7 @@ QPDF::ObjUser::ObjUser(user_e type, std::string const&amp; key) :
90 90 }
91 91  
92 92 bool
93   -QPDF::ObjUser::operator<(ObjUser const& rhs) const
  93 +Lin::ObjUser::operator<(ObjUser const& rhs) const
94 94 {
95 95 if (ou_type < rhs.ou_type) {
96 96 return true;
... ... @@ -106,8 +106,8 @@ QPDF::ObjUser::operator&lt;(ObjUser const&amp; rhs) const
106 106 return false;
107 107 }
108 108  
109   -QPDF::UpdateObjectMapsFrame::UpdateObjectMapsFrame(
110   - QPDF::ObjUser const& ou, QPDFObjectHandle oh, bool top) :
  109 +Lin::UpdateObjectMapsFrame::UpdateObjectMapsFrame(
  110 + ObjUser const& ou, QPDFObjectHandle oh, bool top) :
111 111 ou(ou),
112 112 oh(oh),
113 113 top(top)
... ... @@ -137,7 +137,7 @@ Lin::optimize_internal(
137 137 bool allow_changes,
138 138 std::function<int(QPDFObjectHandle&)> skip_stream_parameters)
139 139 {
140   - if (!m->obj_user_to_objects.empty()) {
  140 + if (!obj_user_to_objects_.empty()) {
141 141 // already optimized
142 142 return;
143 143 }
... ... @@ -186,9 +186,9 @@ Lin::optimize_internal(
186 186 }
187 187  
188 188 ObjUser root_ou = ObjUser(ObjUser::ou_root);
189   - auto root_og = QPDFObjGen(root.getObjGen());
190   - m->obj_user_to_objects[root_ou].insert(root_og);
191   - m->object_to_obj_users[root_og].insert(root_ou);
  189 + auto root_og = root.id_gen();
  190 + obj_user_to_objects_[root_ou].insert(root_og);
  191 + object_to_obj_users_[root_og].insert(root_ou);
192 192  
193 193 filterCompressedObjects(object_stream_data);
194 194 }
... ... @@ -217,14 +217,14 @@ Lin::updateObjectMaps(
217 217 }
218 218 }
219 219  
220   - if (cur.oh.isIndirect()) {
  220 + if (cur.oh.indirect()) {
221 221 QPDFObjGen og(cur.oh.getObjGen());
222 222 if (!visited.add(og)) {
223 223 QTC::TC("qpdf", "QPDF opt loop detected");
224 224 continue;
225 225 }
226   - m->obj_user_to_objects[cur.ou].insert(og);
227   - m->object_to_obj_users[og].insert(cur.ou);
  226 + obj_user_to_objects_[cur.ou].insert(og);
  227 + object_to_obj_users_[og].insert(cur.ou);
228 228 }
229 229  
230 230 if (cur.oh.isArray()) {
... ... @@ -280,34 +280,30 @@ Lin::filterCompressedObjects(std::map&lt;int, int&gt; const&amp; object_stream_data)
280 280 std::map<ObjUser, std::set<QPDFObjGen>> t_obj_user_to_objects;
281 281 std::map<QPDFObjGen, std::set<ObjUser>> t_object_to_obj_users;
282 282  
283   - for (auto const& i1: m->obj_user_to_objects) {
284   - ObjUser const& ou = i1.first;
285   - // Loop over objects.
286   - for (auto const& og: i1.second) {
  283 + for (auto const& [ou, ogs]: obj_user_to_objects_) {
  284 + for (auto const& og: ogs) {
287 285 auto i2 = object_stream_data.find(og.getObj());
288 286 if (i2 == object_stream_data.end()) {
289 287 t_obj_user_to_objects[ou].insert(og);
290 288 } else {
291   - t_obj_user_to_objects[ou].insert(QPDFObjGen(i2->second, 0));
  289 + t_obj_user_to_objects[ou].insert({i2->second, 0});
292 290 }
293 291 }
294 292 }
295 293  
296   - for (auto const& i1: m->object_to_obj_users) {
297   - QPDFObjGen const& og = i1.first;
298   - // Loop over obj_users.
299   - for (auto const& ou: i1.second) {
  294 + for (auto const& [og, ous]: object_to_obj_users_) {
  295 + for (auto const& ou: ous) {
300 296 auto i2 = object_stream_data.find(og.getObj());
301 297 if (i2 == object_stream_data.end()) {
302 298 t_object_to_obj_users[og].insert(ou);
303 299 } else {
304   - t_object_to_obj_users[QPDFObjGen(i2->second, 0)].insert(ou);
  300 + t_object_to_obj_users[{i2->second, 0}].insert(ou);
305 301 }
306 302 }
307 303 }
308 304  
309   - m->obj_user_to_objects = t_obj_user_to_objects;
310   - m->object_to_obj_users = t_object_to_obj_users;
  305 + obj_user_to_objects_ = std::move(t_obj_user_to_objects);
  306 + object_to_obj_users_ = std::move(t_object_to_obj_users);
311 307 }
312 308  
313 309 void
... ... @@ -324,10 +320,8 @@ Lin::filterCompressedObjects(QPDFWriter::ObjTable const&amp; obj)
324 320 std::map<ObjUser, std::set<QPDFObjGen>> t_obj_user_to_objects;
325 321 std::map<QPDFObjGen, std::set<ObjUser>> t_object_to_obj_users;
326 322  
327   - for (auto const& i1: m->obj_user_to_objects) {
328   - ObjUser const& ou = i1.first;
329   - // Loop over objects.
330   - for (auto const& og: i1.second) {
  323 + for (auto const& [ou, ogs]: obj_user_to_objects_) {
  324 + for (auto const& og: ogs) {
331 325 if (obj.contains(og)) {
332 326 if (auto const& i2 = obj[og].object_stream; i2 <= 0) {
333 327 t_obj_user_to_objects[ou].insert(og);
... ... @@ -338,40 +332,45 @@ Lin::filterCompressedObjects(QPDFWriter::ObjTable const&amp; obj)
338 332 }
339 333 }
340 334  
341   - for (auto const& i1: m->object_to_obj_users) {
342   - QPDFObjGen const& og = i1.first;
  335 + for (auto const& [og, ous]: object_to_obj_users_) {
343 336 if (obj.contains(og)) {
344 337 // Loop over obj_users.
345   - for (auto const& ou: i1.second) {
  338 + for (auto const& ou: ous) {
346 339 if (auto i2 = obj[og].object_stream; i2 <= 0) {
347 340 t_object_to_obj_users[og].insert(ou);
348 341 } else {
349   - t_object_to_obj_users[QPDFObjGen(i2, 0)].insert(ou);
  342 + t_object_to_obj_users[{i2, 0}].insert(ou);
350 343 }
351 344 }
352 345 }
353 346 }
354 347  
355   - m->obj_user_to_objects = t_obj_user_to_objects;
356   - m->object_to_obj_users = t_object_to_obj_users;
  348 + obj_user_to_objects_ = std::move(t_obj_user_to_objects);
  349 + object_to_obj_users_ = std::move(t_object_to_obj_users);
357 350 }
358 351  
359 352 void
360 353 Lin::linearizationWarning(std::string_view msg)
361 354 {
362   - m->linearization_warnings = true;
  355 + linearization_warnings_ = true;
363 356 warn(qpdf_e_linearization, "", 0, std::string(msg));
364 357 }
365 358  
366 359 bool
367 360 QPDF::checkLinearization()
368 361 {
  362 + return m->lin.check();
  363 +}
  364 +
  365 +bool
  366 +Lin::check()
  367 +{
369 368 try {
370   - m->lin.readLinearizationData();
371   - m->lin.checkLinearizationInternal();
372   - return !m->linearization_warnings;
  369 + readLinearizationData();
  370 + checkLinearizationInternal();
  371 + return !linearization_warnings_;
373 372 } catch (std::runtime_error& e) {
374   - m->lin.linearizationWarning(
  373 + linearizationWarning(
375 374 "error encountered while checking linearization data: " + std::string(e.what()));
376 375 return false;
377 376 }
... ... @@ -380,6 +379,12 @@ QPDF::checkLinearization()
380 379 bool
381 380 QPDF::isLinearized()
382 381 {
  382 + return m->lin.linearized();
  383 +}
  384 +
  385 +bool
  386 +Lin::linearized()
  387 +{
383 388 // If the first object in the file is a dictionary with a suitable /Linearized key and has an /L
384 389 // key that accurately indicates the file size, initialize m->lindict and return true.
385 390  
... ... @@ -411,7 +416,7 @@ QPDF::isLinearized()
411 416 continue;
412 417 }
413 418  
414   - Dictionary candidate = getObject(toI(QUtil::string_to_ll(t1.getValue().data())), 0);
  419 + Dictionary candidate = qpdf.getObject(toI(QUtil::string_to_ll(t1.getValue().data())), 0);
415 420 auto linkey = candidate["/Linearized"];
416 421 if (!(linkey.isNumber() && toI(floor(linkey.getNumericValue())) == 1)) {
417 422 return false;
... ... @@ -422,8 +427,8 @@ QPDF::isLinearized()
422 427 if (L != m->file->tell()) {
423 428 return false;
424 429 }
425   - m->linp.file_size = L;
426   - m->lindict = candidate;
  430 + linp_.file_size = L;
  431 + lindict_ = candidate;
427 432 return true;
428 433 }
429 434 }
... ... @@ -432,24 +437,24 @@ void
432 437 Lin::readLinearizationData()
433 438 {
434 439 util::assertion(
435   - qpdf.isLinearized(), "called readLinearizationData for file that is not linearized" //
  440 + linearized(), "called readLinearizationData for file that is not linearized" //
436 441 );
437 442  
438 443 // This function throws an exception (which is trapped by checkLinearization()) for any errors
439 444 // that prevent loading.
440 445  
441 446 // /L is read and stored in linp by isLinearized()
442   - Array H = m->lindict["/H"]; // hint table offset/length for primary and overflow hint tables
  447 + Array H = lindict_["/H"]; // hint table offset/length for primary and overflow hint tables
443 448 auto H_size = H.size();
444 449 Integer H_0 = H[0]; // hint table offset
445 450 Integer H_1 = H[1]; // hint table length
446 451 Integer H_2 = H[2]; // hint table offset for overflow hint table
447 452 Integer H_3 = H[3]; // hint table length for overflow hint table
448   - Integer O = m->lindict["/O"];
449   - Integer E = m->lindict["/E"];
450   - Integer N = m->lindict["/N"];
451   - Integer T = m->lindict["/T"];
452   - auto P_oh = m->lindict["/P"];
  453 + Integer O = lindict_["/O"];
  454 + Integer E = lindict_["/E"];
  455 + Integer N = lindict_["/N"];
  456 + Integer T = lindict_["/T"];
  457 + auto P_oh = lindict_["/P"];
453 458 Integer P = P_oh; // first page number
454 459 QTC::TC("qpdf", "QPDF P absent in lindict", P ? 0 : 1);
455 460  
... ... @@ -482,13 +487,13 @@ Lin::readLinearizationData()
482 487 );
483 488  
484 489 // file_size initialized by isLinearized()
485   - m->linp.first_page_object = O;
486   - m->linp.first_page_end = E;
487   - m->linp.npages = N;
488   - m->linp.xref_zero_offset = T;
489   - m->linp.first_page = P ? P : 0;
490   - m->linp.H_offset = H_0;
491   - m->linp.H_length = H_1;
  490 + linp_.first_page_object = O;
  491 + linp_.first_page_end = E;
  492 + linp_.npages = N;
  493 + linp_.xref_zero_offset = T;
  494 + linp_.first_page = P ? P : 0;
  495 + linp_.H_offset = H_0;
  496 + linp_.H_length = H_1;
492 497  
493 498 // Read hint streams
494 499  
... ... @@ -532,7 +537,7 @@ Lin::readLinearizationData()
532 537 "linearization dictionary" //
533 538 );
534 539 size_t HOi = HO;
535   - readHGeneric(BitStream(h_buf + HO, h_size - HOi), m->outline_hints);
  540 + readHGeneric(BitStream(h_buf + HO, h_size - HOi), outline_hints_);
536 541 }
537 542 }
538 543  
... ... @@ -576,7 +581,7 @@ Lin::readHPageOffset(BitStream h)
576 581 {
577 582 // All comments referring to the PDF spec refer to the spec for version 1.4.
578 583  
579   - HPageOffset& t = m->page_offset_hints;
  584 + HPageOffset& t = page_offset_hints_;
580 585  
581 586 t.min_nobjects = h.getBitsInt(32); // 1
582 587 t.first_page_offset = h.getBitsInt(32); // 2
... ... @@ -594,7 +599,7 @@ Lin::readHPageOffset(BitStream h)
594 599  
595 600 std::vector<HPageOffsetEntry>& entries = t.entries;
596 601 entries.clear();
597   - int nitems = toI(m->linp.npages);
  602 + int nitems = toI(linp_.npages);
598 603 load_vector_int(h, nitems, entries, t.nbits_delta_nobjects, &HPageOffsetEntry::delta_nobjects);
599 604 load_vector_int(
600 605 h, nitems, entries, t.nbits_delta_page_length, &HPageOffsetEntry::delta_page_length);
... ... @@ -623,7 +628,7 @@ Lin::readHPageOffset(BitStream h)
623 628 void
624 629 Lin::readHSharedObject(BitStream h)
625 630 {
626   - HSharedObject& t = m->shared_object_hints;
  631 + HSharedObject& t = shared_object_hints_;
627 632  
628 633 t.first_shared_obj = h.getBitsInt(32); // 1
629 634 t.first_shared_offset = h.getBitsInt(32); // 2
... ... @@ -672,7 +677,7 @@ Lin::checkLinearizationInternal()
672 677  
673 678 // Check all values in linearization parameter dictionary
674 679  
675   - LinParameters& p = m->linp;
  680 + LinParameters& p = linp_;
676 681  
677 682 // L: file size in bytes -- checked by isLinearized
678 683  
... ... @@ -708,10 +713,10 @@ Lin::checkLinearizationInternal()
708 713 break;
709 714 }
710 715 }
711   - if (m->file->tell() != m->first_xref_item_offset) {
  716 + if (m->file->tell() != objects.first_xref_item_offset()) {
712 717 linearizationWarning(
713 718 "space before first xref item (/T) mismatch (computed = " +
714   - std::to_string(m->first_xref_item_offset) +
  719 + std::to_string(objects.first_xref_item_offset()) +
715 720 "; file = " + std::to_string(m->file->tell()));
716 721 }
717 722  
... ... @@ -722,7 +727,7 @@ Lin::checkLinearizationInternal()
722 727 // compressed objects are supposed to be at the end of the containing xref section if any object
723 728 // streams are in use.
724 729  
725   - if (m->uncompressed_after_compressed) {
  730 + if (objects.uncompressed_after_compressed()) {
726 731 linearizationWarning(
727 732 "linearized file contains an uncompressed object after a compressed "
728 733 "one in a cross-reference stream");
... ... @@ -751,11 +756,11 @@ Lin::checkLinearizationInternal()
751 756 // suite doesn't contain any files with threads.
752 757  
753 758 no_ci_stop_if(
754   - m->part6.empty(), "linearization part 6 unexpectedly empty" //
  759 + part6_.empty(), "linearization part 6 unexpectedly empty" //
755 760 );
756 761 qpdf_offset_t min_E = -1;
757 762 qpdf_offset_t max_E = -1;
758   - for (auto const& oh: m->part6) {
  763 + for (auto const& oh: part6_) {
759 764 QPDFObjGen og(oh.getObjGen());
760 765 // All objects have to have been dereferenced to be classified.
761 766 util::assertion(m->obj_cache.contains(og), "linearization part6 object not in cache");
... ... @@ -781,12 +786,12 @@ qpdf_offset_t
781 786 Lin::maxEnd(ObjUser const& ou)
782 787 {
783 788 no_ci_stop_if(
784   - !m->obj_user_to_objects.contains(ou),
  789 + !obj_user_to_objects_.contains(ou),
785 790 "no entry in object user table for requested object user" //
786 791 );
787 792  
788 793 qpdf_offset_t end = 0;
789   - for (auto const& og: m->obj_user_to_objects[ou]) {
  794 + for (auto const& og: obj_user_to_objects_[ou]) {
790 795 no_ci_stop_if(
791 796 !m->obj_cache.contains(og), "unknown object referenced in object user table" //
792 797 );
... ... @@ -868,7 +873,7 @@ Lin::checkHPageOffset(
868 873 // dictionary in with shared objects even when they are private.
869 874  
870 875 size_t npages = pages.size();
871   - qpdf_offset_t table_offset = adjusted_offset(m->page_offset_hints.first_page_offset);
  876 + qpdf_offset_t table_offset = adjusted_offset(page_offset_hints_.first_page_offset);
872 877 QPDFObjGen first_page_og(pages.at(0).getObjGen());
873 878 if (!m->xref_table.contains(first_page_og)) {
874 879 stopOnError("supposed first page object is not known");
... ... @@ -886,9 +891,9 @@ Lin::checkHPageOffset(
886 891 }
887 892 offset = getLinearizationOffset(page_og);
888 893  
889   - HPageOffsetEntry& he = m->page_offset_hints.entries.at(toS(pageno));
890   - CHPageOffsetEntry& ce = m->c_page_offset_data.entries.at(toS(pageno));
891   - int h_nobjects = he.delta_nobjects + m->page_offset_hints.min_nobjects;
  894 + HPageOffsetEntry& he = page_offset_hints_.entries.at(pageno);
  895 + CHPageOffsetEntry& ce = c_page_offset_data_.entries.at(pageno);
  896 + int h_nobjects = he.delta_nobjects + page_offset_hints_.min_nobjects;
892 897 if (h_nobjects != ce.nobjects) {
893 898 // This happens with pdlin when there are thumbnails.
894 899 linearizationWarning(
... ... @@ -899,7 +904,7 @@ Lin::checkHPageOffset(
899 904 // Use value for number of objects in hint table rather than computed value if there is a
900 905 // discrepancy.
901 906 int length = lengthNextN(first_object, h_nobjects);
902   - int h_length = toI(he.delta_page_length + m->page_offset_hints.min_page_length);
  907 + int h_length = toI(he.delta_page_length + page_offset_hints_.min_page_length);
903 908 if (length != h_length) {
904 909 // This condition almost certainly indicates a bad hint table or a bug in this code.
905 910 linearizationWarning(
... ... @@ -932,11 +937,11 @@ Lin::checkHPageOffset(
932 937 for (size_t i = 0; i < toS(ce.nshared_objects); ++i) {
933 938 int idx = ce.shared_identifiers.at(i);
934 939 no_ci_stop_if(
935   - idx >= m->c_shared_object_data.nshared_total,
  940 + idx >= c_shared_object_data_.nshared_total,
936 941 "index out of bounds for shared object hint table" //
937 942 );
938 943  
939   - int obj = m->c_shared_object_data.entries.at(toS(idx)).object;
  944 + int obj = c_shared_object_data_.entries.at(toS(idx)).object;
940 945 computed_shared.insert(obj);
941 946 }
942 947  
... ... @@ -978,7 +983,7 @@ Lin::checkHSharedObject(std::vector&lt;QPDFObjectHandle&gt; const&amp; pages, std::map&lt;int
978 983 // Empirically, Acrobat and pdlin generate incorrect values for these whenever there are no
979 984 // shared objects not referenced by the first page (i.e., nshared_total == nshared_first_page).
980 985  
981   - HSharedObject& so = m->shared_object_hints;
  986 + HSharedObject& so = shared_object_hints_;
982 987 if (so.nshared_total < so.nshared_first_page) {
983 988 linearizationWarning("shared object hint table: ntotal < nfirst_page");
984 989 } else {
... ... @@ -988,10 +993,10 @@ Lin::checkHSharedObject(std::vector&lt;QPDFObjectHandle&gt; const&amp; pages, std::map&lt;int
988 993 for (int i = 0; i < so.nshared_total; ++i) {
989 994 if (i == so.nshared_first_page) {
990 995 QTC::TC("qpdf", "QPDF lin check shared past first page");
991   - if (m->part8.empty()) {
  996 + if (part8_.empty()) {
992 997 linearizationWarning("part 8 is empty but nshared_total > nshared_first_page");
993 998 } else {
994   - int obj = m->part8.at(0).getObjectID();
  999 + int obj = part8_.at(0).getObjectID();
995 1000 if (obj != so.first_shared_obj) {
996 1001 linearizationWarning(
997 1002 "first shared object number mismatch: hint table = " +
... ... @@ -1039,12 +1044,12 @@ Lin::checkHOutlines()
1039 1044 // correct number of objects from the wrong starting place). pdlin appears to generate correct
1040 1045 // values in those cases.
1041 1046  
1042   - if (m->c_outline_data.nobjects == m->outline_hints.nobjects) {
1043   - if (m->c_outline_data.nobjects == 0) {
  1047 + if (c_outline_data_.nobjects == outline_hints_.nobjects) {
  1048 + if (c_outline_data_.nobjects == 0) {
1044 1049 return;
1045 1050 }
1046 1051  
1047   - if (m->c_outline_data.first_object == m->outline_hints.first_object) {
  1052 + if (c_outline_data_.first_object == outline_hints_.first_object) {
1048 1053 // Check length and offset. Acrobat gets these wrong.
1049 1054 QPDFObjectHandle outlines = qpdf.getRoot().getKey("/Outlines");
1050 1055 if (!outlines.isIndirect()) {
... ... @@ -1060,13 +1065,13 @@ Lin::checkHOutlines()
1060 1065 qpdf_offset_t offset = getLinearizationOffset(og);
1061 1066 ObjUser ou(ObjUser::ou_root_key, "/Outlines");
1062 1067 int length = toI(maxEnd(ou) - offset);
1063   - qpdf_offset_t table_offset = adjusted_offset(m->outline_hints.first_object_offset);
  1068 + qpdf_offset_t table_offset = adjusted_offset(outline_hints_.first_object_offset);
1064 1069 if (offset != table_offset) {
1065 1070 linearizationWarning(
1066 1071 "incorrect offset in outlines table: hint table = " +
1067 1072 std::to_string(table_offset) + "; computed = " + std::to_string(offset));
1068 1073 }
1069   - int table_length = m->outline_hints.group_length;
  1074 + int table_length = outline_hints_.group_length;
1070 1075 if (length != table_length) {
1071 1076 linearizationWarning(
1072 1077 "incorrect length in outlines table: hint table = " +
... ... @@ -1083,38 +1088,46 @@ Lin::checkHOutlines()
1083 1088 void
1084 1089 QPDF::showLinearizationData()
1085 1090 {
  1091 + m->lin.show_data();
  1092 +}
  1093 +
  1094 +void
  1095 +Lin::show_data()
  1096 +{
1086 1097 try {
1087   - m->lin.readLinearizationData();
1088   - m->lin.checkLinearizationInternal();
1089   - m->lin.dumpLinearizationDataInternal();
  1098 + readLinearizationData();
  1099 + checkLinearizationInternal();
  1100 + dumpLinearizationDataInternal();
1090 1101 } catch (QPDFExc& e) {
1091   - m->lin.linearizationWarning(e.what());
  1102 + linearizationWarning(e.what());
1092 1103 }
1093 1104 }
1094 1105  
1095 1106 void
1096 1107 Lin::dumpLinearizationDataInternal()
1097 1108 {
1098   - *m->log->getInfo() << m->file->getName() << ": linearization data:\n\n";
1099   -
1100   - *m->log->getInfo() << "file_size: " << m->linp.file_size << "\n"
1101   - << "first_page_object: " << m->linp.first_page_object << "\n"
1102   - << "first_page_end: " << m->linp.first_page_end << "\n"
1103   - << "npages: " << m->linp.npages << "\n"
1104   - << "xref_zero_offset: " << m->linp.xref_zero_offset << "\n"
1105   - << "first_page: " << m->linp.first_page << "\n"
1106   - << "H_offset: " << m->linp.H_offset << "\n"
1107   - << "H_length: " << m->linp.H_length << "\n"
1108   - << "\n";
1109   -
1110   - *m->log->getInfo() << "Page Offsets Hint Table\n\n";
  1109 + auto& info = *cf.log()->getInfo();
  1110 +
  1111 + info << m->file->getName() << ": linearization data:\n\n";
  1112 +
  1113 + info << "file_size: " << linp_.file_size << "\n"
  1114 + << "first_page_object: " << linp_.first_page_object << "\n"
  1115 + << "first_page_end: " << linp_.first_page_end << "\n"
  1116 + << "npages: " << linp_.npages << "\n"
  1117 + << "xref_zero_offset: " << linp_.xref_zero_offset << "\n"
  1118 + << "first_page: " << linp_.first_page << "\n"
  1119 + << "H_offset: " << linp_.H_offset << "\n"
  1120 + << "H_length: " << linp_.H_length << "\n"
  1121 + << "\n";
  1122 +
  1123 + info << "Page Offsets Hint Table\n\n";
1111 1124 dumpHPageOffset();
1112   - *m->log->getInfo() << "\nShared Objects Hint Table\n\n";
  1125 + info << "\nShared Objects Hint Table\n\n";
1113 1126 dumpHSharedObject();
1114 1127  
1115   - if (m->outline_hints.nobjects > 0) {
1116   - *m->log->getInfo() << "\nOutlines Hint Table\n\n";
1117   - dumpHGeneric(m->outline_hints);
  1128 + if (outline_hints_.nobjects > 0) {
  1129 + info << "\nOutlines Hint Table\n\n";
  1130 + dumpHGeneric(outline_hints_);
1118 1131 }
1119 1132 }
1120 1133  
... ... @@ -1123,8 +1136,8 @@ Lin::adjusted_offset(qpdf_offset_t offset)
1123 1136 {
1124 1137 // All offsets >= H_offset have to be increased by H_length since all hint table location values
1125 1138 // disregard the hint table itself.
1126   - if (offset >= m->linp.H_offset) {
1127   - return offset + m->linp.H_length;
  1139 + if (offset >= linp_.H_offset) {
  1140 + return offset + linp_.H_length;
1128 1141 }
1129 1142 return offset;
1130 1143 }
... ... @@ -1132,38 +1145,35 @@ Lin::adjusted_offset(qpdf_offset_t offset)
1132 1145 void
1133 1146 Lin::dumpHPageOffset()
1134 1147 {
1135   - HPageOffset& t = m->page_offset_hints;
1136   - *m->log->getInfo() << "min_nobjects: " << t.min_nobjects << "\n"
1137   - << "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n"
1138   - << "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n"
1139   - << "min_page_length: " << t.min_page_length << "\n"
1140   - << "nbits_delta_page_length: " << t.nbits_delta_page_length << "\n"
1141   - << "min_content_offset: " << t.min_content_offset << "\n"
1142   - << "nbits_delta_content_offset: " << t.nbits_delta_content_offset << "\n"
1143   - << "min_content_length: " << t.min_content_length << "\n"
1144   - << "nbits_delta_content_length: " << t.nbits_delta_content_length << "\n"
1145   - << "nbits_nshared_objects: " << t.nbits_nshared_objects << "\n"
1146   - << "nbits_shared_identifier: " << t.nbits_shared_identifier << "\n"
1147   - << "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n"
1148   - << "shared_denominator: " << t.shared_denominator << "\n";
1149   -
1150   - for (size_t i1 = 0; i1 < m->linp.npages; ++i1) {
  1148 + auto& info = *cf.log()->getInfo();
  1149 + HPageOffset& t = page_offset_hints_;
  1150 + info << "min_nobjects: " << t.min_nobjects << "\n"
  1151 + << "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n"
  1152 + << "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n"
  1153 + << "min_page_length: " << t.min_page_length << "\n"
  1154 + << "nbits_delta_page_length: " << t.nbits_delta_page_length << "\n"
  1155 + << "min_content_offset: " << t.min_content_offset << "\n"
  1156 + << "nbits_delta_content_offset: " << t.nbits_delta_content_offset << "\n"
  1157 + << "min_content_length: " << t.min_content_length << "\n"
  1158 + << "nbits_delta_content_length: " << t.nbits_delta_content_length << "\n"
  1159 + << "nbits_nshared_objects: " << t.nbits_nshared_objects << "\n"
  1160 + << "nbits_shared_identifier: " << t.nbits_shared_identifier << "\n"
  1161 + << "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n"
  1162 + << "shared_denominator: " << t.shared_denominator << "\n";
  1163 +
  1164 + for (size_t i1 = 0; i1 < linp_.npages; ++i1) {
1151 1165 HPageOffsetEntry& pe = t.entries.at(i1);
1152   - *m->log->getInfo() << "Page " << i1 << ":\n"
1153   - << " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n"
1154   - << " length: " << pe.delta_page_length + t.min_page_length
1155   - << "\n"
1156   - // content offset is relative to page, not file
1157   - << " content_offset: " << pe.delta_content_offset + t.min_content_offset
1158   - << "\n"
1159   - << " content_length: " << pe.delta_content_length + t.min_content_length
1160   - << "\n"
1161   - << " nshared_objects: " << pe.nshared_objects << "\n";
  1166 + info << "Page " << i1 << ":\n"
  1167 + << " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n"
  1168 + << " length: " << pe.delta_page_length + t.min_page_length
  1169 + << "\n"
  1170 + // content offset is relative to page, not file
  1171 + << " content_offset: " << pe.delta_content_offset + t.min_content_offset << "\n"
  1172 + << " content_length: " << pe.delta_content_length + t.min_content_length << "\n"
  1173 + << " nshared_objects: " << pe.nshared_objects << "\n";
1162 1174 for (size_t i2 = 0; i2 < toS(pe.nshared_objects); ++i2) {
1163   - *m->log->getInfo() << " identifier " << i2 << ": " << pe.shared_identifiers.at(i2)
1164   - << "\n";
1165   - *m->log->getInfo() << " numerator " << i2 << ": " << pe.shared_numerators.at(i2)
1166   - << "\n";
  1175 + info << " identifier " << i2 << ": " << pe.shared_identifiers.at(i2) << "\n";
  1176 + info << " numerator " << i2 << ": " << pe.shared_numerators.at(i2) << "\n";
1167 1177 }
1168 1178 }
1169 1179 }
... ... @@ -1171,27 +1181,27 @@ Lin::dumpHPageOffset()
1171 1181 void
1172 1182 Lin::dumpHSharedObject()
1173 1183 {
1174   - HSharedObject& t = m->shared_object_hints;
1175   - *m->log->getInfo() << "first_shared_obj: " << t.first_shared_obj << "\n"
1176   - << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) << "\n"
1177   - << "nshared_first_page: " << t.nshared_first_page << "\n"
1178   - << "nshared_total: " << t.nshared_total << "\n"
1179   - << "nbits_nobjects: " << t.nbits_nobjects << "\n"
1180   - << "min_group_length: " << t.min_group_length << "\n"
1181   - << "nbits_delta_group_length: " << t.nbits_delta_group_length << "\n";
  1184 + auto& info = *cf.log()->getInfo();
  1185 + HSharedObject& t = shared_object_hints_;
  1186 + info << "first_shared_obj: " << t.first_shared_obj << "\n"
  1187 + << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) << "\n"
  1188 + << "nshared_first_page: " << t.nshared_first_page << "\n"
  1189 + << "nshared_total: " << t.nshared_total << "\n"
  1190 + << "nbits_nobjects: " << t.nbits_nobjects << "\n"
  1191 + << "min_group_length: " << t.min_group_length << "\n"
  1192 + << "nbits_delta_group_length: " << t.nbits_delta_group_length << "\n";
1182 1193  
1183 1194 for (size_t i = 0; i < toS(t.nshared_total); ++i) {
1184 1195 HSharedObjectEntry& se = t.entries.at(i);
1185   - *m->log->getInfo() << "Shared Object " << i << ":\n"
1186   - << " group length: " << se.delta_group_length + t.min_group_length
1187   - << "\n";
  1196 + info << "Shared Object " << i << ":\n"
  1197 + << " group length: " << se.delta_group_length + t.min_group_length << "\n";
1188 1198 // PDF spec says signature present nobjects_minus_one are always 0, so print them only if
1189 1199 // they have a non-zero value.
1190 1200 if (se.signature_present) {
1191   - *m->log->getInfo() << " signature present\n";
  1201 + info << " signature present\n";
1192 1202 }
1193 1203 if (se.nobjects_minus_one != 0) {
1194   - *m->log->getInfo() << " nobjects: " << se.nobjects_minus_one + 1 << "\n";
  1204 + info << " nobjects: " << se.nobjects_minus_one + 1 << "\n";
1195 1205 }
1196 1206 }
1197 1207 }
... ... @@ -1199,10 +1209,11 @@ Lin::dumpHSharedObject()
1199 1209 void
1200 1210 Lin::dumpHGeneric(HGeneric& t)
1201 1211 {
1202   - *m->log->getInfo() << "first_object: " << t.first_object << "\n"
1203   - << "first_object_offset: " << adjusted_offset(t.first_object_offset) << "\n"
1204   - << "nobjects: " << t.nobjects << "\n"
1205   - << "group_length: " << t.group_length << "\n";
  1212 + *cf.log()->getInfo() << "first_object: " << t.first_object << "\n"
  1213 + << "first_object_offset: " << adjusted_offset(t.first_object_offset)
  1214 + << "\n"
  1215 + << "nobjects: " << t.nobjects << "\n"
  1216 + << "group_length: " << t.group_length << "\n";
1206 1217 }
1207 1218  
1208 1219 template <typename T>
... ... @@ -1215,7 +1226,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1215 1226 // actual offsets and lengths are not computed here, but anything related to object ordering is.
1216 1227  
1217 1228 util::assertion(
1218   - !m->object_to_obj_users.empty(),
  1229 + !object_to_obj_users_.empty(),
1219 1230 "INTERNAL ERROR: QPDF::calculateLinearizationData called before optimize()" //
1220 1231 );
1221 1232 // Note that we can't call optimize here because we don't know whether it should be called
... ... @@ -1264,15 +1275,15 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1264 1275  
1265 1276 // * outlines: part 6 or 9
1266 1277  
1267   - m->part4.clear();
1268   - m->part6.clear();
1269   - m->part7.clear();
1270   - m->part8.clear();
1271   - m->part9.clear();
1272   - m->c_linp = LinParameters();
1273   - m->c_page_offset_data = CHPageOffset();
1274   - m->c_shared_object_data = CHSharedObject();
1275   - m->c_outline_data = HGeneric();
  1278 + part4_.clear();
  1279 + part6_.clear();
  1280 + part7_.clear();
  1281 + part8_.clear();
  1282 + part9_.clear();
  1283 + c_linp_ = LinParameters();
  1284 + c_page_offset_data_ = CHPageOffset();
  1285 + c_shared_object_data_ = CHSharedObject();
  1286 + c_outline_data_ = HGeneric();
1276 1287  
1277 1288 QPDFObjectHandle root = qpdf.getRoot();
1278 1289 bool outlines_in_first_page = false;
... ... @@ -1307,10 +1318,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1307 1318 std::set<QPDFObjGen> lc_outlines;
1308 1319 std::set<QPDFObjGen> lc_root;
1309 1320  
1310   - for (auto& oiter: m->object_to_obj_users) {
1311   - QPDFObjGen const& og = oiter.first;
1312   - std::set<ObjUser>& ous = oiter.second;
1313   -
  1321 + for (auto& [og, ous]: object_to_obj_users_) {
1314 1322 bool in_open_document = false;
1315 1323 bool in_first_page = false;
1316 1324 int other_pages = 0;
... ... @@ -1409,8 +1417,8 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1409 1417  
1410 1418 // npages is the size of the existing pages vector, which has been created by traversing the
1411 1419 // pages tree, and as such is a reasonable size.
1412   - m->c_linp.npages = npages;
1413   - m->c_page_offset_data.entries = std::vector<CHPageOffsetEntry>(npages);
  1420 + c_linp_.npages = npages;
  1421 + c_page_offset_data_.entries = std::vector<CHPageOffsetEntry>(npages);
1414 1422  
1415 1423 // Part 4: open document objects. We don't care about the order.
1416 1424  
... ... @@ -1418,9 +1426,9 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1418 1426 lc_root.size() != 1, "found other than one root while calculating linearization data" //
1419 1427 );
1420 1428  
1421   - m->part4.emplace_back(qpdf.getObject(*(lc_root.begin())));
  1429 + part4_.emplace_back(qpdf.getObject(*(lc_root.begin())));
1422 1430 for (auto const& og: lc_open_document) {
1423   - m->part4.emplace_back(qpdf.getObject(og));
  1431 + part4_.emplace_back(qpdf.getObject(og));
1424 1432 }
1425 1433  
1426 1434 // Part 6: first page objects. Note: implementation note 124 states that Acrobat always treats
... ... @@ -1435,31 +1443,31 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1435 1443 no_ci_stop_if(
1436 1444 !lc_first_page_private.erase(first_page_og), "unable to linearize first page" //
1437 1445 );
1438   - m->c_linp.first_page_object = uc_pages.at(0).getObjectID();
1439   - m->part6.emplace_back(uc_pages.at(0));
  1446 + c_linp_.first_page_object = uc_pages.at(0).getObjectID();
  1447 + part6_.emplace_back(uc_pages.at(0));
1440 1448  
1441 1449 // The PDF spec "recommends" an order for the rest of the objects, but we are going to disregard
1442 1450 // it except to the extent that it groups private and shared objects contiguously for the sake
1443 1451 // of hint tables.
1444 1452  
1445 1453 for (auto const& og: lc_first_page_private) {
1446   - m->part6.emplace_back(qpdf.getObject(og));
  1454 + part6_.emplace_back(qpdf.getObject(og));
1447 1455 }
1448 1456  
1449 1457 for (auto const& og: lc_first_page_shared) {
1450   - m->part6.emplace_back(qpdf.getObject(og));
  1458 + part6_.emplace_back(qpdf.getObject(og));
1451 1459 }
1452 1460  
1453 1461 // Place the outline dictionary if it goes in the first page section.
1454 1462 if (outlines_in_first_page) {
1455   - pushOutlinesToPart(m->part6, lc_outlines, object_stream_data);
  1463 + pushOutlinesToPart(part6_, lc_outlines, object_stream_data);
1456 1464 }
1457 1465  
1458 1466 // Fill in page offset hint table information for the first page. The PDF spec says that
1459 1467 // nshared_objects should be zero for the first page. pdlin does not appear to obey this, but
1460 1468 // it fills in garbage values for all the shared object identifiers on the first page.
1461 1469  
1462   - m->c_page_offset_data.entries.at(0).nobjects = toI(m->part6.size());
  1470 + c_page_offset_data_.entries.at(0).nobjects = toI(part6_.size());
1463 1471  
1464 1472 // Part 7: other pages' private objects
1465 1473  
... ... @@ -1473,23 +1481,23 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1473 1481 "unable to linearize page " + std::to_string(i) //
1474 1482 );
1475 1483  
1476   - m->part7.emplace_back(uc_pages.at(i));
  1484 + part7_.emplace_back(uc_pages.at(i));
1477 1485  
1478 1486 // Place all non-shared objects referenced by this page, updating the page object count for
1479 1487 // the hint table.
1480 1488  
1481   - m->c_page_offset_data.entries.at(i).nobjects = 1;
  1489 + c_page_offset_data_.entries.at(i).nobjects = 1;
1482 1490  
1483 1491 ObjUser ou(ObjUser::ou_page, i);
1484 1492 no_ci_stop_if(
1485   - !m->obj_user_to_objects.contains(ou),
  1493 + !obj_user_to_objects_.contains(ou),
1486 1494 "found unreferenced page while calculating linearization data" //
1487 1495 );
1488 1496  
1489   - for (auto const& og: m->obj_user_to_objects[ou]) {
  1497 + for (auto const& og: obj_user_to_objects_[ou]) {
1490 1498 if (lc_other_page_private.erase(og)) {
1491   - m->part7.emplace_back(qpdf.getObject(og));
1492   - ++m->c_page_offset_data.entries.at(i).nobjects;
  1499 + part7_.emplace_back(qpdf.getObject(og));
  1500 + ++c_page_offset_data_.entries.at(i).nobjects;
1493 1501 }
1494 1502 }
1495 1503 }
... ... @@ -1504,7 +1512,7 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1504 1512  
1505 1513 // Order is unimportant.
1506 1514 for (auto const& og: lc_other_page_shared) {
1507   - m->part8.emplace_back(qpdf.getObject(og));
  1515 + part8_.emplace_back(qpdf.getObject(og));
1508 1516 }
1509 1517  
1510 1518 // Part 9: other objects
... ... @@ -1515,14 +1523,13 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1515 1523 // we throw all remaining objects in arbitrary order.
1516 1524  
1517 1525 // Place the pages tree.
1518   - std::set<QPDFObjGen> pages_ogs =
1519   - m->obj_user_to_objects[ObjUser(ObjUser::ou_root_key, "/Pages")];
  1526 + auto& pages_ogs = obj_user_to_objects_[{ObjUser::ou_root_key, "/Pages"}];
1520 1527 no_ci_stop_if(
1521 1528 pages_ogs.empty(), "found empty pages tree while calculating linearization data" //
1522 1529 );
1523 1530 for (auto const& og: pages_ogs) {
1524 1531 if (lc_other.erase(og)) {
1525   - m->part9.emplace_back(qpdf.getObject(og));
  1532 + part9_.emplace_back(qpdf.getObject(og));
1526 1533 }
1527 1534 }
1528 1535  
... ... @@ -1534,17 +1541,16 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1534 1541 QPDFObjGen thumb_og(thumb.getObjGen());
1535 1542 // Output the thumbnail itself
1536 1543 if (lc_thumbnail_private.erase(thumb_og) && !thumb.null()) {
1537   - m->part9.emplace_back(thumb);
  1544 + part9_.emplace_back(thumb);
1538 1545 } else {
1539 1546 // No internal error this time...there's nothing to stop this object from having
1540 1547 // been referred to somewhere else outside of a page's /Thumb, and if it had been,
1541 1548 // there's nothing to prevent it from having been in some set other than
1542 1549 // lc_thumbnail_private.
1543 1550 }
1544   - std::set<QPDFObjGen>& ogs = m->obj_user_to_objects[ObjUser(ObjUser::ou_thumb, i)];
1545   - for (auto const& og: ogs) {
  1551 + for (auto const& og: obj_user_to_objects_[{ObjUser::ou_thumb, i}]) {
1546 1552 if (lc_thumbnail_private.erase(og)) {
1547   - m->part9.emplace_back(qpdf.getObject(og));
  1553 + part9_.emplace_back(qpdf.getObject(og));
1548 1554 }
1549 1555 }
1550 1556 }
... ... @@ -1556,24 +1562,24 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1556 1562  
1557 1563 // Place shared thumbnail objects
1558 1564 for (auto const& og: lc_thumbnail_shared) {
1559   - m->part9.emplace_back(qpdf.getObject(og));
  1565 + part9_.emplace_back(qpdf.getObject(og));
1560 1566 }
1561 1567  
1562 1568 // Place outlines unless in first page
1563 1569 if (!outlines_in_first_page) {
1564   - pushOutlinesToPart(m->part9, lc_outlines, object_stream_data);
  1570 + pushOutlinesToPart(part9_, lc_outlines, object_stream_data);
1565 1571 }
1566 1572  
1567 1573 // Place all remaining objects
1568 1574 for (auto const& og: lc_other) {
1569   - m->part9.emplace_back(qpdf.getObject(og));
  1575 + part9_.emplace_back(qpdf.getObject(og));
1570 1576 }
1571 1577  
1572 1578 // Make sure we got everything exactly once.
1573 1579  
1574 1580 size_t num_placed =
1575   - m->part4.size() + m->part6.size() + m->part7.size() + m->part8.size() + m->part9.size();
1576   - size_t num_wanted = m->object_to_obj_users.size();
  1581 + part4_.size() + part6_.size() + part7_.size() + part8_.size() + part9_.size();
  1582 + size_t num_wanted = object_to_obj_users_.size();
1577 1583 no_ci_stop_if(
1578 1584 // This can happen with damaged files, e.g. if the root is part of the the pages tree.
1579 1585 num_placed != num_wanted,
... ... @@ -1593,20 +1599,20 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1593 1599 // only without regards to generation.
1594 1600 std::map<int, int> obj_to_index;
1595 1601  
1596   - m->c_shared_object_data.nshared_first_page = toI(m->part6.size());
1597   - m->c_shared_object_data.nshared_total =
1598   - m->c_shared_object_data.nshared_first_page + toI(m->part8.size());
  1602 + c_shared_object_data_.nshared_first_page = toI(part6_.size());
  1603 + c_shared_object_data_.nshared_total =
  1604 + c_shared_object_data_.nshared_first_page + toI(part8_.size());
1599 1605  
1600   - std::vector<CHSharedObjectEntry>& shared = m->c_shared_object_data.entries;
1601   - for (auto& oh: m->part6) {
  1606 + std::vector<CHSharedObjectEntry>& shared = c_shared_object_data_.entries;
  1607 + for (auto& oh: part6_) {
1602 1608 int obj = oh.getObjectID();
1603 1609 obj_to_index[obj] = toI(shared.size());
1604 1610 shared.emplace_back(obj);
1605 1611 }
1606   - QTC::TC("qpdf", "QPDF lin part 8 empty", m->part8.empty() ? 1 : 0);
1607   - if (!m->part8.empty()) {
1608   - m->c_shared_object_data.first_shared_obj = m->part8.at(0).getObjectID();
1609   - for (auto& oh: m->part8) {
  1612 + QTC::TC("qpdf", "QPDF lin part 8 empty", part8_.empty() ? 1 : 0);
  1613 + if (!part8_.empty()) {
  1614 + c_shared_object_data_.first_shared_obj = part8_.at(0).getObjectID();
  1615 + for (auto& oh: part8_) {
1610 1616 int obj = oh.getObjectID();
1611 1617 obj_to_index[obj] = toI(shared.size());
1612 1618 shared.emplace_back(obj);
... ... @@ -1614,22 +1620,22 @@ Lin::calculateLinearizationData(T const&amp; object_stream_data)
1614 1620 }
1615 1621 no_ci_stop_if(
1616 1622 std::cmp_not_equal(
1617   - m->c_shared_object_data.nshared_total, m->c_shared_object_data.entries.size()),
  1623 + c_shared_object_data_.nshared_total, c_shared_object_data_.entries.size()),
1618 1624 "shared object hint table has wrong number of entries" //
1619 1625 );
1620 1626  
1621 1627 // Now compute the list of shared objects for each page after the first page.
1622 1628  
1623 1629 for (size_t i = 1; i < npages; ++i) {
1624   - CHPageOffsetEntry& pe = m->c_page_offset_data.entries.at(i);
  1630 + CHPageOffsetEntry& pe = c_page_offset_data_.entries.at(i);
1625 1631 ObjUser ou(ObjUser::ou_page, i);
1626 1632 no_ci_stop_if(
1627   - !m->obj_user_to_objects.contains(ou),
  1633 + !obj_user_to_objects_.contains(ou),
1628 1634 "found unreferenced page while calculating linearization data" //
1629 1635 );
1630 1636  
1631   - for (auto const& og: m->obj_user_to_objects[ou]) {
1632   - if ((m->object_to_obj_users[og].size() > 1) && (obj_to_index.contains(og.getObj()))) {
  1637 + for (auto const& og: obj_user_to_objects_[ou]) {
  1638 + if (object_to_obj_users_[og].size() > 1 && obj_to_index.contains(og.getObj())) {
1633 1639 int idx = obj_to_index[og.getObj()];
1634 1640 ++pe.nshared_objects;
1635 1641 pe.shared_identifiers.push_back(idx);
... ... @@ -1655,22 +1661,22 @@ Lin::pushOutlinesToPart(
1655 1661 QTC::TC(
1656 1662 "qpdf",
1657 1663 "QPDF lin outlines in part",
1658   - &part == &m->part6 ? 0
1659   - : (&part == &m->part9) ? 1
1660   - : 9999); // can't happen
  1664 + &part == &part6_ ? 0
  1665 + : (&part == &part9_) ? 1
  1666 + : 9999); // can't happen
1661 1667 if (lc_outlines.erase(outlines_og)) {
1662 1668 // Make sure outlines is in lc_outlines in case the file is damaged. in which case it may be
1663 1669 // included in an earlier part.
1664 1670 part.emplace_back(outlines);
1665   - m->c_outline_data.first_object = outlines_og.getObj();
1666   - m->c_outline_data.nobjects = 1;
  1671 + c_outline_data_.first_object = outlines_og.getObj();
  1672 + c_outline_data_.nobjects = 1;
1667 1673 }
1668 1674 for (auto const& og: lc_outlines) {
1669   - if (!m->c_outline_data.first_object) {
1670   - m->c_outline_data.first_object = og.getObj();
  1675 + if (!c_outline_data_.first_object) {
  1676 + c_outline_data_.first_object = og.getObj();
1671 1677 }
1672 1678 part.emplace_back(qpdf.getObject(og));
1673   - ++m->c_outline_data.nobjects;
  1679 + ++c_outline_data_.nobjects;
1674 1680 }
1675 1681 }
1676 1682  
... ... @@ -1684,11 +1690,11 @@ Lin::getLinearizedParts(
1684 1690 std::vector<QPDFObjectHandle>& part9)
1685 1691 {
1686 1692 calculateLinearizationData(obj);
1687   - part4 = m->part4;
1688   - part6 = m->part6;
1689   - part7 = m->part7;
1690   - part8 = m->part8;
1691   - part9 = m->part9;
  1693 + part4 = part4_;
  1694 + part6 = part6_;
  1695 + part7 = part7_;
  1696 + part8 = part8_;
  1697 + part9 = part9_;
1692 1698 }
1693 1699  
1694 1700 static inline int
... ... @@ -1728,7 +1734,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1728 1734  
1729 1735 auto const& all_pages = pages.all();
1730 1736 size_t npages = all_pages.size();
1731   - CHPageOffset& cph = m->c_page_offset_data;
  1737 + CHPageOffset& cph = c_page_offset_data_;
1732 1738 std::vector<CHPageOffsetEntry>& cphe = cph.entries;
1733 1739  
1734 1740 // Calculate minimum and maximum values for number of objects per page and page length.
... ... @@ -1739,7 +1745,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1739 1745 int max_length = 0;
1740 1746 int max_shared = 0;
1741 1747  
1742   - HPageOffset& ph = m->page_offset_hints;
  1748 + HPageOffset& ph = page_offset_hints_;
1743 1749 std::vector<HPageOffsetEntry>& phe = ph.entries;
1744 1750 // npages is the size of the existing pages array.
1745 1751 phe = std::vector<HPageOffsetEntry>(npages);
... ... @@ -1774,7 +1780,7 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1774 1780 ph.min_page_length = min_length;
1775 1781 ph.nbits_delta_page_length = nbits(max_length - min_length);
1776 1782 ph.nbits_nshared_objects = nbits(max_shared);
1777   - ph.nbits_shared_identifier = nbits(m->c_shared_object_data.nshared_total);
  1783 + ph.nbits_shared_identifier = nbits(c_shared_object_data_.nshared_total);
1778 1784 ph.shared_denominator = 4; // doesn't matter
1779 1785  
1780 1786 // It isn't clear how to compute content offset and content length. Since we are not
... ... @@ -1806,9 +1812,9 @@ Lin::calculateHPageOffset(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::Ob
1806 1812 void
1807 1813 Lin::calculateHSharedObject(QPDFWriter::NewObjTable const& new_obj, QPDFWriter::ObjTable const& obj)
1808 1814 {
1809   - CHSharedObject& cso = m->c_shared_object_data;
  1815 + CHSharedObject& cso = c_shared_object_data_;
1810 1816 std::vector<CHSharedObjectEntry>& csoe = cso.entries;
1811   - HSharedObject& so = m->shared_object_hints;
  1817 + HSharedObject& so = shared_object_hints_;
1812 1818 std::vector<HSharedObjectEntry>& soe = so.entries;
1813 1819 soe.clear();
1814 1820  
... ... @@ -1851,13 +1857,13 @@ Lin::calculateHSharedObject(QPDFWriter::NewObjTable const&amp; new_obj, QPDFWriter::
1851 1857 void
1852 1858 Lin::calculateHOutline(QPDFWriter::NewObjTable const& new_obj, QPDFWriter::ObjTable const& obj)
1853 1859 {
1854   - HGeneric& cho = m->c_outline_data;
  1860 + HGeneric& cho = c_outline_data_;
1855 1861  
1856 1862 if (cho.nobjects == 0) {
1857 1863 return;
1858 1864 }
1859 1865  
1860   - HGeneric& ho = m->outline_hints;
  1866 + HGeneric& ho = outline_hints_;
1861 1867  
1862 1868 ho.first_object = obj[cho.first_object].renumber;
1863 1869 ho.first_object_offset = new_obj[ho.first_object].xref.getOffset();
... ... @@ -1902,7 +1908,7 @@ write_vector_vector(
1902 1908 void
1903 1909 Lin::writeHPageOffset(BitWriter& w)
1904 1910 {
1905   - HPageOffset& t = m->page_offset_hints;
  1911 + HPageOffset& t = page_offset_hints_;
1906 1912  
1907 1913 w.writeBitsInt(t.min_nobjects, 32); // 1
1908 1914 w.writeBits(toULL(t.first_page_offset), 32); // 2
... ... @@ -1949,7 +1955,7 @@ Lin::writeHPageOffset(BitWriter&amp; w)
1949 1955 void
1950 1956 Lin::writeHSharedObject(BitWriter& w)
1951 1957 {
1952   - HSharedObject& t = m->shared_object_hints;
  1958 + HSharedObject& t = shared_object_hints_;
1953 1959  
1954 1960 w.writeBitsInt(t.first_shared_obj, 32); // 1
1955 1961 w.writeBits(toULL(t.first_shared_offset), 32); // 2
... ... @@ -2011,9 +2017,9 @@ Lin::generateHintStream(
2011 2017 S = toI(c.getCount());
2012 2018 writeHSharedObject(w);
2013 2019 O = 0;
2014   - if (m->outline_hints.nobjects > 0) {
  2020 + if (outline_hints_.nobjects > 0) {
2015 2021 O = toI(c.getCount());
2016   - writeHGeneric(w, m->outline_hints);
  2022 + writeHGeneric(w, outline_hints_);
2017 2023 }
2018 2024 if (compressed) {
2019 2025 hint_buffer = pl::pipe<Pl_Flate>(hint_buffer, Pl_Flate::a_deflate);
... ...
libqpdf/QPDF_objects.cc
... ... @@ -157,7 +157,7 @@ Objects::parse(char const* password)
157 157 throw damagedPDF("", -1, std::string("error reading xref: ") + e.what());
158 158 }
159 159 } catch (QPDFExc& e) {
160   - if (m->attempt_recovery) {
  160 + if (!cf.surpress_recovery()) {
161 161 reconstruct_xref(e, xref_offset > 0);
162 162 } else {
163 163 throw;
... ... @@ -694,7 +694,7 @@ Objects::read_xrefTable(qpdf_offset_t xref_offset)
694 694 for (qpdf_offset_t i = obj; i - num < obj; ++i) {
695 695 if (i == 0) {
696 696 // This is needed by checkLinearization()
697   - m->first_xref_item_offset = m->file->tell();
  697 + first_xref_item_offset_ = m->file->tell();
698 698 }
699 699 // For xref_table, these will always be small enough to be ints
700 700 qpdf_offset_t f1 = 0;
... ... @@ -736,7 +736,7 @@ Objects::read_xrefTable(qpdf_offset_t xref_offset)
736 736 }
737 737  
738 738 if (cur_trailer.hasKey("/XRefStm")) {
739   - if (m->ignore_xref_streams) {
  739 + if (cf.ignore_xref_streams()) {
740 740 QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer");
741 741 } else {
742 742 if (cur_trailer.getKey("/XRefStm").isInteger()) {
... ... @@ -763,7 +763,7 @@ Objects::read_xrefTable(qpdf_offset_t xref_offset)
763 763 qpdf_offset_t
764 764 Objects::read_xrefStream(qpdf_offset_t xref_offset, bool in_stream_recovery)
765 765 {
766   - if (!m->ignore_xref_streams) {
  766 + if (!cf.ignore_xref_streams()) {
767 767 QPDFObjectHandle xref_obj;
768 768 try {
769 769 m->in_read_xref_stream = true;
... ... @@ -956,14 +956,14 @@ Objects::processXRefStream(
956 956 // object record, in which case the generation number appears as the third field.
957 957 if (saw_first_compressed_object) {
958 958 if (fields[0] != 2) {
959   - m->uncompressed_after_compressed = true;
  959 + uncompressed_after_compressed_ = true;
960 960 }
961 961 } else if (fields[0] == 2) {
962 962 saw_first_compressed_object = true;
963 963 }
964 964 if (obj == 0) {
965 965 // This is needed by checkLinearization()
966   - m->first_xref_item_offset = xref_offset;
  966 + first_xref_item_offset_ = xref_offset;
967 967 } else if (fields[0] == 0) {
968 968 // Ignore fields[2], which we don't care about in this case. This works around the
969 969 // issue of some PDF files that put invalid values, like -1, here for deleted
... ... @@ -1073,7 +1073,7 @@ Objects::insertFreeXrefEntry(QPDFObjGen og)
1073 1073 void
1074 1074 QPDF::showXRefTable()
1075 1075 {
1076   - auto& cout = *m->log->getInfo();
  1076 + auto& cout = *m->cf.log()->getInfo();
1077 1077 for (auto const& iter: m->xref_table) {
1078 1078 QPDFObjGen const& og = iter.first;
1079 1079 QPDFXRefEntry const& entry = iter.second;
... ... @@ -1084,15 +1084,15 @@ QPDF::showXRefTable()
1084 1084 break;
1085 1085  
1086 1086 case 2:
1087   - *m->log->getInfo() << "compressed; stream = " << entry.getObjStreamNumber()
1088   - << ", index = " << entry.getObjStreamIndex();
  1087 + *m->cf.log()->getInfo() << "compressed; stream = " << entry.getObjStreamNumber()
  1088 + << ", index = " << entry.getObjStreamIndex();
1089 1089 break;
1090 1090  
1091 1091 default:
1092 1092 throw std::logic_error("unknown cross-reference table type while showing xref_table");
1093 1093 break;
1094 1094 }
1095   - m->log->info("\n");
  1095 + m->cf.log()->info("\n");
1096 1096 }
1097 1097 }
1098 1098  
... ... @@ -1248,7 +1248,7 @@ Objects::readStream(QPDFObjectHandle&amp; object, QPDFObjGen og, qpdf_offset_t offse
1248 1248 throw damagedPDF("expected endstream");
1249 1249 }
1250 1250 } catch (QPDFExc& e) {
1251   - if (m->attempt_recovery) {
  1251 + if (!cf.surpress_recovery()) {
1252 1252 warn(e);
1253 1253 length = recoverStreamLength(m->file, og, stream_offset);
1254 1254 } else {
... ... @@ -1431,7 +1431,7 @@ Objects::readObjectAtOffset(
1431 1431 QPDFObjGen og;
1432 1432 setLastObjectDescription(description, exp_og);
1433 1433  
1434   - if (!m->attempt_recovery) {
  1434 + if (cf.surpress_recovery()) {
1435 1435 try_recovery = false;
1436 1436 }
1437 1437  
... ...
libqpdf/qpdf/QPDFJob_private.hh
... ... @@ -5,6 +5,7 @@
5 5  
6 6 #include <qpdf/ClosedFileInputSource.hh>
7 7 #include <qpdf/QPDFLogger.hh>
  8 +#include <qpdf/QPDF_private.hh>
8 9  
9 10 // A selection of pages from a single input PDF to be included in the output. This corresponds to a
10 11 // single clause in the --pages option.
... ... @@ -149,7 +150,7 @@ class QPDFJob::Members
149 150  
150 151 public:
151 152 Members(QPDFJob& job) :
152   - log(QPDFLogger::defaultLogger()),
  153 + log(qcf.log()),
153 154 inputs(job)
154 155 {
155 156 }
... ... @@ -167,6 +168,7 @@ class QPDFJob::Members
167 168 static int constexpr DEFAULT_OI_MIN_AREA = 16384;
168 169 static int constexpr DEFAULT_II_MIN_BYTES = 1024;
169 170  
  171 + qpdf::Doc::Config qcf;
170 172 std::shared_ptr<QPDFLogger> log;
171 173 std::string message_prefix{"qpdf"};
172 174 bool warnings{false};
... ... @@ -179,11 +181,9 @@ class QPDFJob::Members
179 181 int split_pages{0};
180 182 bool progress{false};
181 183 std::function<void(int)> progress_handler{nullptr};
182   - bool suppress_warnings{false};
183 184 bool warnings_exit_zero{false};
184 185 bool copy_encryption{false};
185 186 bool encrypt{false};
186   - bool password_is_hex_key{false};
187 187 bool suppress_password_recovery{false};
188 188 password_mode_e password_mode{pm_auto};
189 189 bool allow_insecure{false};
... ... @@ -218,10 +218,8 @@ class QPDFJob::Members
218 218 bool decode_level_set{false};
219 219 bool normalize_set{false};
220 220 bool normalize{false};
221   - bool suppress_recovery{false};
222 221 bool object_stream_set{false};
223 222 qpdf_object_stream_e object_stream_mode{qpdf_o_preserve};
224   - bool ignore_xref_streams{false};
225 223 bool qdf_mode{false};
226 224 bool preserve_unreferenced_objects{false};
227 225 remove_unref_e remove_unreferenced_page_resources{re_auto};
... ...
libqpdf/qpdf/QPDF_private.hh
... ... @@ -5,6 +5,7 @@
5 5  
6 6 #include <qpdf/QPDFAcroFormDocumentHelper.hh>
7 7 #include <qpdf/QPDFEmbeddedFileDocumentHelper.hh>
  8 +#include <qpdf/QPDFLogger.hh>
8 9 #include <qpdf/QPDFObject_private.hh>
9 10 #include <qpdf/QPDFOutlineDocumentHelper.hh>
10 11 #include <qpdf/QPDFPageDocumentHelper.hh>
... ... @@ -20,6 +21,135 @@ namespace qpdf
20 21 {
21 22 class OffsetBuffer;
22 23 } // namespace is
  24 +
  25 + class Doc: public QPDF
  26 + {
  27 + public:
  28 + class Config
  29 + {
  30 + public:
  31 + Config() :
  32 + log_(QPDFLogger::defaultLogger())
  33 + {
  34 + }
  35 +
  36 + bool
  37 + password_is_hex_key() const
  38 + {
  39 + return password_is_hex_key_;
  40 + }
  41 +
  42 + Config&
  43 + password_is_hex_key(bool val)
  44 + {
  45 + password_is_hex_key_ = val;
  46 + return *this;
  47 + }
  48 +
  49 + bool
  50 + ignore_xref_streams() const
  51 + {
  52 + return ignore_xref_streams_;
  53 + }
  54 +
  55 + Config&
  56 + ignore_xref_streams(bool val)
  57 + {
  58 + ignore_xref_streams_ = val;
  59 + return *this;
  60 + }
  61 +
  62 + std::shared_ptr<QPDFLogger>
  63 + log() const
  64 + {
  65 + return log_;
  66 + }
  67 +
  68 + Config&
  69 + log(std::shared_ptr<QPDFLogger> val)
  70 + {
  71 + log_ = val;
  72 + return *this;
  73 + }
  74 +
  75 + bool
  76 + suppress_warnings() const
  77 + {
  78 + return suppress_warnings_;
  79 + }
  80 +
  81 + Config&
  82 + suppress_warnings(bool val)
  83 + {
  84 + suppress_warnings_ = val;
  85 + return *this;
  86 + }
  87 +
  88 + size_t
  89 + max_warnings() const
  90 + {
  91 + return max_warnings_;
  92 + }
  93 +
  94 + Config&
  95 + max_warnings(size_t val)
  96 + {
  97 + max_warnings_ = val;
  98 + return *this;
  99 + }
  100 +
  101 + bool
  102 + surpress_recovery() const
  103 + {
  104 + return surpress_recovery_;
  105 + }
  106 +
  107 + Config&
  108 + surpress_recovery(bool val)
  109 + {
  110 + surpress_recovery_ = val;
  111 + return *this;
  112 + }
  113 +
  114 + bool
  115 + immediate_copy_from() const
  116 + {
  117 + return immediate_copy_from_;
  118 + }
  119 +
  120 + Config&
  121 + immediate_copy_from(bool val)
  122 + {
  123 + immediate_copy_from_ = val;
  124 + return *this;
  125 + }
  126 +
  127 + bool
  128 + check_mode() const
  129 + {
  130 + return check_mode_;
  131 + }
  132 +
  133 + Config&
  134 + check_mode(bool val)
  135 + {
  136 + check_mode_ = val;
  137 + return *this;
  138 + }
  139 +
  140 + private:
  141 + std::shared_ptr<QPDFLogger> log_;
  142 +
  143 + size_t max_warnings_{0};
  144 +
  145 + bool password_is_hex_key_{false};
  146 + bool ignore_xref_streams_{false};
  147 + bool suppress_warnings_{false};
  148 + bool surpress_recovery_{false};
  149 + bool check_mode_{false};
  150 + bool immediate_copy_from_{false};
  151 + }; // Class Config
  152 + }; // class Doc
23 153 } // namespace qpdf
24 154  
25 155 class BitStream;
... ... @@ -106,168 +236,8 @@ class QPDF::StringDecrypter final: public QPDFObjectHandle::StringDecrypter
106 236 QPDF* qpdf;
107 237 QPDFObjGen og;
108 238 };
109   -
110   -// PDF 1.4: Table F.4
111   -struct QPDF::HPageOffsetEntry
112   -{
113   - int delta_nobjects{0}; // 1
114   - qpdf_offset_t delta_page_length{0}; // 2
115   - // vectors' sizes = nshared_objects
116   - int nshared_objects{0}; // 3
117   - std::vector<int> shared_identifiers; // 4
118   - std::vector<int> shared_numerators; // 5
119   - qpdf_offset_t delta_content_offset{0}; // 6
120   - qpdf_offset_t delta_content_length{0}; // 7
121   -};
122   -
123   -// PDF 1.4: Table F.3
124   -struct QPDF::HPageOffset
125   -{
126   - int min_nobjects{0}; // 1
127   - qpdf_offset_t first_page_offset{0}; // 2
128   - int nbits_delta_nobjects{0}; // 3
129   - int min_page_length{0}; // 4
130   - int nbits_delta_page_length{0}; // 5
131   - int min_content_offset{0}; // 6
132   - int nbits_delta_content_offset{0}; // 7
133   - int min_content_length{0}; // 8
134   - int nbits_delta_content_length{0}; // 9
135   - int nbits_nshared_objects{0}; // 10
136   - int nbits_shared_identifier{0}; // 11
137   - int nbits_shared_numerator{0}; // 12
138   - int shared_denominator{0}; // 13
139   - // vector size is npages
140   - std::vector<HPageOffsetEntry> entries;
141   -};
142   -
143   -// PDF 1.4: Table F.6
144   -struct QPDF::HSharedObjectEntry
145   -{
146   - // Item 3 is a 128-bit signature (unsupported by Acrobat)
147   - int delta_group_length{0}; // 1
148   - int signature_present{0}; // 2 -- always 0
149   - int nobjects_minus_one{0}; // 4 -- always 0
150   -};
151   -
152   -// PDF 1.4: Table F.5
153   -struct QPDF::HSharedObject
154   -{
155   - int first_shared_obj{0}; // 1
156   - qpdf_offset_t first_shared_offset{0}; // 2
157   - int nshared_first_page{0}; // 3
158   - int nshared_total{0}; // 4
159   - int nbits_nobjects{0}; // 5
160   - int min_group_length{0}; // 6
161   - int nbits_delta_group_length{0}; // 7
162   - // vector size is nshared_total
163   - std::vector<HSharedObjectEntry> entries;
164   -};
165   -
166   -// PDF 1.4: Table F.9
167   -struct QPDF::HGeneric
168   -{
169   - int first_object{0}; // 1
170   - qpdf_offset_t first_object_offset{0}; // 2
171   - int nobjects{0}; // 3
172   - int group_length{0}; // 4
173   -};
174   -
175 239 // Other linearization data structures
176 240  
177   -// Initialized from Linearization Parameter dictionary
178   -struct QPDF::LinParameters
179   -{
180   - qpdf_offset_t file_size{0}; // /L
181   - int first_page_object{0}; // /O
182   - qpdf_offset_t first_page_end{0}; // /E
183   - size_t npages{0}; // /N
184   - qpdf_offset_t xref_zero_offset{0}; // /T
185   - int first_page{0}; // /P
186   - qpdf_offset_t H_offset{0}; // offset of primary hint stream
187   - qpdf_offset_t H_length{0}; // length of primary hint stream
188   -};
189   -
190   -// Computed hint table value data structures. These tables contain the computed values on which
191   -// the hint table values are based. They exclude things like number of bits and store actual
192   -// values instead of mins and deltas. File offsets are also absolute rather than being offset
193   -// by the size of the primary hint table. We populate the hint table structures from these
194   -// during writing and compare the hint table values with these during validation. We ignore
195   -// some values for various reasons described in the code. Those values are omitted from these
196   -// structures. Note also that object numbers are object numbers from the input file, not the
197   -// output file.
198   -
199   -// Naming convention: CHSomething is analogous to HSomething above. "CH" is computed hint.
200   -
201   -struct QPDF::CHPageOffsetEntry
202   -{
203   - int nobjects{0};
204   - int nshared_objects{0};
205   - // vectors' sizes = nshared_objects
206   - std::vector<int> shared_identifiers;
207   -};
208   -
209   -struct QPDF::CHPageOffset
210   -{
211   - // vector size is npages
212   - std::vector<CHPageOffsetEntry> entries;
213   -};
214   -
215   -struct QPDF::CHSharedObjectEntry
216   -{
217   - CHSharedObjectEntry(int object) :
218   - object(object)
219   - {
220   - }
221   -
222   - int object;
223   -};
224   -
225   -// PDF 1.4: Table F.5
226   -struct QPDF::CHSharedObject
227   -{
228   - int first_shared_obj{0};
229   - int nshared_first_page{0};
230   - int nshared_total{0};
231   - // vector size is nshared_total
232   - std::vector<CHSharedObjectEntry> entries;
233   -};
234   -
235   -// No need for CHGeneric -- HGeneric is fine as is.
236   -
237   -// Data structures to support optimization -- implemented in QPDF_optimization.cc
238   -
239   -class QPDF::ObjUser
240   -{
241   - public:
242   - enum user_e { ou_page = 1, ou_thumb, ou_trailer_key, ou_root_key, ou_root };
243   -
244   - ObjUser() = delete;
245   -
246   - // type must be ou_root
247   - ObjUser(user_e type);
248   -
249   - // type must be one of ou_page or ou_thumb
250   - ObjUser(user_e type, size_t pageno);
251   -
252   - // type must be one of ou_trailer_key or ou_root_key
253   - ObjUser(user_e type, std::string const& key);
254   -
255   - bool operator<(ObjUser const&) const;
256   -
257   - user_e ou_type;
258   - size_t pageno{0}; // if ou_page;
259   - std::string key; // if ou_trailer_key or ou_root_key
260   -};
261   -
262   -struct QPDF::UpdateObjectMapsFrame
263   -{
264   - UpdateObjectMapsFrame(ObjUser const& ou, QPDFObjectHandle oh, bool top);
265   -
266   - ObjUser const& ou;
267   - QPDFObjectHandle oh;
268   - bool top;
269   -};
270   -
271 241 class QPDF::PatternFinder final: public InputSource::Finder
272 242 {
273 243 public:
... ... @@ -296,7 +266,6 @@ class QPDF::Doc
296 266 {
297 267 public:
298 268 class Encryption;
299   - class JobSetter;
300 269 class Linearization;
301 270 class Objects;
302 271 class Pages;
... ... @@ -352,7 +321,9 @@ class QPDF::Doc
352 321 QPDF& qpdf;
353 322 QPDF::Members* m;
354 323  
  324 + qpdf::Doc::Config& cf;
355 325 QPDF::Doc::Pages& pages;
  326 + QPDF::Doc::Objects& objects;
356 327 };
357 328  
358 329 Doc() = delete;
... ... @@ -368,6 +339,18 @@ class QPDF::Doc
368 339 {
369 340 }
370 341  
  342 + qpdf::Doc::Config&
  343 + config()
  344 + {
  345 + return cf;
  346 + }
  347 +
  348 + void
  349 + config(qpdf::Doc::Config val)
  350 + {
  351 + cf = val;
  352 + }
  353 +
371 354 inline Linearization& linearization();
372 355  
373 356 inline Objects& objects();
... ... @@ -421,10 +404,13 @@ class QPDF::Doc
421 404 return *page_labels_;
422 405 }
423 406  
424   - private:
  407 + protected:
425 408 QPDF& qpdf;
426 409 QPDF::Members* m;
427 410  
  411 + qpdf::Doc::Config cf;
  412 +
  413 + private:
428 414 // Document Helpers;
429 415 std::unique_ptr<QPDFAcroFormDocumentHelper> acroform_;
430 416 std::unique_ptr<QPDFEmbeddedFileDocumentHelper> embedded_files_;
... ... @@ -564,6 +550,10 @@ class QPDF::Doc::Linearization: Common
564 550 {
565 551 }
566 552  
  553 + bool linearized();
  554 + bool check();
  555 + void show_data();
  556 +
567 557 // For QPDFWriter:
568 558  
569 559 template <typename T>
... ... @@ -593,6 +583,168 @@ class QPDF::Doc::Linearization: Common
593 583 int& O,
594 584 bool compressed);
595 585  
  586 + private:
  587 + // Data structures to support optimization -- implemented in QPDF_optimization.cc
  588 +
  589 + class ObjUser
  590 + {
  591 + public:
  592 + enum user_e { ou_page = 1, ou_thumb, ou_trailer_key, ou_root_key, ou_root };
  593 +
  594 + ObjUser() = delete;
  595 +
  596 + // type must be ou_root
  597 + ObjUser(user_e type);
  598 +
  599 + // type must be one of ou_page or ou_thumb
  600 + ObjUser(user_e type, size_t pageno);
  601 +
  602 + // type must be one of ou_trailer_key or ou_root_key
  603 + ObjUser(user_e type, std::string const& key);
  604 +
  605 + bool operator<(ObjUser const&) const;
  606 +
  607 + user_e ou_type;
  608 + size_t pageno{0}; // if ou_page;
  609 + std::string key; // if ou_trailer_key or ou_root_key
  610 + };
  611 +
  612 + struct UpdateObjectMapsFrame
  613 + {
  614 + UpdateObjectMapsFrame(ObjUser const& ou, QPDFObjectHandle oh, bool top);
  615 +
  616 + ObjUser const& ou;
  617 + QPDFObjectHandle oh;
  618 + bool top;
  619 + };
  620 +
  621 + // PDF 1.4: Table F.4
  622 + struct HPageOffsetEntry
  623 + {
  624 + int delta_nobjects{0}; // 1
  625 + qpdf_offset_t delta_page_length{0}; // 2
  626 + // vectors' sizes = nshared_objects
  627 + int nshared_objects{0}; // 3
  628 + std::vector<int> shared_identifiers; // 4
  629 + std::vector<int> shared_numerators; // 5
  630 + qpdf_offset_t delta_content_offset{0}; // 6
  631 + qpdf_offset_t delta_content_length{0}; // 7
  632 + };
  633 +
  634 + // PDF 1.4: Table F.3
  635 + struct HPageOffset
  636 + {
  637 + int min_nobjects{0}; // 1
  638 + qpdf_offset_t first_page_offset{0}; // 2
  639 + int nbits_delta_nobjects{0}; // 3
  640 + int min_page_length{0}; // 4
  641 + int nbits_delta_page_length{0}; // 5
  642 + int min_content_offset{0}; // 6
  643 + int nbits_delta_content_offset{0}; // 7
  644 + int min_content_length{0}; // 8
  645 + int nbits_delta_content_length{0}; // 9
  646 + int nbits_nshared_objects{0}; // 10
  647 + int nbits_shared_identifier{0}; // 11
  648 + int nbits_shared_numerator{0}; // 12
  649 + int shared_denominator{0}; // 13
  650 + // vector size is npages
  651 + std::vector<HPageOffsetEntry> entries;
  652 + };
  653 +
  654 + // PDF 1.4: Table F.6
  655 + struct HSharedObjectEntry
  656 + {
  657 + // Item 3 is a 128-bit signature (unsupported by Acrobat)
  658 + int delta_group_length{0}; // 1
  659 + int signature_present{0}; // 2 -- always 0
  660 + int nobjects_minus_one{0}; // 4 -- always 0
  661 + };
  662 +
  663 + // PDF 1.4: Table F.5
  664 + struct HSharedObject
  665 + {
  666 + int first_shared_obj{0}; // 1
  667 + qpdf_offset_t first_shared_offset{0}; // 2
  668 + int nshared_first_page{0}; // 3
  669 + int nshared_total{0}; // 4
  670 + int nbits_nobjects{0}; // 5
  671 + int min_group_length{0}; // 6
  672 + int nbits_delta_group_length{0}; // 7
  673 + // vector size is nshared_total
  674 + std::vector<HSharedObjectEntry> entries;
  675 + };
  676 +
  677 + // PDF 1.4: Table F.9
  678 + struct HGeneric
  679 + {
  680 + int first_object{0}; // 1
  681 + qpdf_offset_t first_object_offset{0}; // 2
  682 + int nobjects{0}; // 3
  683 + int group_length{0}; // 4
  684 + };
  685 +
  686 + // Other linearization data structures
  687 +
  688 + // Initialized from Linearization Parameter dictionary
  689 + struct LinParameters
  690 + {
  691 + qpdf_offset_t file_size{0}; // /L
  692 + int first_page_object{0}; // /O
  693 + qpdf_offset_t first_page_end{0}; // /E
  694 + size_t npages{0}; // /N
  695 + qpdf_offset_t xref_zero_offset{0}; // /T
  696 + int first_page{0}; // /P
  697 + qpdf_offset_t H_offset{0}; // offset of primary hint stream
  698 + qpdf_offset_t H_length{0}; // length of primary hint stream
  699 + };
  700 +
  701 + // Computed hint table value data structures. These tables contain the computed values on which
  702 + // the hint table values are based. They exclude things like number of bits and store actual
  703 + // values instead of mins and deltas. File offsets are also absolute rather than being offset
  704 + // by the size of the primary hint table. We populate the hint table structures from these
  705 + // during writing and compare the hint table values with these during validation. We ignore
  706 + // some values for various reasons described in the code. Those values are omitted from these
  707 + // structures. Note also that object numbers are object numbers from the input file, not the
  708 + // output file.
  709 +
  710 + // Naming convention: CHSomething is analogous to HSomething above. "CH" is computed hint.
  711 +
  712 + struct CHPageOffsetEntry
  713 + {
  714 + int nobjects{0};
  715 + int nshared_objects{0};
  716 + // vectors' sizes = nshared_objects
  717 + std::vector<int> shared_identifiers;
  718 + };
  719 +
  720 + struct CHPageOffset
  721 + {
  722 + // vector size is npages
  723 + std::vector<CHPageOffsetEntry> entries;
  724 + };
  725 +
  726 + struct CHSharedObjectEntry
  727 + {
  728 + CHSharedObjectEntry(int object) :
  729 + object(object)
  730 + {
  731 + }
  732 +
  733 + int object;
  734 + };
  735 +
  736 + // PDF 1.4: Table F.5
  737 + struct CHSharedObject
  738 + {
  739 + int first_shared_obj{0};
  740 + int nshared_first_page{0};
  741 + int nshared_total{0};
  742 + // vector size is nshared_total
  743 + std::vector<CHSharedObjectEntry> entries;
  744 + };
  745 +
  746 + // No need for CHGeneric -- HGeneric is fine as is.
  747 +
596 748 // methods to support linearization checking -- implemented in QPDF_linearization.cc
597 749  
598 750 void readLinearizationData();
... ... @@ -647,6 +799,36 @@ class QPDF::Doc::Linearization: Common
647 799 std::function<int(QPDFObjectHandle&)> skip_stream_parameters);
648 800 void filterCompressedObjects(std::map<int, int> const& object_stream_data);
649 801 void filterCompressedObjects(QPDFWriter::ObjTable const& object_stream_data);
  802 +
  803 + // Optimization data
  804 + std::map<ObjUser, std::set<QPDFObjGen>> obj_user_to_objects_;
  805 + std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users_;
  806 +
  807 + // Linearization data
  808 + bool linearization_warnings_{false}; // set by linearizationWarning, used by checkLinearization
  809 +
  810 + // Linearization parameter dictionary and hint table data: may be read from file or computed
  811 + // prior to writing a linearized file
  812 + QPDFObjectHandle lindict_;
  813 + LinParameters linp_;
  814 + HPageOffset page_offset_hints_;
  815 + HSharedObject shared_object_hints_;
  816 + HGeneric outline_hints_;
  817 +
  818 + // Computed linearization data: used to populate above tables during writing and to compare
  819 + // with them during validation. c_ means computed.
  820 + LinParameters c_linp_;
  821 + CHPageOffset c_page_offset_data_;
  822 + CHSharedObject c_shared_object_data_;
  823 + HGeneric c_outline_data_;
  824 +
  825 + // Object ordering data for linearized files: initialized by calculateLinearizationData().
  826 + // Part numbers refer to the PDF 1.4 specification.
  827 + std::vector<QPDFObjectHandle> part4_;
  828 + std::vector<QPDFObjectHandle> part6_;
  829 + std::vector<QPDFObjectHandle> part7_;
  830 + std::vector<QPDFObjectHandle> part8_;
  831 + std::vector<QPDFObjectHandle> part9_;
650 832 };
651 833  
652 834 class QPDF::Doc::Objects: Common
... ... @@ -743,7 +925,7 @@ class QPDF::Doc::Objects: Common
743 925 return copier_;
744 926 }
745 927  
746   - bool immediate_copy_from() const;
  928 + // bool immediate_copy_from() const;
747 929  
748 930 private:
749 931 std::shared_ptr<Copier> copier_;
... ... @@ -776,6 +958,17 @@ class QPDF::Doc::Objects: Common
776 958 return streams_;
777 959 }
778 960  
  961 + // actual value from file
  962 + qpdf_offset_t
  963 + first_xref_item_offset() const
  964 + {
  965 + return first_xref_item_offset_;
  966 + }
  967 + bool
  968 + uncompressed_after_compressed() const
  969 + {
  970 + return uncompressed_after_compressed_;
  971 + }
779 972 void parse(char const* password);
780 973 std::shared_ptr<QPDFObject> const& resolve(QPDFObjGen og);
781 974 void inParse(bool);
... ... @@ -847,6 +1040,10 @@ class QPDF::Doc::Objects: Common
847 1040  
848 1041 Foreign foreign_;
849 1042 Streams streams_;
  1043 +
  1044 + // Linearization data
  1045 + qpdf_offset_t first_xref_item_offset_{0}; // actual value from file
  1046 + bool uncompressed_after_compressed_{false};
850 1047 }; // class QPDF::Doc::Objects
851 1048  
852 1049 // This class is used to represent a PDF Pages tree.
... ... @@ -969,18 +1166,11 @@ class QPDF::Members: Doc
969 1166 Doc::Linearization lin;
970 1167 Doc::Objects objects;
971 1168 Doc::Pages pages;
972   - std::shared_ptr<QPDFLogger> log;
973 1169 unsigned long long unique_id{0};
974 1170 qpdf::Tokenizer tokenizer;
975 1171 std::shared_ptr<InputSource> file;
976 1172 std::string last_object_description;
977 1173 std::shared_ptr<QPDFObject::Description> last_ostream_description;
978   - bool provided_password_is_hex_key{false};
979   - bool ignore_xref_streams{false};
980   - bool suppress_warnings{false};
981   - size_t max_warnings{0};
982   - bool attempt_recovery{true};
983   - bool check_mode{false};
984 1174 std::shared_ptr<EncryptionParameters> encp;
985 1175 std::string pdf_version;
986 1176 std::map<QPDFObjGen, QPDFXRefEntry> xref_table;
... ... @@ -995,42 +1185,9 @@ class QPDF::Members: Doc
995 1185 bool reconstructed_xref{false};
996 1186 bool in_read_xref_stream{false};
997 1187 bool fixed_dangling_refs{false};
998   - bool immediate_copy_from{false};
999 1188 bool in_parse{false};
1000 1189 bool parsed{false};
1001 1190 std::set<int> resolved_object_streams;
1002   -
1003   - // Linearization data
1004   - qpdf_offset_t first_xref_item_offset{0}; // actual value from file
1005   - bool uncompressed_after_compressed{false};
1006   - bool linearization_warnings{false}; // set by linearizationWarning, used by checkLinearization
1007   -
1008   - // Linearization parameter dictionary and hint table data: may be read from file or computed
1009   - // prior to writing a linearized file
1010   - QPDFObjectHandle lindict;
1011   - LinParameters linp;
1012   - HPageOffset page_offset_hints;
1013   - HSharedObject shared_object_hints;
1014   - HGeneric outline_hints;
1015   -
1016   - // Computed linearization data: used to populate above tables during writing and to compare
1017   - // with them during validation. c_ means computed.
1018   - LinParameters c_linp;
1019   - CHPageOffset c_page_offset_data;
1020   - CHSharedObject c_shared_object_data;
1021   - HGeneric c_outline_data;
1022   -
1023   - // Object ordering data for linearized files: initialized by calculateLinearizationData().
1024   - // Part numbers refer to the PDF 1.4 specification.
1025   - std::vector<QPDFObjectHandle> part4;
1026   - std::vector<QPDFObjectHandle> part6;
1027   - std::vector<QPDFObjectHandle> part7;
1028   - std::vector<QPDFObjectHandle> part8;
1029   - std::vector<QPDFObjectHandle> part9;
1030   -
1031   - // Optimization data
1032   - std::map<ObjUser, std::set<QPDFObjGen>> obj_user_to_objects;
1033   - std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
1034 1191 };
1035 1192  
1036 1193 // The Resolver class is restricted to QPDFObject and BaseHandle so that only it can resolve
... ... @@ -1051,7 +1208,9 @@ class QPDF::Doc::Resolver
1051 1208 inline QPDF::Doc::Common::Common(QPDF& qpdf, QPDF::Members* m) :
1052 1209 qpdf(qpdf),
1053 1210 m(m),
1054   - pages(m->pages)
  1211 + cf(m->cf),
  1212 + pages(m->pages),
  1213 + objects(m->objects)
1055 1214 {
1056 1215 }
1057 1216  
... ...
qpdf/qpdf.testcov
... ... @@ -248,7 +248,6 @@ QPDFJob password not encodable 0
248 248 QPDFJob auto-encode password 0
249 249 QPDFJob bytes fallback warning 0
250 250 QPDFJob invalid utf-8 in auto 0
251   -QPDFJob input password hex-bytes 0
252 251 QPDFFormFieldObjectHelper replaced BMC at EOF 0
253 252 QPDFFormFieldObjectHelper fallback Tf 0
254 253 QPDFPageObjectHelper copy shared attribute 1
... ...
qpdf/qtest/qpdf/catalgg.out
1   -checking catalgg.pdf
2 1 WARNING: catalgg.pdf: catalog /Type entry missing or invalid
  2 +checking catalgg.pdf
3 3 PDF Version: 1.3
4 4 File is not encrypted
5 5 File is not linearized
... ...