Commit 05cb757df564e4196c89fbf88c00489b23b65102

Authored by m-holger
Committed by GitHub
2 parents 7e623fd9 a944fe35

Merge pull request #1544 from m-holger/writer

Remove implementation detail from QPDFWriter.hh
include/qpdf/QPDFWriter.hh
@@ -20,11 +20,19 @@ @@ -20,11 +20,19 @@
20 #ifndef QPDFWRITER_HH 20 #ifndef QPDFWRITER_HH
21 #define QPDFWRITER_HH 21 #define QPDFWRITER_HH
22 22
  23 +#include <qpdf/Constants.h>
23 #include <qpdf/DLL.h> 24 #include <qpdf/DLL.h>
24 #include <qpdf/Types.h> 25 #include <qpdf/Types.h>
25 26
  27 +#include <qpdf/Buffer.hh>
  28 +#include <qpdf/PDFVersion.hh>
  29 +#include <qpdf/Pipeline.hh>
  30 +#include <qpdf/Pl_Buffer.hh>
  31 +#include <qpdf/QPDFObjGen.hh>
  32 +#include <qpdf/QPDFObjectHandle.hh>
  33 +#include <qpdf/QPDFXRefEntry.hh>
  34 +
26 #include <bitset> 35 #include <bitset>
27 -#include <concepts>  
28 #include <cstdio> 36 #include <cstdio>
29 #include <functional> 37 #include <functional>
30 #include <list> 38 #include <list>
@@ -35,24 +43,7 @@ @@ -35,24 +43,7 @@
35 #include <string_view> 43 #include <string_view>
36 #include <vector> 44 #include <vector>
37 45
38 -#include <qpdf/Constants.h>  
39 -  
40 -#include <qpdf/Buffer.hh>  
41 -#include <qpdf/PDFVersion.hh>  
42 -#include <qpdf/Pipeline.hh>  
43 -#include <qpdf/Pl_Buffer.hh>  
44 -#include <qpdf/QPDFObjGen.hh>  
45 -#include <qpdf/QPDFObjectHandle.hh>  
46 -#include <qpdf/QPDFXRefEntry.hh>  
47 -  
48 -namespace qpdf::pl  
49 -{  
50 - struct Link;  
51 -}  
52 -  
53 class QPDF; 46 class QPDF;
54 -class Pl_Count;  
55 -class Pl_MD5;  
56 47
57 // This class implements a simple writer for saving QPDF objects to new PDF files. See comments 48 // This class implements a simple writer for saving QPDF objects to new PDF files. See comments
58 // through the header file for additional details. 49 // through the header file for additional details.
@@ -449,132 +440,8 @@ class QPDFWriter @@ -449,132 +440,8 @@ class QPDFWriter
449 class NewObjTable; 440 class NewObjTable;
450 441
451 private: 442 private:
452 - // flags used by unparseObject  
453 - static int const f_stream = 1 << 0;  
454 - static int const f_filtered = 1 << 1;  
455 - static int const f_in_ostream = 1 << 2;  
456 - static int const f_hex_string = 1 << 3;  
457 - static int const f_no_encryption = 1 << 4;  
458 -  
459 - enum trailer_e { t_normal, t_lin_first, t_lin_second };  
460 -  
461 - unsigned int bytesNeeded(long long n);  
462 - void writeBinary(unsigned long long val, unsigned int bytes);  
463 - QPDFWriter& write(std::string_view str);  
464 - QPDFWriter& write(size_t count, char c);  
465 - QPDFWriter& write(std::integral auto val);  
466 - QPDFWriter& write_name(std::string const& str);  
467 - QPDFWriter& write_string(std::string const& str, bool force_binary = false);  
468 - QPDFWriter& write_encrypted(std::string_view str);  
469 -  
470 - template <typename... Args>  
471 - QPDFWriter& write_qdf(Args&&... args);  
472 - template <typename... Args>  
473 - QPDFWriter& write_no_qdf(Args&&... args);  
474 - void assignCompressedObjectNumbers(QPDFObjGen og);  
475 - void enqueueObject(QPDFObjectHandle object);  
476 - void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);  
477 - void writeObjectStream(QPDFObjectHandle object);  
478 - void writeObject(QPDFObjectHandle object, int object_stream_index = -1);  
479 - void writeTrailer(  
480 - trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);  
481 - bool willFilterStream(  
482 - QPDFObjectHandle stream,  
483 - bool& compress_stream,  
484 - bool& is_metadata,  
485 - std::string* stream_data);  
486 - void unparseObject(  
487 - QPDFObjectHandle object,  
488 - size_t level,  
489 - int flags,  
490 - // for stream dictionaries  
491 - size_t stream_length = 0,  
492 - bool compress = false);  
493 - void unparseChild(QPDFObjectHandle const& child, size_t level, int flags);  
494 - void initializeSpecialStreams();  
495 - void preserveObjectStreams();  
496 - void generateObjectStreams();  
497 - std::string getOriginalID1();  
498 - void generateID(bool encrypted);  
499 - void interpretR3EncryptionParameters(  
500 - bool allow_accessibility,  
501 - bool allow_extract,  
502 - bool allow_assemble,  
503 - bool allow_annotate_and_form,  
504 - bool allow_form_filling,  
505 - bool allow_modify_other,  
506 - qpdf_r3_print_e print,  
507 - qpdf_r3_modify_e modify);  
508 - void disableIncompatibleEncryption(int major, int minor, int extension_level);  
509 - void parseVersion(std::string const& version, int& major, int& minor) const;  
510 - int compareVersions(int major1, int minor1, int major2, int minor2) const;  
511 - void setEncryptionParameters(char const* user_password, char const* owner_password);  
512 - void setEncryptionMinimumVersion();  
513 - void setDataKey(int objid);  
514 - int openObject(int objid = 0);  
515 - void closeObject(int objid);  
516 - QPDFObjectHandle getTrimmedTrailer();  
517 - void prepareFileForWrite();  
518 - void enqueueObjectsStandard();  
519 - void enqueueObjectsPCLm();  
520 - void indicateProgress(bool decrement, bool finished);  
521 - void writeStandard();  
522 - void writeLinearized();  
523 - void enqueuePart(std::vector<QPDFObjectHandle>& part);  
524 - void writeEncryptionDictionary();  
525 - void initializeTables(size_t extra = 0);  
526 - void doWriteSetup();  
527 - void writeHeader();  
528 - void writeHintStream(int hint_id);  
529 - qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);  
530 - qpdf_offset_t writeXRefTable(  
531 - trailer_e which,  
532 - int first,  
533 - int last,  
534 - int size,  
535 - // for linearization  
536 - qpdf_offset_t prev,  
537 - bool suppress_offsets,  
538 - int hint_id,  
539 - qpdf_offset_t hint_offset,  
540 - qpdf_offset_t hint_length,  
541 - int linearization_pass);  
542 - qpdf_offset_t writeXRefStream(  
543 - int objid,  
544 - int max_id,  
545 - qpdf_offset_t max_offset,  
546 - trailer_e which,  
547 - int first,  
548 - int last,  
549 - int size);  
550 - qpdf_offset_t writeXRefStream(  
551 - int objid,  
552 - int max_id,  
553 - qpdf_offset_t max_offset,  
554 - trailer_e which,  
555 - int first,  
556 - int last,  
557 - int size,  
558 - // for linearization  
559 - qpdf_offset_t prev,  
560 - int hint_id,  
561 - qpdf_offset_t hint_offset,  
562 - qpdf_offset_t hint_length,  
563 - bool skip_compression,  
564 - int linearization_pass);  
565 - size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes);  
566 -  
567 - // When filtering subsections, push additional pipelines to the stack. When ready to switch,  
568 - // activate the pipeline stack. When the passed in PipelinePopper goes out of scope, the stack  
569 - // is popped.  
570 -  
571 - void adjustAESStreamLength(size_t& length);  
572 - void computeDeterministicIDData();  
573 -  
574 class Members; 443 class Members;
575 444
576 - // Keep all member variables inside the Members object, which we dynamically allocate. This  
577 - // makes it possible to add new private members without breaking binary compatibility.  
578 std::shared_ptr<Members> m; 445 std::shared_ptr<Members> m;
579 }; 446 };
580 447
libqpdf/NNTree.cc
@@ -666,7 +666,7 @@ NNTreeImpl::repair() @@ -666,7 +666,7 @@ NNTreeImpl::repair()
666 NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false); 666 NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false);
667 std::map<QPDFObjectHandle, QPDFObjectHandle, Cmp> items; 667 std::map<QPDFObjectHandle, QPDFObjectHandle, Cmp> items;
668 for (auto const& [key, value]: *this) { 668 for (auto const& [key, value]: *this) {
669 - if (key && value && repl.keyValid(key) && repl.value_valid(value) ) { 669 + if (key && value && repl.keyValid(key) && repl.value_valid(value)) {
670 items.insert_or_assign(key, value); 670 items.insert_or_assign(key, value);
671 } 671 }
672 } 672 }
libqpdf/QPDFWriter.cc
@@ -11,7 +11,6 @@ @@ -11,7 +11,6 @@
11 #include <qpdf/Pl_PNGFilter.hh> 11 #include <qpdf/Pl_PNGFilter.hh>
12 #include <qpdf/Pl_RC4.hh> 12 #include <qpdf/Pl_RC4.hh>
13 #include <qpdf/Pl_StdioFile.hh> 13 #include <qpdf/Pl_StdioFile.hh>
14 -#include <qpdf/Pl_String.hh>  
15 #include <qpdf/QIntC.hh> 14 #include <qpdf/QIntC.hh>
16 #include <qpdf/QPDFObjectHandle_private.hh> 15 #include <qpdf/QPDFObjectHandle_private.hh>
17 #include <qpdf/QPDFObject_private.hh> 16 #include <qpdf/QPDFObject_private.hh>
@@ -22,6 +21,7 @@ @@ -22,6 +21,7 @@
22 #include <qpdf/Util.hh> 21 #include <qpdf/Util.hh>
23 22
24 #include <algorithm> 23 #include <algorithm>
  24 +#include <concepts>
25 #include <cstdlib> 25 #include <cstdlib>
26 #include <stdexcept> 26 #include <stdexcept>
27 27
@@ -265,12 +265,152 @@ class QPDFWriter::Members @@ -265,12 +265,152 @@ class QPDFWriter::Members
265 friend class QPDFWriter; 265 friend class QPDFWriter;
266 266
267 public: 267 public:
268 - ~Members(); 268 + // flags used by unparseObject
  269 + static int const f_stream = 1 << 0;
  270 + static int const f_filtered = 1 << 1;
  271 + static int const f_in_ostream = 1 << 2;
  272 + static int const f_hex_string = 1 << 3;
  273 + static int const f_no_encryption = 1 << 4;
  274 +
  275 + enum trailer_e { t_normal, t_lin_first, t_lin_second };
  276 +
  277 + Members(QPDFWriter& w, QPDF& pdf) :
  278 + w(w),
  279 + pdf(pdf),
  280 + root_og(
  281 + pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)),
  282 + pipeline_stack(pipeline)
  283 + {
  284 + }
269 285
270 - private:  
271 - Members(QPDF& pdf);  
272 Members(Members const&) = delete; 286 Members(Members const&) = delete;
273 287
  288 + ~Members()
  289 + {
  290 + if (file && close_file) {
  291 + fclose(file);
  292 + }
  293 + delete output_buffer;
  294 + }
  295 +
  296 + void write();
  297 + std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable();
  298 + void setMinimumPDFVersion(std::string const& version, int extension_level);
  299 + void copyEncryptionParameters(QPDF&);
  300 + void doWriteSetup();
  301 + void prepareFileForWrite();
  302 +
  303 + void disableIncompatibleEncryption(int major, int minor, int extension_level);
  304 + void interpretR3EncryptionParameters(
  305 + bool allow_accessibility,
  306 + bool allow_extract,
  307 + bool allow_assemble,
  308 + bool allow_annotate_and_form,
  309 + bool allow_form_filling,
  310 + bool allow_modify_other,
  311 + qpdf_r3_print_e print,
  312 + qpdf_r3_modify_e modify);
  313 + void setEncryptionParameters(char const* user_password, char const* owner_password);
  314 + void setEncryptionMinimumVersion();
  315 + void parseVersion(std::string const& version, int& major, int& minor) const;
  316 + int compareVersions(int major1, int minor1, int major2, int minor2) const;
  317 + void generateID(bool encrypted);
  318 + std::string getOriginalID1();
  319 + void initializeTables(size_t extra = 0);
  320 + void preserveObjectStreams();
  321 + void generateObjectStreams();
  322 + void initializeSpecialStreams();
  323 + void enqueueObject(QPDFObjectHandle object);
  324 + void enqueueObjectsStandard();
  325 + void enqueueObjectsPCLm();
  326 + void enqueuePart(std::vector<QPDFObjectHandle>& part);
  327 + void assignCompressedObjectNumbers(QPDFObjGen og);
  328 + QPDFObjectHandle getTrimmedTrailer();
  329 +
  330 + bool willFilterStream(
  331 + QPDFObjectHandle stream,
  332 + bool& compress_stream,
  333 + bool& is_metadata,
  334 + std::string* stream_data);
  335 + unsigned int bytesNeeded(long long n);
  336 + void writeBinary(unsigned long long val, unsigned int bytes);
  337 + Members& write(std::string_view str);
  338 + Members& write(size_t count, char c);
  339 + Members& write(std::integral auto val);
  340 + Members& write_name(std::string const& str);
  341 + Members& write_string(std::string const& str, bool force_binary = false);
  342 + Members& write_encrypted(std::string_view str);
  343 +
  344 + template <typename... Args>
  345 + Members& write_qdf(Args&&... args);
  346 + template <typename... Args>
  347 + Members& write_no_qdf(Args&&... args);
  348 + void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj);
  349 + void writeObjectStream(QPDFObjectHandle object);
  350 + void writeObject(QPDFObjectHandle object, int object_stream_index = -1);
  351 + void writeTrailer(
  352 + trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass);
  353 + void unparseObject(
  354 + QPDFObjectHandle object,
  355 + size_t level,
  356 + int flags,
  357 + // for stream dictionaries
  358 + size_t stream_length = 0,
  359 + bool compress = false);
  360 + void unparseChild(QPDFObjectHandle const& child, size_t level, int flags);
  361 + int openObject(int objid = 0);
  362 + void closeObject(int objid);
  363 + void writeStandard();
  364 + void writeLinearized();
  365 + void writeEncryptionDictionary();
  366 + void writeHeader();
  367 + void writeHintStream(int hint_id);
  368 + qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size);
  369 + qpdf_offset_t writeXRefTable(
  370 + trailer_e which,
  371 + int first,
  372 + int last,
  373 + int size,
  374 + // for linearization
  375 + qpdf_offset_t prev,
  376 + bool suppress_offsets,
  377 + int hint_id,
  378 + qpdf_offset_t hint_offset,
  379 + qpdf_offset_t hint_length,
  380 + int linearization_pass);
  381 + qpdf_offset_t writeXRefStream(
  382 + int objid,
  383 + int max_id,
  384 + qpdf_offset_t max_offset,
  385 + trailer_e which,
  386 + int first,
  387 + int last,
  388 + int size);
  389 + qpdf_offset_t writeXRefStream(
  390 + int objid,
  391 + int max_id,
  392 + qpdf_offset_t max_offset,
  393 + trailer_e which,
  394 + int first,
  395 + int last,
  396 + int size,
  397 + // for linearization
  398 + qpdf_offset_t prev,
  399 + int hint_id,
  400 + qpdf_offset_t hint_offset,
  401 + qpdf_offset_t hint_length,
  402 + bool skip_compression,
  403 + int linearization_pass);
  404 +
  405 + void setDataKey(int objid);
  406 + void indicateProgress(bool decrement, bool finished);
  407 + size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes);
  408 +
  409 + void adjustAESStreamLength(size_t& length);
  410 + void computeDeterministicIDData();
  411 +
  412 + private:
  413 + QPDFWriter& w;
274 QPDF& pdf; 414 QPDF& pdf;
275 QPDFObjGen root_og{-1, 0}; 415 QPDFObjGen root_og{-1, 0};
276 char const* filename{"unspecified"}; 416 char const* filename{"unspecified"};
@@ -341,34 +481,19 @@ class QPDFWriter::Members @@ -341,34 +481,19 @@ class QPDFWriter::Members
341 int next_progress_report{0}; 481 int next_progress_report{0};
342 }; 482 };
343 483
344 -QPDFWriter::Members::Members(QPDF& pdf) :  
345 - pdf(pdf),  
346 - root_og(pdf.getRoot().getObjGen().isIndirect() ? pdf.getRoot().getObjGen() : QPDFObjGen(-1, 0)),  
347 - pipeline_stack(pipeline)  
348 -{  
349 -}  
350 -  
351 -QPDFWriter::Members::~Members()  
352 -{  
353 - if (file && close_file) {  
354 - fclose(file);  
355 - }  
356 - delete output_buffer;  
357 -}  
358 -  
359 QPDFWriter::QPDFWriter(QPDF& pdf) : 484 QPDFWriter::QPDFWriter(QPDF& pdf) :
360 - m(new Members(pdf)) 485 + m(std::make_shared<Members>(*this, pdf))
361 { 486 {
362 } 487 }
363 488
364 QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) : 489 QPDFWriter::QPDFWriter(QPDF& pdf, char const* filename) :
365 - m(new Members(pdf)) 490 + m(std::make_shared<Members>(*this, pdf))
366 { 491 {
367 setOutputFilename(filename); 492 setOutputFilename(filename);
368 } 493 }
369 494
370 QPDFWriter::QPDFWriter(QPDF& pdf, char const* description, FILE* file, bool close_file) : 495 QPDFWriter::QPDFWriter(QPDF& pdf, char const* description, FILE* file, bool close_file) :
371 - m(new Members(pdf)) 496 + m(std::make_shared<Members>(*this, pdf))
372 { 497 {
373 setOutputFile(description, file, close_file); 498 setOutputFile(description, file, close_file);
374 } 499 }
@@ -381,11 +506,9 @@ QPDFWriter::setOutputFilename(char const* filename) @@ -381,11 +506,9 @@ QPDFWriter::setOutputFilename(char const* filename)
381 bool close_file = false; 506 bool close_file = false;
382 if (filename == nullptr) { 507 if (filename == nullptr) {
383 description = "standard output"; 508 description = "standard output";
384 - QTC::TC("qpdf", "QPDFWriter write to stdout");  
385 f = stdout; 509 f = stdout;
386 QUtil::binary_stdout(); 510 QUtil::binary_stdout();
387 } else { 511 } else {
388 - QTC::TC("qpdf", "QPDFWriter write to file");  
389 f = QUtil::safe_fopen(filename, "wb+"); 512 f = QUtil::safe_fopen(filename, "wb+");
390 close_file = true; 513 close_file = true;
391 } 514 }
@@ -508,9 +631,15 @@ QPDFWriter::setNewlineBeforeEndstream(bool val) @@ -508,9 +631,15 @@ QPDFWriter::setNewlineBeforeEndstream(bool val)
508 void 631 void
509 QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level) 632 QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level)
510 { 633 {
  634 + m->setMinimumPDFVersion(version, extension_level);
  635 +}
  636 +
  637 +void
  638 +QPDFWriter::Members::setMinimumPDFVersion(std::string const& version, int extension_level)
  639 +{
511 bool set_version = false; 640 bool set_version = false;
512 bool set_extension_level = false; 641 bool set_extension_level = false;
513 - if (m->min_pdf_version.empty()) { 642 + if (min_pdf_version.empty()) {
514 set_version = true; 643 set_version = true;
515 set_extension_level = true; 644 set_extension_level = true;
516 } else { 645 } else {
@@ -519,25 +648,24 @@ QPDFWriter::setMinimumPDFVersion(std::string const&amp; version, int extension_level @@ -519,25 +648,24 @@ QPDFWriter::setMinimumPDFVersion(std::string const&amp; version, int extension_level
519 int min_major = 0; 648 int min_major = 0;
520 int min_minor = 0; 649 int min_minor = 0;
521 parseVersion(version, old_major, old_minor); 650 parseVersion(version, old_major, old_minor);
522 - parseVersion(m->min_pdf_version, min_major, min_minor); 651 + parseVersion(min_pdf_version, min_major, min_minor);
523 int compare = compareVersions(old_major, old_minor, min_major, min_minor); 652 int compare = compareVersions(old_major, old_minor, min_major, min_minor);
524 if (compare > 0) { 653 if (compare > 0) {
525 QTC::TC("qpdf", "QPDFWriter increasing minimum version", extension_level == 0 ? 0 : 1); 654 QTC::TC("qpdf", "QPDFWriter increasing minimum version", extension_level == 0 ? 0 : 1);
526 set_version = true; 655 set_version = true;
527 set_extension_level = true; 656 set_extension_level = true;
528 } else if (compare == 0) { 657 } else if (compare == 0) {
529 - if (extension_level > m->min_extension_level) {  
530 - QTC::TC("qpdf", "QPDFWriter increasing extension level"); 658 + if (extension_level > min_extension_level) {
531 set_extension_level = true; 659 set_extension_level = true;
532 } 660 }
533 } 661 }
534 } 662 }
535 663
536 if (set_version) { 664 if (set_version) {
537 - m->min_pdf_version = version; 665 + min_pdf_version = version;
538 } 666 }
539 if (set_extension_level) { 667 if (set_extension_level) {
540 - m->min_extension_level = extension_level; 668 + min_extension_level = extension_level;
541 } 669 }
542 } 670 }
543 671
@@ -562,7 +690,6 @@ QPDFWriter::setExtraHeaderText(std::string const&amp; text) @@ -562,7 +690,6 @@ QPDFWriter::setExtraHeaderText(std::string const&amp; text)
562 { 690 {
563 m->extra_header_text = text; 691 m->extra_header_text = text;
564 if (!m->extra_header_text.empty() && *m->extra_header_text.rbegin() != '\n') { 692 if (!m->extra_header_text.empty() && *m->extra_header_text.rbegin() != '\n') {
565 - QTC::TC("qpdf", "QPDFWriter extra header text add newline");  
566 m->extra_header_text += "\n"; 693 m->extra_header_text += "\n";
567 } else { 694 } else {
568 QTC::TC("qpdf", "QPDFWriter extra header text no newline"); 695 QTC::TC("qpdf", "QPDFWriter extra header text no newline");
@@ -647,7 +774,7 @@ QPDFWriter::setR2EncryptionParametersInsecure( @@ -647,7 +774,7 @@ QPDFWriter::setR2EncryptionParametersInsecure(
647 if (!allow_annotate) { 774 if (!allow_annotate) {
648 m->encryption->setP(6, false); 775 m->encryption->setP(6, false);
649 } 776 }
650 - setEncryptionParameters(user_password, owner_password); 777 + m->setEncryptionParameters(user_password, owner_password);
651 } 778 }
652 779
653 void 780 void
@@ -663,7 +790,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( @@ -663,7 +790,7 @@ QPDFWriter::setR3EncryptionParametersInsecure(
663 qpdf_r3_print_e print) 790 qpdf_r3_print_e print)
664 { 791 {
665 m->encryption = std::make_unique<QPDF::EncryptionData>(2, 3, 16, true); 792 m->encryption = std::make_unique<QPDF::EncryptionData>(2, 3, 16, true);
666 - interpretR3EncryptionParameters( 793 + m->interpretR3EncryptionParameters(
667 allow_accessibility, 794 allow_accessibility,
668 allow_extract, 795 allow_extract,
669 allow_assemble, 796 allow_assemble,
@@ -672,7 +799,7 @@ QPDFWriter::setR3EncryptionParametersInsecure( @@ -672,7 +799,7 @@ QPDFWriter::setR3EncryptionParametersInsecure(
672 allow_modify_other, 799 allow_modify_other,
673 print, 800 print,
674 qpdf_r3m_all); 801 qpdf_r3m_all);
675 - setEncryptionParameters(user_password, owner_password); 802 + m->setEncryptionParameters(user_password, owner_password);
676 } 803 }
677 804
678 void 805 void
@@ -691,7 +818,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( @@ -691,7 +818,7 @@ QPDFWriter::setR4EncryptionParametersInsecure(
691 { 818 {
692 m->encryption = std::make_unique<QPDF::EncryptionData>(4, 4, 16, encrypt_metadata); 819 m->encryption = std::make_unique<QPDF::EncryptionData>(4, 4, 16, encrypt_metadata);
693 m->encrypt_use_aes = use_aes; 820 m->encrypt_use_aes = use_aes;
694 - interpretR3EncryptionParameters( 821 + m->interpretR3EncryptionParameters(
695 allow_accessibility, 822 allow_accessibility,
696 allow_extract, 823 allow_extract,
697 allow_assemble, 824 allow_assemble,
@@ -700,7 +827,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( @@ -700,7 +827,7 @@ QPDFWriter::setR4EncryptionParametersInsecure(
700 allow_modify_other, 827 allow_modify_other,
701 print, 828 print,
702 qpdf_r3m_all); 829 qpdf_r3m_all);
703 - setEncryptionParameters(user_password, owner_password); 830 + m->setEncryptionParameters(user_password, owner_password);
704 } 831 }
705 832
706 void 833 void
@@ -718,7 +845,7 @@ QPDFWriter::setR5EncryptionParameters( @@ -718,7 +845,7 @@ QPDFWriter::setR5EncryptionParameters(
718 { 845 {
719 m->encryption = std::make_unique<QPDF::EncryptionData>(5, 5, 32, encrypt_metadata); 846 m->encryption = std::make_unique<QPDF::EncryptionData>(5, 5, 32, encrypt_metadata);
720 m->encrypt_use_aes = true; 847 m->encrypt_use_aes = true;
721 - interpretR3EncryptionParameters( 848 + m->interpretR3EncryptionParameters(
722 allow_accessibility, 849 allow_accessibility,
723 allow_extract, 850 allow_extract,
724 allow_assemble, 851 allow_assemble,
@@ -727,7 +854,7 @@ QPDFWriter::setR5EncryptionParameters( @@ -727,7 +854,7 @@ QPDFWriter::setR5EncryptionParameters(
727 allow_modify_other, 854 allow_modify_other,
728 print, 855 print,
729 qpdf_r3m_all); 856 qpdf_r3m_all);
730 - setEncryptionParameters(user_password, owner_password); 857 + m->setEncryptionParameters(user_password, owner_password);
731 } 858 }
732 859
733 void 860 void
@@ -744,7 +871,7 @@ QPDFWriter::setR6EncryptionParameters( @@ -744,7 +871,7 @@ QPDFWriter::setR6EncryptionParameters(
744 bool encrypt_metadata) 871 bool encrypt_metadata)
745 { 872 {
746 m->encryption = std::make_unique<QPDF::EncryptionData>(5, 6, 32, encrypt_metadata); 873 m->encryption = std::make_unique<QPDF::EncryptionData>(5, 6, 32, encrypt_metadata);
747 - interpretR3EncryptionParameters( 874 + m->interpretR3EncryptionParameters(
748 allow_accessibility, 875 allow_accessibility,
749 allow_extract, 876 allow_extract,
750 allow_assemble, 877 allow_assemble,
@@ -754,11 +881,11 @@ QPDFWriter::setR6EncryptionParameters( @@ -754,11 +881,11 @@ QPDFWriter::setR6EncryptionParameters(
754 print, 881 print,
755 qpdf_r3m_all); 882 qpdf_r3m_all);
756 m->encrypt_use_aes = true; 883 m->encrypt_use_aes = true;
757 - setEncryptionParameters(user_password, owner_password); 884 + m->setEncryptionParameters(user_password, owner_password);
758 } 885 }
759 886
760 void 887 void
761 -QPDFWriter::interpretR3EncryptionParameters( 888 +QPDFWriter::Members::interpretR3EncryptionParameters(
762 bool allow_accessibility, 889 bool allow_accessibility,
763 bool allow_extract, 890 bool allow_extract,
764 bool allow_assemble, 891 bool allow_assemble,
@@ -797,21 +924,21 @@ QPDFWriter::interpretR3EncryptionParameters( @@ -797,21 +924,21 @@ QPDFWriter::interpretR3EncryptionParameters(
797 // 10: accessibility; ignored by readers, should always be set 924 // 10: accessibility; ignored by readers, should always be set
798 // 11: document assembly even if 4 is clear 925 // 11: document assembly even if 4 is clear
799 // 12: high-resolution printing 926 // 12: high-resolution printing
800 - if (!allow_accessibility && m->encryption->getR() <= 3) { 927 + if (!allow_accessibility && encryption->getR() <= 3) {
801 // Bit 10 is deprecated and should always be set. This used to mean accessibility. There 928 // Bit 10 is deprecated and should always be set. This used to mean accessibility. There
802 // is no way to disable accessibility with R > 3. 929 // is no way to disable accessibility with R > 3.
803 - m->encryption->setP(10, false); 930 + encryption->setP(10, false);
804 } 931 }
805 if (!allow_extract) { 932 if (!allow_extract) {
806 - m->encryption->setP(5, false); 933 + encryption->setP(5, false);
807 } 934 }
808 935
809 switch (print) { 936 switch (print) {
810 case qpdf_r3p_none: 937 case qpdf_r3p_none:
811 - m->encryption->setP(3, false); // any printing 938 + encryption->setP(3, false); // any printing
812 [[fallthrough]]; 939 [[fallthrough]];
813 case qpdf_r3p_low: 940 case qpdf_r3p_low:
814 - m->encryption->setP(12, false); // high resolution printing 941 + encryption->setP(12, false); // high resolution printing
815 [[fallthrough]]; 942 [[fallthrough]];
816 case qpdf_r3p_full: 943 case qpdf_r3p_full:
817 break; 944 break;
@@ -825,16 +952,16 @@ QPDFWriter::interpretR3EncryptionParameters( @@ -825,16 +952,16 @@ QPDFWriter::interpretR3EncryptionParameters(
825 // NOT EXERCISED IN TEST SUITE 952 // NOT EXERCISED IN TEST SUITE
826 switch (modify) { 953 switch (modify) {
827 case qpdf_r3m_none: 954 case qpdf_r3m_none:
828 - m->encryption->setP(11, false); // document assembly 955 + encryption->setP(11, false); // document assembly
829 [[fallthrough]]; 956 [[fallthrough]];
830 case qpdf_r3m_assembly: 957 case qpdf_r3m_assembly:
831 - m->encryption->setP(9, false); // filling in form fields 958 + encryption->setP(9, false); // filling in form fields
832 [[fallthrough]]; 959 [[fallthrough]];
833 case qpdf_r3m_form: 960 case qpdf_r3m_form:
834 - m->encryption->setP(6, false); // modify annotations, fill in form fields 961 + encryption->setP(6, false); // modify annotations, fill in form fields
835 [[fallthrough]]; 962 [[fallthrough]];
836 case qpdf_r3m_annotate: 963 case qpdf_r3m_annotate:
837 - m->encryption->setP(4, false); // other modifications 964 + encryption->setP(4, false); // other modifications
838 [[fallthrough]]; 965 [[fallthrough]];
839 case qpdf_r3m_all: 966 case qpdf_r3m_all:
840 break; 967 break;
@@ -843,36 +970,42 @@ QPDFWriter::interpretR3EncryptionParameters( @@ -843,36 +970,42 @@ QPDFWriter::interpretR3EncryptionParameters(
843 // END NOT EXERCISED IN TEST SUITE 970 // END NOT EXERCISED IN TEST SUITE
844 971
845 if (!allow_assemble) { 972 if (!allow_assemble) {
846 - m->encryption->setP(11, false); 973 + encryption->setP(11, false);
847 } 974 }
848 if (!allow_annotate_and_form) { 975 if (!allow_annotate_and_form) {
849 - m->encryption->setP(6, false); 976 + encryption->setP(6, false);
850 } 977 }
851 if (!allow_form_filling) { 978 if (!allow_form_filling) {
852 - m->encryption->setP(9, false); 979 + encryption->setP(9, false);
853 } 980 }
854 if (!allow_modify_other) { 981 if (!allow_modify_other) {
855 - m->encryption->setP(4, false); 982 + encryption->setP(4, false);
856 } 983 }
857 } 984 }
858 985
859 void 986 void
860 -QPDFWriter::setEncryptionParameters(char const* user_password, char const* owner_password) 987 +QPDFWriter::Members::setEncryptionParameters(char const* user_password, char const* owner_password)
861 { 988 {
862 generateID(true); 989 generateID(true);
863 - m->encryption->setId1(m->id1);  
864 - m->encryption_key = m->encryption->compute_parameters(user_password, owner_password); 990 + encryption->setId1(id1);
  991 + encryption_key = encryption->compute_parameters(user_password, owner_password);
865 setEncryptionMinimumVersion(); 992 setEncryptionMinimumVersion();
866 } 993 }
867 994
868 void 995 void
869 QPDFWriter::copyEncryptionParameters(QPDF& qpdf) 996 QPDFWriter::copyEncryptionParameters(QPDF& qpdf)
870 { 997 {
871 - m->preserve_encryption = false; 998 + m->copyEncryptionParameters(qpdf);
  999 +}
  1000 +
  1001 +void
  1002 +QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf)
  1003 +{
  1004 + preserve_encryption = false;
872 QPDFObjectHandle trailer = qpdf.getTrailer(); 1005 QPDFObjectHandle trailer = qpdf.getTrailer();
873 if (trailer.hasKey("/Encrypt")) { 1006 if (trailer.hasKey("/Encrypt")) {
874 generateID(true); 1007 generateID(true);
875 - m->id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue(); 1008 + id1 = trailer.getKey("/ID").getArrayItem(0).getStringValue();
876 QPDFObjectHandle encrypt = trailer.getKey("/Encrypt"); 1009 QPDFObjectHandle encrypt = trailer.getKey("/Encrypt");
877 int V = encrypt.getKey("/V").getIntValueAsInt(); 1010 int V = encrypt.getKey("/V").getIntValueAsInt();
878 int key_len = 5; 1011 int key_len = 5;
@@ -888,12 +1021,12 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf) @@ -888,12 +1021,12 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf)
888 // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of 1021 // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of
889 // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF 1022 // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF
890 // all potentially having different values. 1023 // all potentially having different values.
891 - m->encrypt_use_aes = true; 1024 + encrypt_use_aes = true;
892 } 1025 }
893 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); 1026 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1);
894 - QTC::TC("qpdf", "QPDFWriter copy use_aes", m->encrypt_use_aes ? 0 : 1); 1027 + QTC::TC("qpdf", "QPDFWriter copy use_aes", encrypt_use_aes ? 0 : 1);
895 1028
896 - m->encryption = std::make_unique<QPDF::EncryptionData>( 1029 + encryption = std::make_unique<QPDF::EncryptionData>(
897 V, 1030 V,
898 encrypt.getKey("/R").getIntValueAsInt(), 1031 encrypt.getKey("/R").getIntValueAsInt(),
899 key_len, 1032 key_len,
@@ -903,54 +1036,53 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf) @@ -903,54 +1036,53 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf)
903 V < 5 ? "" : encrypt.getKey("/OE").getStringValue(), 1036 V < 5 ? "" : encrypt.getKey("/OE").getStringValue(),
904 V < 5 ? "" : encrypt.getKey("/UE").getStringValue(), 1037 V < 5 ? "" : encrypt.getKey("/UE").getStringValue(),
905 V < 5 ? "" : encrypt.getKey("/Perms").getStringValue(), 1038 V < 5 ? "" : encrypt.getKey("/Perms").getStringValue(),
906 - m->id1, // m->id1 == the other file's id1 1039 + id1, // id1 == the other file's id1
907 encrypt_metadata); 1040 encrypt_metadata);
908 - m->encryption_key = V >= 5  
909 - ? qpdf.getEncryptionKey()  
910 - : m->encryption->compute_encryption_key(qpdf.getPaddedUserPassword()); 1041 + encryption_key = V >= 5 ? qpdf.getEncryptionKey()
  1042 + : encryption->compute_encryption_key(qpdf.getPaddedUserPassword());
911 setEncryptionMinimumVersion(); 1043 setEncryptionMinimumVersion();
912 } 1044 }
913 } 1045 }
914 1046
915 void 1047 void
916 -QPDFWriter::disableIncompatibleEncryption(int major, int minor, int extension_level) 1048 +QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int extension_level)
917 { 1049 {
918 - if (!m->encryption) { 1050 + if (!encryption) {
919 return; 1051 return;
920 } 1052 }
921 if (compareVersions(major, minor, 1, 3) < 0) { 1053 if (compareVersions(major, minor, 1, 3) < 0) {
922 - m->encryption = nullptr; 1054 + encryption = nullptr;
923 return; 1055 return;
924 } 1056 }
925 - int V = m->encryption->getV();  
926 - int R = m->encryption->getR(); 1057 + int V = encryption->getV();
  1058 + int R = encryption->getR();
927 if (compareVersions(major, minor, 1, 4) < 0) { 1059 if (compareVersions(major, minor, 1, 4) < 0) {
928 if (V > 1 || R > 2) { 1060 if (V > 1 || R > 2) {
929 - m->encryption = nullptr; 1061 + encryption = nullptr;
930 } 1062 }
931 } else if (compareVersions(major, minor, 1, 5) < 0) { 1063 } else if (compareVersions(major, minor, 1, 5) < 0) {
932 if (V > 2 || R > 3) { 1064 if (V > 2 || R > 3) {
933 - m->encryption = nullptr; 1065 + encryption = nullptr;
934 } 1066 }
935 } else if (compareVersions(major, minor, 1, 6) < 0) { 1067 } else if (compareVersions(major, minor, 1, 6) < 0) {
936 - if (m->encrypt_use_aes) {  
937 - m->encryption = nullptr; 1068 + if (encrypt_use_aes) {
  1069 + encryption = nullptr;
938 } 1070 }
939 } else if ( 1071 } else if (
940 (compareVersions(major, minor, 1, 7) < 0) || 1072 (compareVersions(major, minor, 1, 7) < 0) ||
941 ((compareVersions(major, minor, 1, 7) == 0) && extension_level < 3)) { 1073 ((compareVersions(major, minor, 1, 7) == 0) && extension_level < 3)) {
942 if (V >= 5 || R >= 5) { 1074 if (V >= 5 || R >= 5) {
943 - m->encryption = nullptr; 1075 + encryption = nullptr;
944 } 1076 }
945 } 1077 }
946 1078
947 - if (!m->encryption) { 1079 + if (!encryption) {
948 QTC::TC("qpdf", "QPDFWriter forced version disabled encryption"); 1080 QTC::TC("qpdf", "QPDFWriter forced version disabled encryption");
949 } 1081 }
950 } 1082 }
951 1083
952 void 1084 void
953 -QPDFWriter::parseVersion(std::string const& version, int& major, int& minor) const 1085 +QPDFWriter::Members::parseVersion(std::string const& version, int& major, int& minor) const
954 { 1086 {
955 major = QUtil::string_to_int(version.c_str()); 1087 major = QUtil::string_to_int(version.c_str());
956 minor = 0; 1088 minor = 0;
@@ -967,54 +1099,48 @@ QPDFWriter::parseVersion(std::string const&amp; version, int&amp; major, int&amp; minor) con @@ -967,54 +1099,48 @@ QPDFWriter::parseVersion(std::string const&amp; version, int&amp; major, int&amp; minor) con
967 } 1099 }
968 1100
969 int 1101 int
970 -QPDFWriter::compareVersions(int major1, int minor1, int major2, int minor2) const 1102 +QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int minor2) const
971 { 1103 {
972 if (major1 < major2) { 1104 if (major1 < major2) {
973 return -1; 1105 return -1;
974 - } else if (major1 > major2) { 1106 + }
  1107 + if (major1 > major2) {
975 return 1; 1108 return 1;
976 - } else if (minor1 < minor2) { 1109 + }
  1110 + if (minor1 < minor2) {
977 return -1; 1111 return -1;
978 - } else if (minor1 > minor2) {  
979 - return 1;  
980 - } else {  
981 - return 0;  
982 } 1112 }
  1113 + return minor1 > minor2 ? 1 : 0;
983 } 1114 }
984 1115
985 void 1116 void
986 -QPDFWriter::setEncryptionMinimumVersion() 1117 +QPDFWriter::Members::setEncryptionMinimumVersion()
987 { 1118 {
988 - auto const R = m->encryption->getR(); 1119 + auto const R = encryption->getR();
989 if (R >= 6) { 1120 if (R >= 6) {
990 - setMinimumPDFVersion("1.7", 8); 1121 + w.setMinimumPDFVersion("1.7", 8);
991 } else if (R == 5) { 1122 } else if (R == 5) {
992 - setMinimumPDFVersion("1.7", 3); 1123 + w.setMinimumPDFVersion("1.7", 3);
993 } else if (R == 4) { 1124 } else if (R == 4) {
994 - setMinimumPDFVersion(m->encrypt_use_aes ? "1.6" : "1.5"); 1125 + w.setMinimumPDFVersion(encrypt_use_aes ? "1.6" : "1.5");
995 } else if (R == 3) { 1126 } else if (R == 3) {
996 - setMinimumPDFVersion("1.4"); 1127 + w.setMinimumPDFVersion("1.4");
997 } else { 1128 } else {
998 - setMinimumPDFVersion("1.3"); 1129 + w.setMinimumPDFVersion("1.3");
999 } 1130 }
1000 } 1131 }
1001 1132
1002 void 1133 void
1003 -QPDFWriter::setDataKey(int objid) 1134 +QPDFWriter::Members::setDataKey(int objid)
1004 { 1135 {
1005 - if (m->encryption) {  
1006 - m->cur_data_key = QPDF::compute_data_key(  
1007 - m->encryption_key,  
1008 - objid,  
1009 - 0,  
1010 - m->encrypt_use_aes,  
1011 - m->encryption->getV(),  
1012 - m->encryption->getR()); 1136 + if (encryption) {
  1137 + cur_data_key = QPDF::compute_data_key(
  1138 + encryption_key, objid, 0, encrypt_use_aes, encryption->getV(), encryption->getR());
1013 } 1139 }
1014 } 1140 }
1015 1141
1016 unsigned int 1142 unsigned int
1017 -QPDFWriter::bytesNeeded(long long n) 1143 +QPDFWriter::Members::bytesNeeded(long long n)
1018 { 1144 {
1019 unsigned int bytes = 0; 1145 unsigned int bytes = 0;
1020 while (n) { 1146 while (n) {
@@ -1025,7 +1151,7 @@ QPDFWriter::bytesNeeded(long long n) @@ -1025,7 +1151,7 @@ QPDFWriter::bytesNeeded(long long n)
1025 } 1151 }
1026 1152
1027 void 1153 void
1028 -QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) 1154 +QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes)
1029 { 1155 {
1030 if (bytes > sizeof(unsigned long long)) { 1156 if (bytes > sizeof(unsigned long long)) {
1031 throw std::logic_error("QPDFWriter::writeBinary called with too many bytes"); 1157 throw std::logic_error("QPDFWriter::writeBinary called with too many bytes");
@@ -1035,191 +1161,189 @@ QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes) @@ -1035,191 +1161,189 @@ QPDFWriter::writeBinary(unsigned long long val, unsigned int bytes)
1035 data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff); 1161 data[bytes - i - 1] = static_cast<unsigned char>(val & 0xff);
1036 val >>= 8; 1162 val >>= 8;
1037 } 1163 }
1038 - m->pipeline->write(data, bytes); 1164 + pipeline->write(data, bytes);
1039 } 1165 }
1040 1166
1041 -QPDFWriter&  
1042 -QPDFWriter::write(std::string_view str) 1167 +QPDFWriter::Members&
  1168 +QPDFWriter::Members::write(std::string_view str)
1043 { 1169 {
1044 - m->pipeline->write(str); 1170 + pipeline->write(str);
1045 return *this; 1171 return *this;
1046 } 1172 }
1047 1173
1048 -QPDFWriter&  
1049 -QPDFWriter::write(std::integral auto val) 1174 +QPDFWriter::Members&
  1175 +QPDFWriter::Members::write(std::integral auto val)
1050 { 1176 {
1051 - m->pipeline->write(std::to_string(val)); 1177 + pipeline->write(std::to_string(val));
1052 return *this; 1178 return *this;
1053 } 1179 }
1054 1180
1055 -QPDFWriter&  
1056 -QPDFWriter::write(size_t count, char c) 1181 +QPDFWriter::Members&
  1182 +QPDFWriter::Members::write(size_t count, char c)
1057 { 1183 {
1058 - m->pipeline->write(count, c); 1184 + pipeline->write(count, c);
1059 return *this; 1185 return *this;
1060 } 1186 }
1061 1187
1062 -QPDFWriter&  
1063 -QPDFWriter::write_name(std::string const& str) 1188 +QPDFWriter::Members&
  1189 +QPDFWriter::Members::write_name(std::string const& str)
1064 { 1190 {
1065 - m->pipeline->write(Name::normalize(str)); 1191 + pipeline->write(Name::normalize(str));
1066 return *this; 1192 return *this;
1067 } 1193 }
1068 1194
1069 -QPDFWriter&  
1070 -QPDFWriter::write_string(std::string const& str, bool force_binary) 1195 +QPDFWriter::Members&
  1196 +QPDFWriter::Members::write_string(std::string const& str, bool force_binary)
1071 { 1197 {
1072 - m->pipeline->write(QPDF_String(str).unparse(force_binary)); 1198 + pipeline->write(QPDF_String(str).unparse(force_binary));
1073 return *this; 1199 return *this;
1074 } 1200 }
1075 1201
1076 template <typename... Args> 1202 template <typename... Args>
1077 -QPDFWriter&  
1078 -QPDFWriter::write_qdf(Args&&... args) 1203 +QPDFWriter::Members&
  1204 +QPDFWriter::Members::write_qdf(Args&&... args)
1079 { 1205 {
1080 - if (m->qdf_mode) {  
1081 - m->pipeline->write(std::forward<Args>(args)...); 1206 + if (qdf_mode) {
  1207 + pipeline->write(std::forward<Args>(args)...);
1082 } 1208 }
1083 return *this; 1209 return *this;
1084 } 1210 }
1085 1211
1086 template <typename... Args> 1212 template <typename... Args>
1087 -QPDFWriter&  
1088 -QPDFWriter::write_no_qdf(Args&&... args) 1213 +QPDFWriter::Members&
  1214 +QPDFWriter::Members::write_no_qdf(Args&&... args)
1089 { 1215 {
1090 - if (!m->qdf_mode) {  
1091 - m->pipeline->write(std::forward<Args>(args)...); 1216 + if (!qdf_mode) {
  1217 + pipeline->write(std::forward<Args>(args)...);
1092 } 1218 }
1093 return *this; 1219 return *this;
1094 } 1220 }
1095 1221
1096 void 1222 void
1097 -QPDFWriter::adjustAESStreamLength(size_t& length) 1223 +QPDFWriter::Members::adjustAESStreamLength(size_t& length)
1098 { 1224 {
1099 - if (m->encryption && !m->cur_data_key.empty() && m->encrypt_use_aes) { 1225 + if (encryption && !cur_data_key.empty() && encrypt_use_aes) {
1100 // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will 1226 // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will
1101 // also be prepended by 16 bits of random data. 1227 // also be prepended by 16 bits of random data.
1102 length += 32 - (length & 0xf); 1228 length += 32 - (length & 0xf);
1103 } 1229 }
1104 } 1230 }
1105 1231
1106 -QPDFWriter&  
1107 -QPDFWriter::write_encrypted(std::string_view str) 1232 +QPDFWriter::Members&
  1233 +QPDFWriter::Members::write_encrypted(std::string_view str)
1108 { 1234 {
1109 - if (!(m->encryption && !m->cur_data_key.empty())) { 1235 + if (!(encryption && !cur_data_key.empty())) {
1110 write(str); 1236 write(str);
1111 - } else if (m->encrypt_use_aes) {  
1112 - write(pl::pipe<Pl_AES_PDF>(str, true, m->cur_data_key)); 1237 + } else if (encrypt_use_aes) {
  1238 + write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key));
1113 } else { 1239 } else {
1114 - write(pl::pipe<Pl_RC4>(str, m->cur_data_key)); 1240 + write(pl::pipe<Pl_RC4>(str, cur_data_key));
1115 } 1241 }
1116 1242
1117 return *this; 1243 return *this;
1118 } 1244 }
1119 1245
1120 void 1246 void
1121 -QPDFWriter::computeDeterministicIDData() 1247 +QPDFWriter::Members::computeDeterministicIDData()
1122 { 1248 {
1123 - if (!m->id2.empty()) { 1249 + if (!id2.empty()) {
1124 // Can't happen in the code 1250 // Can't happen in the code
1125 throw std::logic_error( 1251 throw std::logic_error(
1126 "Deterministic ID computation enabled after ID generation has already occurred."); 1252 "Deterministic ID computation enabled after ID generation has already occurred.");
1127 } 1253 }
1128 - qpdf_assert_debug(m->deterministic_id_data.empty());  
1129 - m->deterministic_id_data = m->pipeline_stack.hex_digest(); 1254 + qpdf_assert_debug(deterministic_id_data.empty());
  1255 + deterministic_id_data = pipeline_stack.hex_digest();
1130 } 1256 }
1131 1257
1132 int 1258 int
1133 -QPDFWriter::openObject(int objid) 1259 +QPDFWriter::Members::openObject(int objid)
1134 { 1260 {
1135 if (objid == 0) { 1261 if (objid == 0) {
1136 - objid = m->next_objid++; 1262 + objid = next_objid++;
1137 } 1263 }
1138 - m->new_obj[objid].xref = QPDFXRefEntry(m->pipeline->getCount()); 1264 + new_obj[objid].xref = QPDFXRefEntry(pipeline->getCount());
1139 write(objid).write(" 0 obj\n"); 1265 write(objid).write(" 0 obj\n");
1140 return objid; 1266 return objid;
1141 } 1267 }
1142 1268
1143 void 1269 void
1144 -QPDFWriter::closeObject(int objid) 1270 +QPDFWriter::Members::closeObject(int objid)
1145 { 1271 {
1146 // Write a newline before endobj as it makes the file easier to repair. 1272 // Write a newline before endobj as it makes the file easier to repair.
1147 write("\nendobj\n").write_qdf("\n"); 1273 write("\nendobj\n").write_qdf("\n");
1148 - auto& new_obj = m->new_obj[objid];  
1149 - new_obj.length = m->pipeline->getCount() - new_obj.xref.getOffset(); 1274 + auto& no = new_obj[objid];
  1275 + no.length = pipeline->getCount() - no.xref.getOffset();
1150 } 1276 }
1151 1277
1152 void 1278 void
1153 -QPDFWriter::assignCompressedObjectNumbers(QPDFObjGen og) 1279 +QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og)
1154 { 1280 {
1155 int objid = og.getObj(); 1281 int objid = og.getObj();
1156 - if ((og.getGen() != 0) || (!m->object_stream_to_objects.contains(objid))) { 1282 + if (og.getGen() != 0 || !object_stream_to_objects.contains(objid)) {
1157 // This is not an object stream. 1283 // This is not an object stream.
1158 return; 1284 return;
1159 } 1285 }
1160 1286
1161 // Reserve numbers for the objects that belong to this object stream. 1287 // Reserve numbers for the objects that belong to this object stream.
1162 - for (auto const& iter: m->object_stream_to_objects[objid]) {  
1163 - m->obj[iter].renumber = m->next_objid++; 1288 + for (auto const& iter: object_stream_to_objects[objid]) {
  1289 + obj[iter].renumber = next_objid++;
1164 } 1290 }
1165 } 1291 }
1166 1292
1167 void 1293 void
1168 -QPDFWriter::enqueueObject(QPDFObjectHandle object) 1294 +QPDFWriter::Members::enqueueObject(QPDFObjectHandle object)
1169 { 1295 {
1170 if (object.isIndirect()) { 1296 if (object.isIndirect()) {
1171 // This owner check can only be done for indirect objects. It is possible for a direct 1297 // This owner check can only be done for indirect objects. It is possible for a direct
1172 // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from 1298 // object to have an owning QPDF that is from another file if a direct QPDFObjectHandle from
1173 // one file was insert into another file without copying. Doing that is safe even if the 1299 // one file was insert into another file without copying. Doing that is safe even if the
1174 // original QPDF gets destroyed, which just disconnects the QPDFObjectHandle from its owner. 1300 // original QPDF gets destroyed, which just disconnects the QPDFObjectHandle from its owner.
1175 - if (object.getOwningQPDF() != &(m->pdf)) {  
1176 - QTC::TC("qpdf", "QPDFWriter foreign object"); 1301 + if (object.getOwningQPDF() != &pdf) {
1177 throw std::logic_error( 1302 throw std::logic_error(
1178 "QPDFObjectHandle from different QPDF found while writing. Use " 1303 "QPDFObjectHandle from different QPDF found while writing. Use "
1179 "QPDF::copyForeignObject to add objects from another file."); 1304 "QPDF::copyForeignObject to add objects from another file.");
1180 } 1305 }
1181 1306
1182 - if (m->qdf_mode && object.isStreamOfType("/XRef")) { 1307 + if (qdf_mode && object.isStreamOfType("/XRef")) {
1183 // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so 1308 // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so
1184 // will confuse fix-qdf, which expects to see only one XRef stream at the end of the 1309 // will confuse fix-qdf, which expects to see only one XRef stream at the end of the
1185 // file. This case can occur when creating a QDF from a file with object streams when 1310 // file. This case can occur when creating a QDF from a file with object streams when
1186 // preserving unreferenced objects since the old cross reference streams are not 1311 // preserving unreferenced objects since the old cross reference streams are not
1187 // actually referenced by object number. 1312 // actually referenced by object number.
1188 - QTC::TC("qpdf", "QPDFWriter ignore XRef in qdf mode");  
1189 return; 1313 return;
1190 } 1314 }
1191 1315
1192 QPDFObjGen og = object.getObjGen(); 1316 QPDFObjGen og = object.getObjGen();
1193 - auto& obj = m->obj[og]; 1317 + auto& o = obj[og];
1194 1318
1195 - if (obj.renumber == 0) {  
1196 - if (obj.object_stream > 0) { 1319 + if (o.renumber == 0) {
  1320 + if (o.object_stream > 0) {
1197 // This is in an object stream. Don't process it here. Instead, enqueue the object 1321 // This is in an object stream. Don't process it here. Instead, enqueue the object
1198 // stream. Object streams always have generation 0. 1322 // stream. Object streams always have generation 0.
1199 // Detect loops by storing invalid object ID -1, which will get overwritten later. 1323 // Detect loops by storing invalid object ID -1, which will get overwritten later.
1200 - obj.renumber = -1;  
1201 - enqueueObject(m->pdf.getObject(obj.object_stream, 0)); 1324 + o.renumber = -1;
  1325 + enqueueObject(pdf.getObject(o.object_stream, 0));
1202 } else { 1326 } else {
1203 - m->object_queue.push_back(object);  
1204 - obj.renumber = m->next_objid++; 1327 + object_queue.emplace_back(object);
  1328 + o.renumber = next_objid++;
1205 1329
1206 - if ((og.getGen() == 0) && m->object_stream_to_objects.contains(og.getObj())) { 1330 + if (og.getGen() == 0 && object_stream_to_objects.contains(og.getObj())) {
1207 // For linearized files, uncompressed objects go at end, and we take care of 1331 // For linearized files, uncompressed objects go at end, and we take care of
1208 // assigning numbers to them elsewhere. 1332 // assigning numbers to them elsewhere.
1209 - if (!m->linearized) { 1333 + if (!linearized) {
1210 assignCompressedObjectNumbers(og); 1334 assignCompressedObjectNumbers(og);
1211 } 1335 }
1212 - } else if ((!m->direct_stream_lengths) && object.isStream()) { 1336 + } else if (!direct_stream_lengths && object.isStream()) {
1213 // reserve next object ID for length 1337 // reserve next object ID for length
1214 - ++m->next_objid; 1338 + ++next_objid;
1215 } 1339 }
1216 } 1340 }
1217 - } else if (obj.renumber == -1) { 1341 + } else if (o.renumber == -1) {
1218 // This can happen if a specially constructed file indicates that an object stream is 1342 // This can happen if a specially constructed file indicates that an object stream is
1219 // inside itself. 1343 // inside itself.
1220 } 1344 }
1221 return; 1345 return;
1222 - } else if (!m->linearized) { 1346 + } else if (!linearized) {
1223 if (object.isArray()) { 1347 if (object.isArray()) {
1224 for (auto& item: object.as_array()) { 1348 for (auto& item: object.as_array()) {
1225 enqueueObject(item); 1349 enqueueObject(item);
@@ -1237,25 +1361,25 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object) @@ -1237,25 +1361,25 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
1237 } 1361 }
1238 1362
1239 void 1363 void
1240 -QPDFWriter::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) 1364 +QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, int flags)
1241 { 1365 {
1242 - if (!m->linearized) { 1366 + if (!linearized) {
1243 enqueueObject(child); 1367 enqueueObject(child);
1244 } 1368 }
1245 if (child.isIndirect()) { 1369 if (child.isIndirect()) {
1246 - write(m->obj[child].renumber).write(" 0 R"); 1370 + write(obj[child].renumber).write(" 0 R");
1247 } else { 1371 } else {
1248 unparseObject(child, level, flags); 1372 unparseObject(child, level, flags);
1249 } 1373 }
1250 } 1374 }
1251 1375
1252 void 1376 void
1253 -QPDFWriter::writeTrailer( 1377 +QPDFWriter::Members::writeTrailer(
1254 trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) 1378 trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass)
1255 { 1379 {
1256 QPDFObjectHandle trailer = getTrimmedTrailer(); 1380 QPDFObjectHandle trailer = getTrimmedTrailer();
1257 if (xref_stream) { 1381 if (xref_stream) {
1258 - m->cur_data_key.clear(); 1382 + cur_data_key.clear();
1259 } else { 1383 } else {
1260 write("trailer <<"); 1384 write("trailer <<");
1261 } 1385 }
@@ -1272,8 +1396,8 @@ QPDFWriter::writeTrailer( @@ -1272,8 +1396,8 @@ QPDFWriter::writeTrailer(
1272 write(size); 1396 write(size);
1273 if (which == t_lin_first) { 1397 if (which == t_lin_first) {
1274 write(" /Prev "); 1398 write(" /Prev ");
1275 - qpdf_offset_t pos = m->pipeline->getCount();  
1276 - write(prev).write(QIntC::to_size(pos - m->pipeline->getCount() + 21), ' '); 1399 + qpdf_offset_t pos = pipeline->getCount();
  1400 + write(prev).write(QIntC::to_size(pos - pipeline->getCount() + 21), ' ');
1277 } 1401 }
1278 } else { 1402 } else {
1279 unparseChild(value, 1, 0); 1403 unparseChild(value, 1, 0);
@@ -1298,18 +1422,18 @@ QPDFWriter::writeTrailer( @@ -1298,18 +1422,18 @@ QPDFWriter::writeTrailer(
1298 } 1422 }
1299 write("<00000000000000000000000000000000>"); 1423 write("<00000000000000000000000000000000>");
1300 } else { 1424 } else {
1301 - if (linearization_pass == 0 && m->deterministic_id) { 1425 + if (linearization_pass == 0 && deterministic_id) {
1302 computeDeterministicIDData(); 1426 computeDeterministicIDData();
1303 } 1427 }
1304 - generateID(m->encryption.get());  
1305 - write_string(m->id1, true).write_string(m->id2, true); 1428 + generateID(encryption.get());
  1429 + write_string(id1, true).write_string(id2, true);
1306 } 1430 }
1307 write("]"); 1431 write("]");
1308 1432
1309 if (which != t_lin_second) { 1433 if (which != t_lin_second) {
1310 // Write reference to encryption dictionary 1434 // Write reference to encryption dictionary
1311 - if (m->encryption) {  
1312 - write(" /Encrypt ").write(m->encryption_dict_objid).write(" 0 R"); 1435 + if (encryption) {
  1436 + write(" /Encrypt ").write(encryption_dict_objid).write(" 0 R");
1313 } 1437 }
1314 } 1438 }
1315 1439
@@ -1317,7 +1441,7 @@ QPDFWriter::writeTrailer( @@ -1317,7 +1441,7 @@ QPDFWriter::writeTrailer(
1317 } 1441 }
1318 1442
1319 bool 1443 bool
1320 -QPDFWriter::willFilterStream( 1444 +QPDFWriter::Members::willFilterStream(
1321 QPDFObjectHandle stream, 1445 QPDFObjectHandle stream,
1322 bool& compress_stream, // out only 1446 bool& compress_stream, // out only
1323 bool& is_root_metadata, // out only 1447 bool& is_root_metadata, // out only
@@ -1332,38 +1456,33 @@ QPDFWriter::willFilterStream( @@ -1332,38 +1456,33 @@ QPDFWriter::willFilterStream(
1332 if (stream.isRootMetadata()) { 1456 if (stream.isRootMetadata()) {
1333 is_root_metadata = true; 1457 is_root_metadata = true;
1334 } 1458 }
1335 - bool filter = stream.isDataModified() || m->compress_streams || m->stream_decode_level; 1459 + bool filter = stream.isDataModified() || compress_streams || stream_decode_level;
1336 bool filter_on_write = stream.getFilterOnWrite(); 1460 bool filter_on_write = stream.getFilterOnWrite();
1337 if (!filter_on_write) { 1461 if (!filter_on_write) {
1338 - QTC::TC("qpdf", "QPDFWriter getFilterOnWrite false");  
1339 filter = false; 1462 filter = false;
1340 } 1463 }
1341 - if (filter_on_write && m->compress_streams) { 1464 + if (filter_on_write && compress_streams) {
1342 // Don't filter if the stream is already compressed with FlateDecode. This way we don't make 1465 // Don't filter if the stream is already compressed with FlateDecode. This way we don't make
1343 // it worse if the original file used a better Flate algorithm, and we don't spend time and 1466 // it worse if the original file used a better Flate algorithm, and we don't spend time and
1344 // CPU cycles uncompressing and recompressing stuff. This can be overridden with 1467 // CPU cycles uncompressing and recompressing stuff. This can be overridden with
1345 // setRecompressFlate(true). 1468 // setRecompressFlate(true).
1346 QPDFObjectHandle filter_obj = stream_dict.getKey("/Filter"); 1469 QPDFObjectHandle filter_obj = stream_dict.getKey("/Filter");
1347 - if (!m->recompress_flate && !stream.isDataModified() && filter_obj.isName() && 1470 + if (!recompress_flate && !stream.isDataModified() && filter_obj.isName() &&
1348 (filter_obj.getName() == "/FlateDecode" || filter_obj.getName() == "/Fl")) { 1471 (filter_obj.getName() == "/FlateDecode" || filter_obj.getName() == "/Fl")) {
1349 - QTC::TC("qpdf", "QPDFWriter not recompressing /FlateDecode");  
1350 filter = false; 1472 filter = false;
1351 } 1473 }
1352 } 1474 }
1353 bool normalize = false; 1475 bool normalize = false;
1354 bool uncompress = false; 1476 bool uncompress = false;
1355 - if (filter_on_write && is_root_metadata &&  
1356 - (!m->encryption || !m->encryption->getEncryptMetadata())) {  
1357 - QTC::TC("qpdf", "QPDFWriter not compressing metadata"); 1477 + if (filter_on_write && is_root_metadata && (!encryption || !encryption->getEncryptMetadata())) {
1358 filter = true; 1478 filter = true;
1359 compress_stream = false; 1479 compress_stream = false;
1360 uncompress = true; 1480 uncompress = true;
1361 - } else if (filter_on_write && m->normalize_content && m->normalized_streams.contains(old_og)) { 1481 + } else if (filter_on_write && normalize_content && normalized_streams.contains(old_og)) {
1362 normalize = true; 1482 normalize = true;
1363 filter = true; 1483 filter = true;
1364 - } else if (filter_on_write && filter && m->compress_streams) { 1484 + } else if (filter_on_write && filter && compress_streams) {
1365 compress_stream = true; 1485 compress_stream = true;
1366 - QTC::TC("qpdf", "QPDFWriter compressing uncompressed stream");  
1367 } 1486 }
1368 1487
1369 // Disable compression for empty streams to improve compatibility 1488 // Disable compression for empty streams to improve compatibility
@@ -1375,16 +1494,16 @@ QPDFWriter::willFilterStream( @@ -1375,16 +1494,16 @@ QPDFWriter::willFilterStream(
1375 1494
1376 bool filtered = false; 1495 bool filtered = false;
1377 for (bool first_attempt: {true, false}) { 1496 for (bool first_attempt: {true, false}) {
1378 - auto pp_stream_data = stream_data ? m->pipeline_stack.activate(*stream_data)  
1379 - : m->pipeline_stack.activate(true); 1497 + auto pp_stream_data =
  1498 + stream_data ? pipeline_stack.activate(*stream_data) : pipeline_stack.activate(true);
1380 1499
1381 try { 1500 try {
1382 filtered = stream.pipeStreamData( 1501 filtered = stream.pipeStreamData(
1383 - m->pipeline, 1502 + pipeline,
1384 !filter ? 0 1503 !filter ? 0
1385 : ((normalize ? qpdf_ef_normalize : 0) | 1504 : ((normalize ? qpdf_ef_normalize : 0) |
1386 (compress_stream ? qpdf_ef_compress : 0)), 1505 (compress_stream ? qpdf_ef_compress : 0)),
1387 - !filter ? qpdf_dl_none : (uncompress ? qpdf_dl_all : m->stream_decode_level), 1506 + !filter ? qpdf_dl_none : (uncompress ? qpdf_dl_all : stream_decode_level),
1388 false, 1507 false,
1389 first_attempt); 1508 first_attempt);
1390 if (filter && !filtered) { 1509 if (filter && !filtered) {
@@ -1416,7 +1535,7 @@ QPDFWriter::willFilterStream( @@ -1416,7 +1535,7 @@ QPDFWriter::willFilterStream(
1416 } 1535 }
1417 1536
1418 void 1537 void
1419 -QPDFWriter::unparseObject( 1538 +QPDFWriter::Members::unparseObject(
1420 QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) 1539 QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress)
1421 { 1540 {
1422 QPDFObjGen old_og = object.getObjGen(); 1541 QPDFObjGen old_og = object.getObjGen();
@@ -1424,11 +1543,11 @@ QPDFWriter::unparseObject( @@ -1424,11 +1543,11 @@ QPDFWriter::unparseObject(
1424 // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they 1543 // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they
1425 // include the preceding newline. 1544 // include the preceding newline.
1426 std::string indent_large = " "; 1545 std::string indent_large = " ";
1427 - if (m->qdf_mode) { 1546 + if (qdf_mode) {
1428 indent_large.append(2 * (level + 1), ' '); 1547 indent_large.append(2 * (level + 1), ' ');
1429 indent_large[0] = '\n'; 1548 indent_large[0] = '\n';
1430 } 1549 }
1431 - std::string_view indent{indent_large.data(), m->qdf_mode ? indent_large.size() - 2 : 1}; 1550 + std::string_view indent{indent_large.data(), qdf_mode ? indent_large.size() - 2 : 1};
1432 1551
1433 if (auto const tc = object.getTypeCode(); tc == ::ot_array) { 1552 if (auto const tc = object.getTypeCode(); tc == ::ot_array) {
1434 // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the 1553 // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the
@@ -1443,7 +1562,7 @@ QPDFWriter::unparseObject( @@ -1443,7 +1562,7 @@ QPDFWriter::unparseObject(
1443 } else if (tc == ::ot_dictionary) { 1562 } else if (tc == ::ot_dictionary) {
1444 // Handle special cases for specific dictionaries. 1563 // Handle special cases for specific dictionaries.
1445 1564
1446 - if (old_og == m->root_og) { 1565 + if (old_og == root_og) {
1447 // Extensions dictionaries. 1566 // Extensions dictionaries.
1448 1567
1449 // We have one of several cases: 1568 // We have one of several cases:
@@ -1464,7 +1583,7 @@ QPDFWriter::unparseObject( @@ -1464,7 +1583,7 @@ QPDFWriter::unparseObject(
1464 1583
1465 auto extensions = object.getKey("/Extensions"); 1584 auto extensions = object.getKey("/Extensions");
1466 const bool has_extensions = extensions.isDictionary(); 1585 const bool has_extensions = extensions.isDictionary();
1467 - const bool need_extensions_adbe = m->final_extension_level > 0; 1586 + const bool need_extensions_adbe = final_extension_level > 0;
1468 1587
1469 if (has_extensions || need_extensions_adbe) { 1588 if (has_extensions || need_extensions_adbe) {
1470 // Make a shallow copy of this object so we can modify it safely without affecting 1589 // Make a shallow copy of this object so we can modify it safely without affecting
@@ -1484,7 +1603,7 @@ QPDFWriter::unparseObject( @@ -1484,7 +1603,7 @@ QPDFWriter::unparseObject(
1484 if (need_extensions_adbe) { 1603 if (need_extensions_adbe) {
1485 if (!(have_extensions_other || have_extensions_adbe)) { 1604 if (!(have_extensions_other || have_extensions_adbe)) {
1486 // We need Extensions and don't have it. Create it here. 1605 // We need Extensions and don't have it. Create it here.
1487 - QTC::TC("qpdf", "QPDFWriter create Extensions", m->qdf_mode ? 0 : 1); 1606 + QTC::TC("qpdf", "QPDFWriter create Extensions", qdf_mode ? 0 : 1);
1488 extensions = object.replaceKeyAndGetNew( 1607 extensions = object.replaceKeyAndGetNew(
1489 "/Extensions", QPDFObjectHandle::newDictionary()); 1608 "/Extensions", QPDFObjectHandle::newDictionary());
1490 } 1609 }
@@ -1501,21 +1620,17 @@ QPDFWriter::unparseObject( @@ -1501,21 +1620,17 @@ QPDFWriter::unparseObject(
1501 QTC::TC("qpdf", "QPDFWriter preserve Extensions"); 1620 QTC::TC("qpdf", "QPDFWriter preserve Extensions");
1502 QPDFObjectHandle adbe = extensions.getKey("/ADBE"); 1621 QPDFObjectHandle adbe = extensions.getKey("/ADBE");
1503 if (adbe.isDictionary() && 1622 if (adbe.isDictionary() &&
1504 - adbe.getKey("/BaseVersion").isNameAndEquals("/" + m->final_pdf_version) && 1623 + adbe.getKey("/BaseVersion").isNameAndEquals("/" + final_pdf_version) &&
1505 adbe.getKey("/ExtensionLevel").isInteger() && 1624 adbe.getKey("/ExtensionLevel").isInteger() &&
1506 - (adbe.getKey("/ExtensionLevel").getIntValue() ==  
1507 - m->final_extension_level)) {  
1508 - QTC::TC("qpdf", "QPDFWriter preserve ADBE"); 1625 + (adbe.getKey("/ExtensionLevel").getIntValue() == final_extension_level)) {
1509 } else { 1626 } else {
1510 if (need_extensions_adbe) { 1627 if (need_extensions_adbe) {
1511 extensions.replaceKey( 1628 extensions.replaceKey(
1512 "/ADBE", 1629 "/ADBE",
1513 QPDFObjectHandle::parse( 1630 QPDFObjectHandle::parse(
1514 - "<< /BaseVersion /" + m->final_pdf_version +  
1515 - " /ExtensionLevel " + std::to_string(m->final_extension_level) +  
1516 - " >>")); 1631 + "<< /BaseVersion /" + final_pdf_version + " /ExtensionLevel " +
  1632 + std::to_string(final_extension_level) + " >>"));
1517 } else { 1633 } else {
1518 - QTC::TC("qpdf", "QPDFWriter remove ADBE");  
1519 extensions.removeKey("/ADBE"); 1634 extensions.removeKey("/ADBE");
1520 } 1635 }
1521 } 1636 }
@@ -1593,10 +1708,10 @@ QPDFWriter::unparseObject( @@ -1593,10 +1708,10 @@ QPDFWriter::unparseObject(
1593 if (flags & f_stream) { 1708 if (flags & f_stream) {
1594 write(indent_large).write("/Length "); 1709 write(indent_large).write("/Length ");
1595 1710
1596 - if (m->direct_stream_lengths) { 1711 + if (direct_stream_lengths) {
1597 write(stream_length); 1712 write(stream_length);
1598 } else { 1713 } else {
1599 - write(m->cur_stream_length_id).write(" 0 R"); 1714 + write(cur_stream_length_id).write(" 0 R");
1600 } 1715 }
1601 if (compress && (flags & f_filtered)) { 1716 if (compress && (flags & f_filtered)) {
1602 write(indent_large).write("/Filter /FlateDecode"); 1717 write(indent_large).write("/Filter /FlateDecode");
@@ -1606,8 +1721,8 @@ QPDFWriter::unparseObject( @@ -1606,8 +1721,8 @@ QPDFWriter::unparseObject(
1606 write(indent).write(">>"); 1721 write(indent).write(">>");
1607 } else if (tc == ::ot_stream) { 1722 } else if (tc == ::ot_stream) {
1608 // Write stream data to a buffer. 1723 // Write stream data to a buffer.
1609 - if (!m->direct_stream_lengths) {  
1610 - m->cur_stream_length_id = m->obj[old_og].renumber + 1; 1724 + if (!direct_stream_lengths) {
  1725 + cur_stream_length_id = obj[old_og].renumber + 1;
1611 } 1726 }
1612 1727
1613 flags |= f_stream; 1728 flags |= f_stream;
@@ -1619,25 +1734,25 @@ QPDFWriter::unparseObject( @@ -1619,25 +1734,25 @@ QPDFWriter::unparseObject(
1619 } 1734 }
1620 QPDFObjectHandle stream_dict = object.getDict(); 1735 QPDFObjectHandle stream_dict = object.getDict();
1621 1736
1622 - m->cur_stream_length = stream_data.size();  
1623 - if (is_metadata && m->encryption && !m->encryption->getEncryptMetadata()) { 1737 + cur_stream_length = stream_data.size();
  1738 + if (is_metadata && encryption && !encryption->getEncryptMetadata()) {
1624 // Don't encrypt stream data for the metadata stream 1739 // Don't encrypt stream data for the metadata stream
1625 - m->cur_data_key.clear(); 1740 + cur_data_key.clear();
1626 } 1741 }
1627 - adjustAESStreamLength(m->cur_stream_length);  
1628 - unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); 1742 + adjustAESStreamLength(cur_stream_length);
  1743 + unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream);
1629 char last_char = stream_data.empty() ? '\0' : stream_data.back(); 1744 char last_char = stream_data.empty() ? '\0' : stream_data.back();
1630 write("\nstream\n").write_encrypted(stream_data); 1745 write("\nstream\n").write_encrypted(stream_data);
1631 - m->added_newline = m->newline_before_endstream || (m->qdf_mode && last_char != '\n');  
1632 - write(m->added_newline ? "\nendstream" : "endstream"); 1746 + added_newline = newline_before_endstream || (qdf_mode && last_char != '\n');
  1747 + write(added_newline ? "\nendstream" : "endstream");
1633 } else if (tc == ::ot_string) { 1748 } else if (tc == ::ot_string) {
1634 std::string val; 1749 std::string val;
1635 - if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) &&  
1636 - !m->cur_data_key.empty()) { 1750 + if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) &&
  1751 + !cur_data_key.empty()) {
1637 val = object.getStringValue(); 1752 val = object.getStringValue();
1638 - if (m->encrypt_use_aes) { 1753 + if (encrypt_use_aes) {
1639 Pl_Buffer bufpl("encrypted string"); 1754 Pl_Buffer bufpl("encrypted string");
1640 - Pl_AES_PDF pl("aes encrypt string", &bufpl, true, m->cur_data_key); 1755 + Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key);
1641 pl.writeString(val); 1756 pl.writeString(val);
1642 pl.finish(); 1757 pl.finish();
1643 val = QPDF_String(bufpl.getString()).unparse(true); 1758 val = QPDF_String(bufpl.getString()).unparse(true);
@@ -1646,8 +1761,8 @@ QPDFWriter::unparseObject( @@ -1646,8 +1761,8 @@ QPDFWriter::unparseObject(
1646 char* tmp = tmp_ph.get(); 1761 char* tmp = tmp_ph.get();
1647 size_t vlen = val.length(); 1762 size_t vlen = val.length();
1648 RC4 rc4( 1763 RC4 rc4(
1649 - QUtil::unsigned_char_pointer(m->cur_data_key),  
1650 - QIntC::to_int(m->cur_data_key.length())); 1764 + QUtil::unsigned_char_pointer(cur_data_key),
  1765 + QIntC::to_int(cur_data_key.length()));
1651 auto data = QUtil::unsigned_char_pointer(tmp); 1766 auto data = QUtil::unsigned_char_pointer(tmp);
1652 rc4.process(data, vlen, data); 1767 rc4.process(data, vlen, data);
1653 val = QPDF_String(std::string(tmp, vlen)).unparse(); 1768 val = QPDF_String(std::string(tmp, vlen)).unparse();
@@ -1664,7 +1779,7 @@ QPDFWriter::unparseObject( @@ -1664,7 +1779,7 @@ QPDFWriter::unparseObject(
1664 } 1779 }
1665 1780
1666 void 1781 void
1667 -QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj) 1782 +QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj)
1668 { 1783 {
1669 qpdf_assert_debug(first_obj > 0); 1784 qpdf_assert_debug(first_obj > 0);
1670 bool is_first = true; 1785 bool is_first = true;
@@ -1683,7 +1798,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector&lt;qpdf_offset_t&gt;&amp; offsets, int fi @@ -1683,7 +1798,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector&lt;qpdf_offset_t&gt;&amp; offsets, int fi
1683 } 1798 }
1684 1799
1685 void 1800 void
1686 -QPDFWriter::writeObjectStream(QPDFObjectHandle object) 1801 +QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object)
1687 { 1802 {
1688 // Note: object might be null if this is a place-holder for an object stream that we are 1803 // Note: object might be null if this is a place-holder for an object stream that we are
1689 // generating from scratch. 1804 // generating from scratch.
@@ -1691,7 +1806,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1691,7 +1806,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1691 QPDFObjGen old_og = object.getObjGen(); 1806 QPDFObjGen old_og = object.getObjGen();
1692 qpdf_assert_debug(old_og.getGen() == 0); 1807 qpdf_assert_debug(old_og.getGen() == 0);
1693 int old_id = old_og.getObj(); 1808 int old_id = old_og.getObj();
1694 - int new_stream_id = m->obj[old_og].renumber; 1809 + int new_stream_id = obj[old_og].renumber;
1695 1810
1696 std::vector<qpdf_offset_t> offsets; 1811 std::vector<qpdf_offset_t> offsets;
1697 qpdf_offset_t first = 0; 1812 qpdf_offset_t first = 0;
@@ -1701,39 +1816,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1701,39 +1816,38 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1701 std::string stream_buffer_pass1; 1816 std::string stream_buffer_pass1;
1702 std::string stream_buffer_pass2; 1817 std::string stream_buffer_pass2;
1703 int first_obj = -1; 1818 int first_obj = -1;
1704 - const bool compressed = m->compress_streams && !m->qdf_mode; 1819 + const bool compressed = compress_streams && !qdf_mode;
1705 { 1820 {
1706 // Pass 1 1821 // Pass 1
1707 - auto pp_ostream_pass1 = m->pipeline_stack.activate(stream_buffer_pass1); 1822 + auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1);
1708 1823
1709 int count = -1; 1824 int count = -1;
1710 - for (auto const& obj: m->object_stream_to_objects[old_id]) { 1825 + for (auto const& og: object_stream_to_objects[old_id]) {
1711 ++count; 1826 ++count;
1712 - int new_obj = m->obj[obj].renumber; 1827 + int new_o = obj[og].renumber;
1713 if (first_obj == -1) { 1828 if (first_obj == -1) {
1714 - first_obj = new_obj; 1829 + first_obj = new_o;
1715 } 1830 }
1716 - if (m->qdf_mode) {  
1717 - write("%% Object stream: object ").write(new_obj).write(", index ").write(count);  
1718 - if (!m->suppress_original_object_ids) {  
1719 - write("; original object ID: ").write(obj.getObj()); 1831 + if (qdf_mode) {
  1832 + write("%% Object stream: object ").write(new_o).write(", index ").write(count);
  1833 + if (!suppress_original_object_ids) {
  1834 + write("; original object ID: ").write(og.getObj());
1720 // For compatibility, only write the generation if non-zero. While object 1835 // For compatibility, only write the generation if non-zero. While object
1721 // streams only allow objects with generation 0, if we are generating object 1836 // streams only allow objects with generation 0, if we are generating object
1722 // streams, the old object could have a non-zero generation. 1837 // streams, the old object could have a non-zero generation.
1723 - if (obj.getGen() != 0) {  
1724 - QTC::TC("qpdf", "QPDFWriter original obj non-zero gen");  
1725 - write(" ").write(obj.getGen()); 1838 + if (og.getGen() != 0) {
  1839 + write(" ").write(og.getGen());
1726 } 1840 }
1727 } 1841 }
1728 write("\n"); 1842 write("\n");
1729 } 1843 }
1730 1844
1731 - offsets.push_back(m->pipeline->getCount()); 1845 + offsets.push_back(pipeline->getCount());
1732 // To avoid double-counting objects being written in object streams for progress 1846 // To avoid double-counting objects being written in object streams for progress
1733 // reporting, decrement in pass 1. 1847 // reporting, decrement in pass 1.
1734 indicateProgress(true, false); 1848 indicateProgress(true, false);
1735 1849
1736 - QPDFObjectHandle obj_to_write = m->pdf.getObject(obj); 1850 + QPDFObjectHandle obj_to_write = pdf.getObject(og);
1737 if (obj_to_write.isStream()) { 1851 if (obj_to_write.isStream()) {
1738 // This condition occurred in a fuzz input. Ideally we should block it at parse 1852 // This condition occurred in a fuzz input. Ideally we should block it at parse
1739 // time, but it's not clear to me how to construct a case for this. 1853 // time, but it's not clear to me how to construct a case for this.
@@ -1742,7 +1856,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1742,7 +1856,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1742 } 1856 }
1743 writeObject(obj_to_write, count); 1857 writeObject(obj_to_write, count);
1744 1858
1745 - m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count); 1859 + new_obj[new_o].xref = QPDFXRefEntry(new_stream_id, count);
1746 } 1860 }
1747 } 1861 }
1748 { 1862 {
@@ -1754,13 +1868,13 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1754,13 +1868,13 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1754 1868
1755 // Take one pass at writing pairs of numbers so we can get their size information 1869 // Take one pass at writing pairs of numbers so we can get their size information
1756 { 1870 {
1757 - auto pp_discard = m->pipeline_stack.activate(true); 1871 + auto pp_discard = pipeline_stack.activate(true);
1758 writeObjectStreamOffsets(offsets, first_obj); 1872 writeObjectStreamOffsets(offsets, first_obj);
1759 - first += m->pipeline->getCount(); 1873 + first += pipeline->getCount();
1760 } 1874 }
1761 1875
1762 // Set up a stream to write the stream data into a buffer. 1876 // Set up a stream to write the stream data into a buffer.
1763 - auto pp_ostream = m->pipeline_stack.activate(stream_buffer_pass2); 1877 + auto pp_ostream = pipeline_stack.activate(stream_buffer_pass2);
1764 1878
1765 writeObjectStreamOffsets(offsets, first_obj); 1879 writeObjectStreamOffsets(offsets, first_obj);
1766 write(stream_buffer_pass1); 1880 write(stream_buffer_pass1);
@@ -1792,65 +1906,65 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1792,65 +1906,65 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1792 } 1906 }
1793 } 1907 }
1794 write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); 1908 write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2);
1795 - if (m->encryption) { 1909 + if (encryption) {
1796 QTC::TC("qpdf", "QPDFWriter encrypt object stream"); 1910 QTC::TC("qpdf", "QPDFWriter encrypt object stream");
1797 } 1911 }
1798 - write(m->newline_before_endstream ? "\nendstream" : "endstream");  
1799 - m->cur_data_key.clear(); 1912 + write(newline_before_endstream ? "\nendstream" : "endstream");
  1913 + cur_data_key.clear();
1800 closeObject(new_stream_id); 1914 closeObject(new_stream_id);
1801 } 1915 }
1802 1916
1803 void 1917 void
1804 -QPDFWriter::writeObject(QPDFObjectHandle object, int object_stream_index) 1918 +QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_index)
1805 { 1919 {
1806 QPDFObjGen old_og = object.getObjGen(); 1920 QPDFObjGen old_og = object.getObjGen();
1807 1921
1808 if (object_stream_index == -1 && old_og.getGen() == 0 && 1922 if (object_stream_index == -1 && old_og.getGen() == 0 &&
1809 - m->object_stream_to_objects.contains(old_og.getObj())) { 1923 + object_stream_to_objects.contains(old_og.getObj())) {
1810 writeObjectStream(object); 1924 writeObjectStream(object);
1811 return; 1925 return;
1812 } 1926 }
1813 1927
1814 indicateProgress(false, false); 1928 indicateProgress(false, false);
1815 - auto new_id = m->obj[old_og].renumber;  
1816 - if (m->qdf_mode) {  
1817 - if (m->page_object_to_seq.contains(old_og)) {  
1818 - write("%% Page ").write(m->page_object_to_seq[old_og]).write("\n"); 1929 + auto new_id = obj[old_og].renumber;
  1930 + if (qdf_mode) {
  1931 + if (page_object_to_seq.contains(old_og)) {
  1932 + write("%% Page ").write(page_object_to_seq[old_og]).write("\n");
1819 } 1933 }
1820 - if (m->contents_to_page_seq.contains(old_og)) {  
1821 - write("%% Contents for page ").write(m->contents_to_page_seq[old_og]).write("\n"); 1934 + if (contents_to_page_seq.contains(old_og)) {
  1935 + write("%% Contents for page ").write(contents_to_page_seq[old_og]).write("\n");
1822 } 1936 }
1823 } 1937 }
1824 if (object_stream_index == -1) { 1938 if (object_stream_index == -1) {
1825 - if (m->qdf_mode && (!m->suppress_original_object_ids)) { 1939 + if (qdf_mode && !suppress_original_object_ids) {
1826 write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); 1940 write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n");
1827 } 1941 }
1828 openObject(new_id); 1942 openObject(new_id);
1829 setDataKey(new_id); 1943 setDataKey(new_id);
1830 unparseObject(object, 0, 0); 1944 unparseObject(object, 0, 0);
1831 - m->cur_data_key.clear(); 1945 + cur_data_key.clear();
1832 closeObject(new_id); 1946 closeObject(new_id);
1833 } else { 1947 } else {
1834 unparseObject(object, 0, f_in_ostream); 1948 unparseObject(object, 0, f_in_ostream);
1835 write("\n"); 1949 write("\n");
1836 } 1950 }
1837 1951
1838 - if (!m->direct_stream_lengths && object.isStream()) {  
1839 - if (m->qdf_mode) {  
1840 - if (m->added_newline) { 1952 + if (!direct_stream_lengths && object.isStream()) {
  1953 + if (qdf_mode) {
  1954 + if (added_newline) {
1841 write("%QDF: ignore_newline\n"); 1955 write("%QDF: ignore_newline\n");
1842 } 1956 }
1843 } 1957 }
1844 openObject(new_id + 1); 1958 openObject(new_id + 1);
1845 - write(m->cur_stream_length); 1959 + write(cur_stream_length);
1846 closeObject(new_id + 1); 1960 closeObject(new_id + 1);
1847 } 1961 }
1848 } 1962 }
1849 1963
1850 std::string 1964 std::string
1851 -QPDFWriter::getOriginalID1() 1965 +QPDFWriter::Members::getOriginalID1()
1852 { 1966 {
1853 - QPDFObjectHandle trailer = m->pdf.getTrailer(); 1967 + QPDFObjectHandle trailer = pdf.getTrailer();
1854 if (trailer.hasKey("/ID")) { 1968 if (trailer.hasKey("/ID")) {
1855 return trailer.getKey("/ID").getArrayItem(0).getStringValue(); 1969 return trailer.getKey("/ID").getArrayItem(0).getStringValue();
1856 } else { 1970 } else {
@@ -1859,20 +1973,20 @@ QPDFWriter::getOriginalID1() @@ -1859,20 +1973,20 @@ QPDFWriter::getOriginalID1()
1859 } 1973 }
1860 1974
1861 void 1975 void
1862 -QPDFWriter::generateID(bool encrypted) 1976 +QPDFWriter::Members::generateID(bool encrypted)
1863 { 1977 {
1864 // Generate the ID lazily so that we can handle the user's preference to use static or 1978 // Generate the ID lazily so that we can handle the user's preference to use static or
1865 // deterministic ID generation. 1979 // deterministic ID generation.
1866 1980
1867 - if (!m->id2.empty()) { 1981 + if (!id2.empty()) {
1868 return; 1982 return;
1869 } 1983 }
1870 1984
1871 - QPDFObjectHandle trailer = m->pdf.getTrailer(); 1985 + QPDFObjectHandle trailer = pdf.getTrailer();
1872 1986
1873 std::string result; 1987 std::string result;
1874 1988
1875 - if (m->static_id) { 1989 + if (static_id) {
1876 // For test suite use only... 1990 // For test suite use only...
1877 static unsigned char tmp[] = { 1991 static unsigned char tmp[] = {
1878 0x31, 1992 0x31,
@@ -1904,20 +2018,20 @@ QPDFWriter::generateID(bool encrypted) @@ -1904,20 +2018,20 @@ QPDFWriter::generateID(bool encrypted)
1904 // that case, would have the same ID regardless of the output file's name. 2018 // that case, would have the same ID regardless of the output file's name.
1905 2019
1906 std::string seed; 2020 std::string seed;
1907 - if (m->deterministic_id) { 2021 + if (deterministic_id) {
1908 if (encrypted) { 2022 if (encrypted) {
1909 throw std::runtime_error( 2023 throw std::runtime_error(
1910 "QPDFWriter: unable to generated a deterministic ID because the file to be " 2024 "QPDFWriter: unable to generated a deterministic ID because the file to be "
1911 "written is encrypted (even though the file may not require a password)"); 2025 "written is encrypted (even though the file may not require a password)");
1912 } 2026 }
1913 - if (m->deterministic_id_data.empty()) { 2027 + if (deterministic_id_data.empty()) {
1914 throw std::logic_error( 2028 throw std::logic_error(
1915 "INTERNAL ERROR: QPDFWriter::generateID has no data for deterministic ID"); 2029 "INTERNAL ERROR: QPDFWriter::generateID has no data for deterministic ID");
1916 } 2030 }
1917 - seed += m->deterministic_id_data; 2031 + seed += deterministic_id_data;
1918 } else { 2032 } else {
1919 seed += std::to_string(QUtil::get_current_time()); 2033 seed += std::to_string(QUtil::get_current_time());
1920 - seed += m->filename; 2034 + seed += filename;
1921 seed += " "; 2035 seed += " ";
1922 } 2036 }
1923 seed += " QPDF "; 2037 seed += " QPDF ";
@@ -1930,32 +2044,32 @@ QPDFWriter::generateID(bool encrypted) @@ -1930,32 +2044,32 @@ QPDFWriter::generateID(bool encrypted)
1930 } 2044 }
1931 } 2045 }
1932 2046
1933 - MD5 m;  
1934 - m.encodeString(seed.c_str()); 2047 + MD5 md5;
  2048 + md5.encodeString(seed.c_str());
1935 MD5::Digest digest; 2049 MD5::Digest digest;
1936 - m.digest(digest); 2050 + md5.digest(digest);
1937 result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest)); 2051 result = std::string(reinterpret_cast<char*>(digest), sizeof(MD5::Digest));
1938 } 2052 }
1939 2053
1940 // If /ID already exists, follow the spec: use the original first word and generate a new second 2054 // If /ID already exists, follow the spec: use the original first word and generate a new second
1941 // word. Otherwise, we'll use the generated ID for both. 2055 // word. Otherwise, we'll use the generated ID for both.
1942 2056
1943 - m->id2 = result; 2057 + id2 = result;
1944 // Note: keep /ID from old file even if --static-id was given. 2058 // Note: keep /ID from old file even if --static-id was given.
1945 - m->id1 = getOriginalID1();  
1946 - if (m->id1.empty()) {  
1947 - m->id1 = m->id2; 2059 + id1 = getOriginalID1();
  2060 + if (id1.empty()) {
  2061 + id1 = id2;
1948 } 2062 }
1949 } 2063 }
1950 2064
1951 void 2065 void
1952 -QPDFWriter::initializeSpecialStreams() 2066 +QPDFWriter::Members::initializeSpecialStreams()
1953 { 2067 {
1954 // Mark all page content streams in case we are filtering or normalizing. 2068 // Mark all page content streams in case we are filtering or normalizing.
1955 - std::vector<QPDFObjectHandle> pages = m->pdf.getAllPages(); 2069 + std::vector<QPDFObjectHandle> pages = pdf.getAllPages();
1956 int num = 0; 2070 int num = 0;
1957 for (auto& page: pages) { 2071 for (auto& page: pages) {
1958 - m->page_object_to_seq[page.getObjGen()] = ++num; 2072 + page_object_to_seq[page.getObjGen()] = ++num;
1959 QPDFObjectHandle contents = page.getKey("/Contents"); 2073 QPDFObjectHandle contents = page.getKey("/Contents");
1960 std::vector<QPDFObjGen> contents_objects; 2074 std::vector<QPDFObjGen> contents_objects;
1961 if (contents.isArray()) { 2075 if (contents.isArray()) {
@@ -1968,16 +2082,16 @@ QPDFWriter::initializeSpecialStreams() @@ -1968,16 +2082,16 @@ QPDFWriter::initializeSpecialStreams()
1968 } 2082 }
1969 2083
1970 for (auto const& c: contents_objects) { 2084 for (auto const& c: contents_objects) {
1971 - m->contents_to_page_seq[c] = num;  
1972 - m->normalized_streams.insert(c); 2085 + contents_to_page_seq[c] = num;
  2086 + normalized_streams.insert(c);
1973 } 2087 }
1974 } 2088 }
1975 } 2089 }
1976 2090
1977 void 2091 void
1978 -QPDFWriter::preserveObjectStreams() 2092 +QPDFWriter::Members::preserveObjectStreams()
1979 { 2093 {
1980 - auto const& xref = QPDF::Writer::getXRefTable(m->pdf); 2094 + auto const& xref = QPDF::Writer::getXRefTable(pdf);
1981 // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object 2095 // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object
1982 // streams out of old objects that have generation numbers greater than zero. However in an 2096 // streams out of old objects that have generation numbers greater than zero. However in an
1983 // existing PDF, all object stream objects and all objects in them must have generation 0 2097 // existing PDF, all object stream objects and all objects in them must have generation 0
@@ -1986,14 +2100,13 @@ QPDFWriter::preserveObjectStreams() @@ -1986,14 +2100,13 @@ QPDFWriter::preserveObjectStreams()
1986 // erroneously included in object streams in the source PDF, it also prevents unreferenced 2100 // erroneously included in object streams in the source PDF, it also prevents unreferenced
1987 // objects from being included. 2101 // objects from being included.
1988 auto end = xref.cend(); 2102 auto end = xref.cend();
1989 - m->obj.streams_empty = true;  
1990 - if (m->preserve_unreferenced_objects) { 2103 + obj.streams_empty = true;
  2104 + if (preserve_unreferenced_objects) {
1991 for (auto iter = xref.cbegin(); iter != end; ++iter) { 2105 for (auto iter = xref.cbegin(); iter != end; ++iter) {
1992 if (iter->second.getType() == 2) { 2106 if (iter->second.getType() == 2) {
1993 // Pdf contains object streams. 2107 // Pdf contains object streams.
1994 - QTC::TC("qpdf", "QPDFWriter preserve object streams preserve unreferenced");  
1995 - m->obj.streams_empty = false;  
1996 - m->obj[iter->first].object_stream = iter->second.getObjStreamNumber(); 2108 + obj.streams_empty = false;
  2109 + obj[iter->first].object_stream = iter->second.getObjStreamNumber();
1997 } 2110 }
1998 } 2111 }
1999 } else { 2112 } else {
@@ -2002,9 +2115,8 @@ QPDFWriter::preserveObjectStreams() @@ -2002,9 +2115,8 @@ QPDFWriter::preserveObjectStreams()
2002 for (auto iter = xref.cbegin(); iter != end; ++iter) { 2115 for (auto iter = xref.cbegin(); iter != end; ++iter) {
2003 if (iter->second.getType() == 2) { 2116 if (iter->second.getType() == 2) {
2004 // Pdf contains object streams. 2117 // Pdf contains object streams.
2005 - QTC::TC("qpdf", "QPDFWriter preserve object streams");  
2006 - m->obj.streams_empty = false;  
2007 - auto eligible = QPDF::Writer::getCompressibleObjSet(m->pdf); 2118 + obj.streams_empty = false;
  2119 + auto eligible = QPDF::Writer::getCompressibleObjSet(pdf);
2008 // The object pointed to by iter may be a previous generation, in which case it is 2120 // The object pointed to by iter may be a previous generation, in which case it is
2009 // removed by getCompressibleObjSet. We need to restart the loop (while the object 2121 // removed by getCompressibleObjSet. We need to restart the loop (while the object
2010 // table may contain multiple generations of an object). 2122 // table may contain multiple generations of an object).
@@ -2012,7 +2124,7 @@ QPDFWriter::preserveObjectStreams() @@ -2012,7 +2124,7 @@ QPDFWriter::preserveObjectStreams()
2012 if (iter->second.getType() == 2) { 2124 if (iter->second.getType() == 2) {
2013 auto id = static_cast<size_t>(iter->first.getObj()); 2125 auto id = static_cast<size_t>(iter->first.getObj());
2014 if (id < eligible.size() && eligible[id]) { 2126 if (id < eligible.size() && eligible[id]) {
2015 - m->obj[iter->first].object_stream = iter->second.getObjStreamNumber(); 2127 + obj[iter->first].object_stream = iter->second.getObjStreamNumber();
2016 } else { 2128 } else {
2017 QTC::TC("qpdf", "QPDFWriter exclude from object stream"); 2129 QTC::TC("qpdf", "QPDFWriter exclude from object stream");
2018 } 2130 }
@@ -2025,7 +2137,7 @@ QPDFWriter::preserveObjectStreams() @@ -2025,7 +2137,7 @@ QPDFWriter::preserveObjectStreams()
2025 } 2137 }
2026 2138
2027 void 2139 void
2028 -QPDFWriter::generateObjectStreams() 2140 +QPDFWriter::Members::generateObjectStreams()
2029 { 2141 {
2030 // Basic strategy: make a list of objects that can go into an object stream. Then figure out 2142 // Basic strategy: make a list of objects that can go into an object stream. Then figure out
2031 // how many object streams are needed so that we can distribute objects approximately evenly 2143 // how many object streams are needed so that we can distribute objects approximately evenly
@@ -2035,12 +2147,12 @@ QPDFWriter::generateObjectStreams() @@ -2035,12 +2147,12 @@ QPDFWriter::generateObjectStreams()
2035 2147
2036 // This code doesn't do anything with /Extends. 2148 // This code doesn't do anything with /Extends.
2037 2149
2038 - std::vector<QPDFObjGen> eligible = QPDF::Writer::getCompressibleObjGens(m->pdf); 2150 + std::vector<QPDFObjGen> eligible = QPDF::Writer::getCompressibleObjGens(pdf);
2039 size_t n_object_streams = (eligible.size() + 99U) / 100U; 2151 size_t n_object_streams = (eligible.size() + 99U) / 100U;
2040 2152
2041 initializeTables(2U * n_object_streams); 2153 initializeTables(2U * n_object_streams);
2042 if (n_object_streams == 0) { 2154 if (n_object_streams == 0) {
2043 - m->obj.streams_empty = true; 2155 + obj.streams_empty = true;
2044 return; 2156 return;
2045 } 2157 }
2046 size_t n_per = eligible.size() / n_object_streams; 2158 size_t n_per = eligible.size() / n_object_streams;
@@ -2048,28 +2160,27 @@ QPDFWriter::generateObjectStreams() @@ -2048,28 +2160,27 @@ QPDFWriter::generateObjectStreams()
2048 ++n_per; 2160 ++n_per;
2049 } 2161 }
2050 unsigned int n = 0; 2162 unsigned int n = 0;
2051 - int cur_ostream = m->pdf.newIndirectNull().getObjectID(); 2163 + int cur_ostream = pdf.newIndirectNull().getObjectID();
2052 for (auto const& item: eligible) { 2164 for (auto const& item: eligible) {
2053 if (n == n_per) { 2165 if (n == n_per) {
2054 - QTC::TC("qpdf", "QPDFWriter generate >1 ostream");  
2055 n = 0; 2166 n = 0;
2056 // Construct a new null object as the "original" object stream. The rest of the code 2167 // Construct a new null object as the "original" object stream. The rest of the code
2057 // knows that this means we're creating the object stream from scratch. 2168 // knows that this means we're creating the object stream from scratch.
2058 - cur_ostream = m->pdf.newIndirectNull().getObjectID(); 2169 + cur_ostream = pdf.newIndirectNull().getObjectID();
2059 } 2170 }
2060 - auto& obj = m->obj[item];  
2061 - obj.object_stream = cur_ostream;  
2062 - obj.gen = item.getGen(); 2171 + auto& o = obj[item];
  2172 + o.object_stream = cur_ostream;
  2173 + o.gen = item.getGen();
2063 ++n; 2174 ++n;
2064 } 2175 }
2065 } 2176 }
2066 2177
2067 QPDFObjectHandle 2178 QPDFObjectHandle
2068 -QPDFWriter::getTrimmedTrailer() 2179 +QPDFWriter::Members::getTrimmedTrailer()
2069 { 2180 {
2070 // Remove keys from the trailer that necessarily have to be replaced when writing the file. 2181 // Remove keys from the trailer that necessarily have to be replaced when writing the file.
2071 2182
2072 - QPDFObjectHandle trailer = m->pdf.getTrailer().unsafeShallowCopy(); 2183 + QPDFObjectHandle trailer = pdf.getTrailer().unsafeShallowCopy();
2073 2184
2074 // Remove encryption keys 2185 // Remove encryption keys
2075 trailer.removeKey("/ID"); 2186 trailer.removeKey("/ID");
@@ -2092,10 +2203,10 @@ QPDFWriter::getTrimmedTrailer() @@ -2092,10 +2203,10 @@ QPDFWriter::getTrimmedTrailer()
2092 2203
2093 // Make document extension level information direct as required by the spec. 2204 // Make document extension level information direct as required by the spec.
2094 void 2205 void
2095 -QPDFWriter::prepareFileForWrite() 2206 +QPDFWriter::Members::prepareFileForWrite()
2096 { 2207 {
2097 - m->pdf.fixDanglingReferences();  
2098 - auto root = m->pdf.getRoot(); 2208 + pdf.fixDanglingReferences();
  2209 + auto root = pdf.getRoot();
2099 auto oh = root.getKey("/Extensions"); 2210 auto oh = root.getKey("/Extensions");
2100 if (oh.isDictionary()) { 2211 if (oh.isDictionary()) {
2101 const bool extensions_indirect = oh.isIndirect(); 2212 const bool extensions_indirect = oh.isIndirect();
@@ -2115,84 +2226,83 @@ QPDFWriter::prepareFileForWrite() @@ -2115,84 +2226,83 @@ QPDFWriter::prepareFileForWrite()
2115 } 2226 }
2116 2227
2117 void 2228 void
2118 -QPDFWriter::initializeTables(size_t extra) 2229 +QPDFWriter::Members::initializeTables(size_t extra)
2119 { 2230 {
2120 - auto size = QIntC::to_size(QPDF::Writer::tableSize(m->pdf) + 100) + extra;  
2121 - m->obj.resize(size);  
2122 - m->new_obj.resize(size); 2231 + auto size = QIntC::to_size(QPDF::Writer::tableSize(pdf) + 100) + extra;
  2232 + obj.resize(size);
  2233 + new_obj.resize(size);
2123 } 2234 }
2124 2235
2125 void 2236 void
2126 -QPDFWriter::doWriteSetup() 2237 +QPDFWriter::Members::doWriteSetup()
2127 { 2238 {
2128 - if (m->did_write_setup) { 2239 + if (did_write_setup) {
2129 return; 2240 return;
2130 } 2241 }
2131 - m->did_write_setup = true; 2242 + did_write_setup = true;
2132 2243
2133 // Do preliminary setup 2244 // Do preliminary setup
2134 2245
2135 - if (m->linearized) {  
2136 - m->qdf_mode = false; 2246 + if (linearized) {
  2247 + qdf_mode = false;
2137 } 2248 }
2138 2249
2139 - if (m->pclm) {  
2140 - m->stream_decode_level = qpdf_dl_none;  
2141 - m->compress_streams = false;  
2142 - m->encryption = nullptr; 2250 + if (pclm) {
  2251 + stream_decode_level = qpdf_dl_none;
  2252 + compress_streams = false;
  2253 + encryption = nullptr;
2143 } 2254 }
2144 2255
2145 - if (m->qdf_mode) {  
2146 - if (!m->normalize_content_set) {  
2147 - m->normalize_content = true; 2256 + if (qdf_mode) {
  2257 + if (!normalize_content_set) {
  2258 + normalize_content = true;
2148 } 2259 }
2149 - if (!m->compress_streams_set) {  
2150 - m->compress_streams = false; 2260 + if (!compress_streams_set) {
  2261 + compress_streams = false;
2151 } 2262 }
2152 - if (!m->stream_decode_level_set) {  
2153 - m->stream_decode_level = qpdf_dl_generalized; 2263 + if (!stream_decode_level_set) {
  2264 + stream_decode_level = qpdf_dl_generalized;
2154 } 2265 }
2155 } 2266 }
2156 2267
2157 - if (m->encryption) { 2268 + if (encryption) {
2158 // Encryption has been explicitly set 2269 // Encryption has been explicitly set
2159 - m->preserve_encryption = false;  
2160 - } else if (m->normalize_content || !m->compress_streams || m->pclm || m->qdf_mode) { 2270 + preserve_encryption = false;
  2271 + } else if (normalize_content || !compress_streams || pclm || qdf_mode) {
2161 // Encryption makes looking at contents pretty useless. If the user explicitly encrypted 2272 // Encryption makes looking at contents pretty useless. If the user explicitly encrypted
2162 // though, we still obey that. 2273 // though, we still obey that.
2163 - m->preserve_encryption = false; 2274 + preserve_encryption = false;
2164 } 2275 }
2165 2276
2166 - if (m->preserve_encryption) {  
2167 - copyEncryptionParameters(m->pdf); 2277 + if (preserve_encryption) {
  2278 + copyEncryptionParameters(pdf);
2168 } 2279 }
2169 2280
2170 - if (!m->forced_pdf_version.empty()) { 2281 + if (!forced_pdf_version.empty()) {
2171 int major = 0; 2282 int major = 0;
2172 int minor = 0; 2283 int minor = 0;
2173 - parseVersion(m->forced_pdf_version, major, minor);  
2174 - disableIncompatibleEncryption(major, minor, m->forced_extension_level); 2284 + parseVersion(forced_pdf_version, major, minor);
  2285 + disableIncompatibleEncryption(major, minor, forced_extension_level);
2175 if (compareVersions(major, minor, 1, 5) < 0) { 2286 if (compareVersions(major, minor, 1, 5) < 0) {
2176 - QTC::TC("qpdf", "QPDFWriter forcing object stream disable");  
2177 - m->object_stream_mode = qpdf_o_disable; 2287 + object_stream_mode = qpdf_o_disable;
2178 } 2288 }
2179 } 2289 }
2180 2290
2181 - if (m->qdf_mode || m->normalize_content) { 2291 + if (qdf_mode || normalize_content) {
2182 initializeSpecialStreams(); 2292 initializeSpecialStreams();
2183 } 2293 }
2184 2294
2185 - if (m->qdf_mode) { 2295 + if (qdf_mode) {
2186 // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing 2296 // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing
2187 // recomputed stream length data. Certain streams such as object streams, xref streams, and 2297 // recomputed stream length data. Certain streams such as object streams, xref streams, and
2188 // hint streams always get direct stream lengths. 2298 // hint streams always get direct stream lengths.
2189 - m->direct_stream_lengths = false; 2299 + direct_stream_lengths = false;
2190 } 2300 }
2191 2301
2192 - switch (m->object_stream_mode) { 2302 + switch (object_stream_mode) {
2193 case qpdf_o_disable: 2303 case qpdf_o_disable:
2194 initializeTables(); 2304 initializeTables();
2195 - m->obj.streams_empty = true; 2305 + obj.streams_empty = true;
2196 break; 2306 break;
2197 2307
2198 case qpdf_o_preserve: 2308 case qpdf_o_preserve:
@@ -2207,82 +2317,85 @@ QPDFWriter::doWriteSetup() @@ -2207,82 +2317,85 @@ QPDFWriter::doWriteSetup()
2207 // no default so gcc will warn for missing case tag 2317 // no default so gcc will warn for missing case tag
2208 } 2318 }
2209 2319
2210 - if (!m->obj.streams_empty) {  
2211 - if (m->linearized) { 2320 + if (!obj.streams_empty) {
  2321 + if (linearized) {
2212 // Page dictionaries are not allowed to be compressed objects. 2322 // Page dictionaries are not allowed to be compressed objects.
2213 - for (auto& page: m->pdf.getAllPages()) {  
2214 - if (m->obj[page].object_stream > 0) {  
2215 - QTC::TC("qpdf", "QPDFWriter uncompressing page dictionary");  
2216 - m->obj[page].object_stream = 0; 2323 + for (auto& page: pdf.getAllPages()) {
  2324 + if (obj[page].object_stream > 0) {
  2325 + obj[page].object_stream = 0;
2217 } 2326 }
2218 } 2327 }
2219 } 2328 }
2220 2329
2221 - if (m->linearized || m->encryption) { 2330 + if (linearized || encryption) {
2222 // The document catalog is not allowed to be compressed in linearized files either. It 2331 // The document catalog is not allowed to be compressed in linearized files either. It
2223 // also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to 2332 // also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to
2224 // handle encrypted files with compressed document catalogs, so we disable them in that 2333 // handle encrypted files with compressed document catalogs, so we disable them in that
2225 // case as well. 2334 // case as well.
2226 - if (m->obj[m->root_og].object_stream > 0) {  
2227 - QTC::TC("qpdf", "QPDFWriter uncompressing root");  
2228 - m->obj[m->root_og].object_stream = 0; 2335 + if (obj[root_og].object_stream > 0) {
  2336 + obj[root_og].object_stream = 0;
2229 } 2337 }
2230 } 2338 }
2231 2339
2232 // Generate reverse mapping from object stream to objects 2340 // Generate reverse mapping from object stream to objects
2233 - m->obj.forEach([this](auto id, auto const& item) -> void { 2341 + obj.forEach([this](auto id, auto const& item) -> void {
2234 if (item.object_stream > 0) { 2342 if (item.object_stream > 0) {
2235 - auto& vec = m->object_stream_to_objects[item.object_stream]; 2343 + auto& vec = object_stream_to_objects[item.object_stream];
2236 vec.emplace_back(id, item.gen); 2344 vec.emplace_back(id, item.gen);
2237 - if (m->max_ostream_index < vec.size()) {  
2238 - ++m->max_ostream_index; 2345 + if (max_ostream_index < vec.size()) {
  2346 + ++max_ostream_index;
2239 } 2347 }
2240 } 2348 }
2241 }); 2349 });
2242 - --m->max_ostream_index; 2350 + --max_ostream_index;
2243 2351
2244 - if (m->object_stream_to_objects.empty()) {  
2245 - m->obj.streams_empty = true; 2352 + if (object_stream_to_objects.empty()) {
  2353 + obj.streams_empty = true;
2246 } else { 2354 } else {
2247 - setMinimumPDFVersion("1.5"); 2355 + w.setMinimumPDFVersion("1.5");
2248 } 2356 }
2249 } 2357 }
2250 2358
2251 - setMinimumPDFVersion(m->pdf.getPDFVersion(), m->pdf.getExtensionLevel());  
2252 - m->final_pdf_version = m->min_pdf_version;  
2253 - m->final_extension_level = m->min_extension_level;  
2254 - if (!m->forced_pdf_version.empty()) {  
2255 - QTC::TC("qpdf", "QPDFWriter using forced PDF version");  
2256 - m->final_pdf_version = m->forced_pdf_version;  
2257 - m->final_extension_level = m->forced_extension_level; 2359 + setMinimumPDFVersion(pdf.getPDFVersion(), pdf.getExtensionLevel());
  2360 + final_pdf_version = min_pdf_version;
  2361 + final_extension_level = min_extension_level;
  2362 + if (!forced_pdf_version.empty()) {
  2363 + final_pdf_version = forced_pdf_version;
  2364 + final_extension_level = forced_extension_level;
2258 } 2365 }
2259 } 2366 }
2260 2367
2261 void 2368 void
2262 QPDFWriter::write() 2369 QPDFWriter::write()
2263 { 2370 {
  2371 + m->write();
  2372 +}
  2373 +
  2374 +void
  2375 +QPDFWriter::Members::write()
  2376 +{
2264 doWriteSetup(); 2377 doWriteSetup();
2265 2378
2266 // Set up progress reporting. For linearized files, we write two passes. events_expected is an 2379 // Set up progress reporting. For linearized files, we write two passes. events_expected is an
2267 // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. 2380 // approximation, but it's good enough for progress reporting, which is mostly a guess anyway.
2268 - m->events_expected = QIntC::to_int(m->pdf.getObjectCount() * (m->linearized ? 2 : 1)); 2381 + events_expected = QIntC::to_int(pdf.getObjectCount() * (linearized ? 2 : 1));
2269 2382
2270 prepareFileForWrite(); 2383 prepareFileForWrite();
2271 2384
2272 - if (m->linearized) { 2385 + if (linearized) {
2273 writeLinearized(); 2386 writeLinearized();
2274 } else { 2387 } else {
2275 writeStandard(); 2388 writeStandard();
2276 } 2389 }
2277 2390
2278 - m->pipeline->finish();  
2279 - if (m->close_file) {  
2280 - fclose(m->file); 2391 + pipeline->finish();
  2392 + if (close_file) {
  2393 + fclose(file);
2281 } 2394 }
2282 - m->file = nullptr;  
2283 - if (m->buffer_pipeline) {  
2284 - m->output_buffer = m->buffer_pipeline->getBuffer();  
2285 - m->buffer_pipeline = nullptr; 2395 + file = nullptr;
  2396 + if (buffer_pipeline) {
  2397 + output_buffer = buffer_pipeline->getBuffer();
  2398 + buffer_pipeline = nullptr;
2286 } 2399 }
2287 indicateProgress(false, true); 2400 indicateProgress(false, true);
2288 } 2401 }
@@ -2296,10 +2409,16 @@ QPDFWriter::getRenumberedObjGen(QPDFObjGen og) @@ -2296,10 +2409,16 @@ QPDFWriter::getRenumberedObjGen(QPDFObjGen og)
2296 std::map<QPDFObjGen, QPDFXRefEntry> 2409 std::map<QPDFObjGen, QPDFXRefEntry>
2297 QPDFWriter::getWrittenXRefTable() 2410 QPDFWriter::getWrittenXRefTable()
2298 { 2411 {
  2412 + return m->getWrittenXRefTable();
  2413 +}
  2414 +
  2415 +std::map<QPDFObjGen, QPDFXRefEntry>
  2416 +QPDFWriter::Members::getWrittenXRefTable()
  2417 +{
2299 std::map<QPDFObjGen, QPDFXRefEntry> result; 2418 std::map<QPDFObjGen, QPDFXRefEntry> result;
2300 2419
2301 auto it = result.begin(); 2420 auto it = result.begin();
2302 - m->new_obj.forEach([&it, &result](auto id, auto const& item) -> void { 2421 + new_obj.forEach([&it, &result](auto id, auto const& item) -> void {
2303 if (item.xref.getType() != 0) { 2422 if (item.xref.getType() != 0) {
2304 it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref); 2423 it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref);
2305 } 2424 }
@@ -2308,7 +2427,7 @@ QPDFWriter::getWrittenXRefTable() @@ -2308,7 +2427,7 @@ QPDFWriter::getWrittenXRefTable()
2308 } 2427 }
2309 2428
2310 void 2429 void
2311 -QPDFWriter::enqueuePart(std::vector<QPDFObjectHandle>& part) 2430 +QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part)
2312 { 2431 {
2313 for (auto const& oh: part) { 2432 for (auto const& oh: part) {
2314 enqueueObject(oh); 2433 enqueueObject(oh);
@@ -2316,20 +2435,20 @@ QPDFWriter::enqueuePart(std::vector&lt;QPDFObjectHandle&gt;&amp; part) @@ -2316,20 +2435,20 @@ QPDFWriter::enqueuePart(std::vector&lt;QPDFObjectHandle&gt;&amp; part)
2316 } 2435 }
2317 2436
2318 void 2437 void
2319 -QPDFWriter::writeEncryptionDictionary() 2438 +QPDFWriter::Members::writeEncryptionDictionary()
2320 { 2439 {
2321 - m->encryption_dict_objid = openObject(m->encryption_dict_objid);  
2322 - auto& enc = *m->encryption; 2440 + encryption_dict_objid = openObject(encryption_dict_objid);
  2441 + auto& enc = *encryption;
2323 auto const V = enc.getV(); 2442 auto const V = enc.getV();
2324 2443
2325 write("<<"); 2444 write("<<");
2326 if (V >= 4) { 2445 if (V >= 4) {
2327 write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); 2446 write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM ");
2328 - write(m->encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2"); 2447 + write(encrypt_use_aes ? ((V < 5) ? "/AESV2" : "/AESV3") : "/V2");
2329 // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of 2448 // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of
2330 // MacOS won't open encrypted files without it. 2449 // MacOS won't open encrypted files without it.
2331 write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>"); 2450 write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>");
2332 - if (!m->encryption->getEncryptMetadata()) { 2451 + if (!encryption->getEncryptMetadata()) {
2333 write(" /EncryptMetadata false"); 2452 write(" /EncryptMetadata false");
2334 } 2453 }
2335 } 2454 }
@@ -2352,21 +2471,21 @@ QPDFWriter::writeEncryptionDictionary() @@ -2352,21 +2471,21 @@ QPDFWriter::writeEncryptionDictionary()
2352 write(" /UE ").write_string(enc.getUE(), true); 2471 write(" /UE ").write_string(enc.getUE(), true);
2353 } 2472 }
2354 write(" /V ").write(enc.getV()).write(" >>"); 2473 write(" /V ").write(enc.getV()).write(" >>");
2355 - closeObject(m->encryption_dict_objid); 2474 + closeObject(encryption_dict_objid);
2356 } 2475 }
2357 2476
2358 std::string 2477 std::string
2359 QPDFWriter::getFinalVersion() 2478 QPDFWriter::getFinalVersion()
2360 { 2479 {
2361 - doWriteSetup(); 2480 + m->doWriteSetup();
2362 return m->final_pdf_version; 2481 return m->final_pdf_version;
2363 } 2482 }
2364 2483
2365 void 2484 void
2366 -QPDFWriter::writeHeader() 2485 +QPDFWriter::Members::writeHeader()
2367 { 2486 {
2368 - write("%PDF-").write(m->final_pdf_version);  
2369 - if (m->pclm) { 2487 + write("%PDF-").write(final_pdf_version);
  2488 + if (pclm) {
2370 // PCLm version 2489 // PCLm version
2371 write("\n%PCLm 1.0\n"); 2490 write("\n%PCLm 1.0\n");
2372 } else { 2491 } else {
@@ -2383,13 +2502,13 @@ QPDFWriter::writeHeader() @@ -2383,13 +2502,13 @@ QPDFWriter::writeHeader()
2383 } 2502 }
2384 2503
2385 void 2504 void
2386 -QPDFWriter::writeHintStream(int hint_id) 2505 +QPDFWriter::Members::writeHintStream(int hint_id)
2387 { 2506 {
2388 std::string hint_buffer; 2507 std::string hint_buffer;
2389 int S = 0; 2508 int S = 0;
2390 int O = 0; 2509 int O = 0;
2391 - bool compressed = m->compress_streams && !m->qdf_mode;  
2392 - QPDF::Writer::generateHintStream(m->pdf, m->new_obj, m->obj, hint_buffer, S, O, compressed); 2510 + bool compressed = compress_streams && !qdf_mode;
  2511 + QPDF::Writer::generateHintStream(pdf, new_obj, obj, hint_buffer, S, O, compressed);
2393 2512
2394 openObject(hint_id); 2513 openObject(hint_id);
2395 setDataKey(hint_id); 2514 setDataKey(hint_id);
@@ -2408,7 +2527,7 @@ QPDFWriter::writeHintStream(int hint_id) @@ -2408,7 +2527,7 @@ QPDFWriter::writeHintStream(int hint_id)
2408 write(" /Length ").write(hlen); 2527 write(" /Length ").write(hlen);
2409 write(" >>\nstream\n").write_encrypted(hint_buffer); 2528 write(" >>\nstream\n").write_encrypted(hint_buffer);
2410 2529
2411 - if (m->encryption) { 2530 + if (encryption) {
2412 QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); 2531 QTC::TC("qpdf", "QPDFWriter encrypted hint stream");
2413 } 2532 }
2414 2533
@@ -2417,7 +2536,7 @@ QPDFWriter::writeHintStream(int hint_id) @@ -2417,7 +2536,7 @@ QPDFWriter::writeHintStream(int hint_id)
2417 } 2536 }
2418 2537
2419 qpdf_offset_t 2538 qpdf_offset_t
2420 -QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) 2539 +QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int size)
2421 { 2540 {
2422 // There are too many extra arguments to replace overloaded function with defaults in the header 2541 // There are too many extra arguments to replace overloaded function with defaults in the header
2423 // file...too much risk of leaving something off. 2542 // file...too much risk of leaving something off.
@@ -2425,7 +2544,7 @@ QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size) @@ -2425,7 +2544,7 @@ QPDFWriter::writeXRefTable(trailer_e which, int first, int last, int size)
2425 } 2544 }
2426 2545
2427 qpdf_offset_t 2546 qpdf_offset_t
2428 -QPDFWriter::writeXRefTable( 2547 +QPDFWriter::Members::writeXRefTable(
2429 trailer_e which, 2548 trailer_e which,
2430 int first, 2549 int first,
2431 int last, 2550 int last,
@@ -2438,7 +2557,7 @@ QPDFWriter::writeXRefTable( @@ -2438,7 +2557,7 @@ QPDFWriter::writeXRefTable(
2438 int linearization_pass) 2557 int linearization_pass)
2439 { 2558 {
2440 write("xref\n").write(first).write(" ").write(last - first + 1); 2559 write("xref\n").write(first).write(" ").write(last - first + 1);
2441 - qpdf_offset_t space_before_zero = m->pipeline->getCount(); 2560 + qpdf_offset_t space_before_zero = pipeline->getCount();
2442 write("\n"); 2561 write("\n");
2443 if (first == 0) { 2562 if (first == 0) {
2444 write("0000000000 65535 f \n"); 2563 write("0000000000 65535 f \n");
@@ -2447,7 +2566,7 @@ QPDFWriter::writeXRefTable( @@ -2447,7 +2566,7 @@ QPDFWriter::writeXRefTable(
2447 for (int i = first; i <= last; ++i) { 2566 for (int i = first; i <= last; ++i) {
2448 qpdf_offset_t offset = 0; 2567 qpdf_offset_t offset = 0;
2449 if (!suppress_offsets) { 2568 if (!suppress_offsets) {
2450 - offset = m->new_obj[i].xref.getOffset(); 2569 + offset = new_obj[i].xref.getOffset();
2451 if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) { 2570 if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) {
2452 offset += hint_length; 2571 offset += hint_length;
2453 } 2572 }
@@ -2460,7 +2579,7 @@ QPDFWriter::writeXRefTable( @@ -2460,7 +2579,7 @@ QPDFWriter::writeXRefTable(
2460 } 2579 }
2461 2580
2462 qpdf_offset_t 2581 qpdf_offset_t
2463 -QPDFWriter::writeXRefStream( 2582 +QPDFWriter::Members::writeXRefStream(
2464 int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) 2583 int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size)
2465 { 2584 {
2466 // There are too many extra arguments to replace overloaded function with defaults in the header 2585 // There are too many extra arguments to replace overloaded function with defaults in the header
@@ -2470,7 +2589,7 @@ QPDFWriter::writeXRefStream( @@ -2470,7 +2589,7 @@ QPDFWriter::writeXRefStream(
2470 } 2589 }
2471 2590
2472 qpdf_offset_t 2591 qpdf_offset_t
2473 -QPDFWriter::writeXRefStream( 2592 +QPDFWriter::Members::writeXRefStream(
2474 int xref_id, 2593 int xref_id,
2475 int max_id, 2594 int max_id,
2476 qpdf_offset_t max_offset, 2595 qpdf_offset_t max_offset,
@@ -2485,28 +2604,28 @@ QPDFWriter::writeXRefStream( @@ -2485,28 +2604,28 @@ QPDFWriter::writeXRefStream(
2485 bool skip_compression, 2604 bool skip_compression,
2486 int linearization_pass) 2605 int linearization_pass)
2487 { 2606 {
2488 - qpdf_offset_t xref_offset = m->pipeline->getCount(); 2607 + qpdf_offset_t xref_offset = pipeline->getCount();
2489 qpdf_offset_t space_before_zero = xref_offset - 1; 2608 qpdf_offset_t space_before_zero = xref_offset - 1;
2490 2609
2491 // field 1 contains offsets and object stream identifiers 2610 // field 1 contains offsets and object stream identifiers
2492 unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id)); 2611 unsigned int f1_size = std::max(bytesNeeded(max_offset + hint_length), bytesNeeded(max_id));
2493 2612
2494 // field 2 contains object stream indices 2613 // field 2 contains object stream indices
2495 - unsigned int f2_size = bytesNeeded(QIntC::to_longlong(m->max_ostream_index)); 2614 + unsigned int f2_size = bytesNeeded(QIntC::to_longlong(max_ostream_index));
2496 2615
2497 unsigned int esize = 1 + f1_size + f2_size; 2616 unsigned int esize = 1 + f1_size + f2_size;
2498 2617
2499 // Must store in xref table in advance of writing the actual data rather than waiting for 2618 // Must store in xref table in advance of writing the actual data rather than waiting for
2500 // openObject to do it. 2619 // openObject to do it.
2501 - m->new_obj[xref_id].xref = QPDFXRefEntry(m->pipeline->getCount()); 2620 + new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount());
2502 2621
2503 std::string xref_data; 2622 std::string xref_data;
2504 - const bool compressed = m->compress_streams && !m->qdf_mode; 2623 + const bool compressed = compress_streams && !qdf_mode;
2505 { 2624 {
2506 - auto pp_xref = m->pipeline_stack.activate(xref_data); 2625 + auto pp_xref = pipeline_stack.activate(xref_data);
2507 2626
2508 for (int i = first; i <= last; ++i) { 2627 for (int i = first; i <= last; ++i) {
2509 - QPDFXRefEntry& e = m->new_obj[i].xref; 2628 + QPDFXRefEntry& e = new_obj[i].xref;
2510 switch (e.getType()) { 2629 switch (e.getType()) {
2511 case 0: 2630 case 0:
2512 writeBinary(0, 1); 2631 writeBinary(0, 1);
@@ -2566,7 +2685,7 @@ QPDFWriter::writeXRefStream( @@ -2566,7 +2685,7 @@ QPDFWriter::writeXRefStream(
2566 } 2685 }
2567 2686
2568 size_t 2687 size_t
2569 -QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) 2688 +QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes)
2570 { 2689 {
2571 // This routine is called right after a linearization first pass xref stream has been written 2690 // This routine is called right after a linearization first pass xref stream has been written
2572 // without compression. Calculate the amount of padding that would be required in the worst 2691 // without compression. Calculate the amount of padding that would be required in the worst
@@ -2578,7 +2697,7 @@ QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) @@ -2578,7 +2697,7 @@ QPDFWriter::calculateXrefStreamPadding(qpdf_offset_t xref_bytes)
2578 } 2697 }
2579 2698
2580 void 2699 void
2581 -QPDFWriter::writeLinearized() 2700 +QPDFWriter::Members::writeLinearized()
2582 { 2701 {
2583 // Optimize file and enqueue objects in order 2702 // Optimize file and enqueue objects in order
2584 2703
@@ -2598,14 +2717,14 @@ QPDFWriter::writeLinearized() @@ -2598,14 +2717,14 @@ QPDFWriter::writeLinearized()
2598 return result; 2717 return result;
2599 }; 2718 };
2600 2719
2601 - QPDF::Writer::optimize(m->pdf, m->obj, skip_stream_parameters); 2720 + QPDF::Writer::optimize(pdf, obj, skip_stream_parameters);
2602 2721
2603 std::vector<QPDFObjectHandle> part4; 2722 std::vector<QPDFObjectHandle> part4;
2604 std::vector<QPDFObjectHandle> part6; 2723 std::vector<QPDFObjectHandle> part6;
2605 std::vector<QPDFObjectHandle> part7; 2724 std::vector<QPDFObjectHandle> part7;
2606 std::vector<QPDFObjectHandle> part8; 2725 std::vector<QPDFObjectHandle> part8;
2607 std::vector<QPDFObjectHandle> part9; 2726 std::vector<QPDFObjectHandle> part9;
2608 - QPDF::Writer::getLinearizedParts(m->pdf, m->obj, part4, part6, part7, part8, part9); 2727 + QPDF::Writer::getLinearizedParts(pdf, obj, part4, part6, part7, part8, part9);
2609 2728
2610 // Object number sequence: 2729 // Object number sequence:
2611 // 2730 //
@@ -2627,11 +2746,11 @@ QPDFWriter::writeLinearized() @@ -2627,11 +2746,11 @@ QPDFWriter::writeLinearized()
2627 int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size()); 2746 int second_half_uncompressed = QIntC::to_int(part7.size() + part8.size() + part9.size());
2628 int second_half_first_obj = 1; 2747 int second_half_first_obj = 1;
2629 int after_second_half = 1 + second_half_uncompressed; 2748 int after_second_half = 1 + second_half_uncompressed;
2630 - m->next_objid = after_second_half; 2749 + next_objid = after_second_half;
2631 int second_half_xref = 0; 2750 int second_half_xref = 0;
2632 - bool need_xref_stream = !m->obj.streams_empty; 2751 + bool need_xref_stream = !obj.streams_empty;
2633 if (need_xref_stream) { 2752 if (need_xref_stream) {
2634 - second_half_xref = m->next_objid++; 2753 + second_half_xref = next_objid++;
2635 } 2754 }
2636 // Assign numbers to all compressed objects in the second half. 2755 // Assign numbers to all compressed objects in the second half.
2637 std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9}; 2756 std::vector<QPDFObjectHandle>* vecs2[] = {&part7, &part8, &part9};
@@ -2640,26 +2759,26 @@ QPDFWriter::writeLinearized() @@ -2640,26 +2759,26 @@ QPDFWriter::writeLinearized()
2640 assignCompressedObjectNumbers(oh.getObjGen()); 2759 assignCompressedObjectNumbers(oh.getObjGen());
2641 } 2760 }
2642 } 2761 }
2643 - int second_half_end = m->next_objid - 1;  
2644 - int second_trailer_size = m->next_objid; 2762 + int second_half_end = next_objid - 1;
  2763 + int second_trailer_size = next_objid;
2645 2764
2646 // First half objects 2765 // First half objects
2647 - int first_half_start = m->next_objid;  
2648 - int lindict_id = m->next_objid++; 2766 + int first_half_start = next_objid;
  2767 + int lindict_id = next_objid++;
2649 int first_half_xref = 0; 2768 int first_half_xref = 0;
2650 if (need_xref_stream) { 2769 if (need_xref_stream) {
2651 - first_half_xref = m->next_objid++;  
2652 - }  
2653 - int part4_first_obj = m->next_objid;  
2654 - m->next_objid += QIntC::to_int(part4.size());  
2655 - int after_part4 = m->next_objid;  
2656 - if (m->encryption) {  
2657 - m->encryption_dict_objid = m->next_objid++;  
2658 - }  
2659 - int hint_id = m->next_objid++;  
2660 - int part6_first_obj = m->next_objid;  
2661 - m->next_objid += QIntC::to_int(part6.size());  
2662 - int after_part6 = m->next_objid; 2770 + first_half_xref = next_objid++;
  2771 + }
  2772 + int part4_first_obj = next_objid;
  2773 + next_objid += QIntC::to_int(part4.size());
  2774 + int after_part4 = next_objid;
  2775 + if (encryption) {
  2776 + encryption_dict_objid = next_objid++;
  2777 + }
  2778 + int hint_id = next_objid++;
  2779 + int part6_first_obj = next_objid;
  2780 + next_objid += QIntC::to_int(part6.size());
  2781 + int after_part6 = next_objid;
2663 // Assign numbers to all compressed objects in the first half 2782 // Assign numbers to all compressed objects in the first half
2664 std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6}; 2783 std::vector<QPDFObjectHandle>* vecs1[] = {&part4, &part6};
2665 for (int i = 0; i < 2; ++i) { 2784 for (int i = 0; i < 2; ++i) {
@@ -2667,8 +2786,8 @@ QPDFWriter::writeLinearized() @@ -2667,8 +2786,8 @@ QPDFWriter::writeLinearized()
2667 assignCompressedObjectNumbers(oh.getObjGen()); 2786 assignCompressedObjectNumbers(oh.getObjGen());
2668 } 2787 }
2669 } 2788 }
2670 - int first_half_end = m->next_objid - 1;  
2671 - int first_trailer_size = m->next_objid; 2789 + int first_half_end = next_objid - 1;
  2790 + int first_trailer_size = next_objid;
2672 2791
2673 int part4_end_marker = part4.back().getObjectID(); 2792 int part4_end_marker = part4.back().getObjectID();
2674 int part6_end_marker = part6.back().getObjectID(); 2793 int part6_end_marker = part6.back().getObjectID();
@@ -2680,23 +2799,23 @@ QPDFWriter::writeLinearized() @@ -2680,23 +2799,23 @@ QPDFWriter::writeLinearized()
2680 qpdf_offset_t first_xref_end = 0; 2799 qpdf_offset_t first_xref_end = 0;
2681 qpdf_offset_t second_xref_end = 0; 2800 qpdf_offset_t second_xref_end = 0;
2682 2801
2683 - m->next_objid = part4_first_obj; 2802 + next_objid = part4_first_obj;
2684 enqueuePart(part4); 2803 enqueuePart(part4);
2685 - if (m->next_objid != after_part4) { 2804 + if (next_objid != after_part4) {
2686 // This can happen with very botched files as in the fuzzer test. There are likely some 2805 // This can happen with very botched files as in the fuzzer test. There are likely some
2687 // faulty assumptions in calculateLinearizationData 2806 // faulty assumptions in calculateLinearizationData
2688 throw std::runtime_error("error encountered after writing part 4 of linearized data"); 2807 throw std::runtime_error("error encountered after writing part 4 of linearized data");
2689 } 2808 }
2690 - m->next_objid = part6_first_obj; 2809 + next_objid = part6_first_obj;
2691 enqueuePart(part6); 2810 enqueuePart(part6);
2692 - if (m->next_objid != after_part6) { 2811 + if (next_objid != after_part6) {
2693 throw std::runtime_error("error encountered after writing part 6 of linearized data"); 2812 throw std::runtime_error("error encountered after writing part 6 of linearized data");
2694 } 2813 }
2695 - m->next_objid = second_half_first_obj; 2814 + next_objid = second_half_first_obj;
2696 enqueuePart(part7); 2815 enqueuePart(part7);
2697 enqueuePart(part8); 2816 enqueuePart(part8);
2698 enqueuePart(part9); 2817 enqueuePart(part9);
2699 - if (m->next_objid != after_second_half) { 2818 + if (next_objid != after_second_half) {
2700 throw std::runtime_error("error encountered after writing part 9 of linearized data"); 2819 throw std::runtime_error("error encountered after writing part 9 of linearized data");
2701 } 2820 }
2702 2821
@@ -2706,20 +2825,20 @@ QPDFWriter::writeLinearized() @@ -2706,20 +2825,20 @@ QPDFWriter::writeLinearized()
2706 // Write file in two passes. Part numbers refer to PDF spec 1.4. 2825 // Write file in two passes. Part numbers refer to PDF spec 1.4.
2707 2826
2708 FILE* lin_pass1_file = nullptr; 2827 FILE* lin_pass1_file = nullptr;
2709 - auto pp_pass1 = m->pipeline_stack.popper();  
2710 - auto pp_md5 = m->pipeline_stack.popper(); 2828 + auto pp_pass1 = pipeline_stack.popper();
  2829 + auto pp_md5 = pipeline_stack.popper();
2711 for (int pass: {1, 2}) { 2830 for (int pass: {1, 2}) {
2712 if (pass == 1) { 2831 if (pass == 1) {
2713 - if (!m->lin_pass1_filename.empty()) {  
2714 - lin_pass1_file = QUtil::safe_fopen(m->lin_pass1_filename.c_str(), "wb");  
2715 - m->pipeline_stack.activate( 2832 + if (!lin_pass1_filename.empty()) {
  2833 + lin_pass1_file = QUtil::safe_fopen(lin_pass1_filename.c_str(), "wb");
  2834 + pipeline_stack.activate(
2716 pp_pass1, 2835 pp_pass1,
2717 std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); 2836 std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file));
2718 } else { 2837 } else {
2719 - m->pipeline_stack.activate(pp_pass1, true); 2838 + pipeline_stack.activate(pp_pass1, true);
2720 } 2839 }
2721 - if (m->deterministic_id) {  
2722 - m->pipeline_stack.activate_md5(pp_md5); 2840 + if (deterministic_id) {
  2841 + pipeline_stack.activate_md5(pp_md5);
2723 } 2842 }
2724 } 2843 }
2725 2844
@@ -2733,16 +2852,16 @@ QPDFWriter::writeLinearized() @@ -2733,16 +2852,16 @@ QPDFWriter::writeLinearized()
2733 // linearization parameter dictionary must appear within the first 1024 characters of the 2852 // linearization parameter dictionary must appear within the first 1024 characters of the
2734 // file. 2853 // file.
2735 2854
2736 - qpdf_offset_t pos = m->pipeline->getCount(); 2855 + qpdf_offset_t pos = pipeline->getCount();
2737 openObject(lindict_id); 2856 openObject(lindict_id);
2738 write("<<"); 2857 write("<<");
2739 if (pass == 2) { 2858 if (pass == 2) {
2740 - std::vector<QPDFObjectHandle> const& pages = m->pdf.getAllPages();  
2741 - int first_page_object = m->obj[pages.at(0)].renumber; 2859 + std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
  2860 + int first_page_object = obj[pages.at(0)].renumber;
2742 2861
2743 write(" /Linearized 1 /L ").write(file_size + hint_length); 2862 write(" /Linearized 1 /L ").write(file_size + hint_length);
2744 // Implementation note 121 states that a space is mandatory after this open bracket. 2863 // Implementation note 121 states that a space is mandatory after this open bracket.
2745 - write(" /H [ ").write(m->new_obj[hint_id].xref.getOffset()).write(" "); 2864 + write(" /H [ ").write(new_obj[hint_id].xref.getOffset()).write(" ");
2746 write(hint_length); 2865 write(hint_length);
2747 write(" ] /O ").write(first_page_object); 2866 write(" ] /O ").write(first_page_object);
2748 write(" /E ").write(part6_end_offset + hint_length); 2867 write(" /E ").write(part6_end_offset + hint_length);
@@ -2752,18 +2871,18 @@ QPDFWriter::writeLinearized() @@ -2752,18 +2871,18 @@ QPDFWriter::writeLinearized()
2752 write(" >>"); 2871 write(" >>");
2753 closeObject(lindict_id); 2872 closeObject(lindict_id);
2754 static int const pad = 200; 2873 static int const pad = 200;
2755 - write(QIntC::to_size(pos - m->pipeline->getCount() + pad), ' ').write("\n"); 2874 + write(QIntC::to_size(pos - pipeline->getCount() + pad), ' ').write("\n");
2756 2875
2757 // If the user supplied any additional header text, write it here after the linearization 2876 // If the user supplied any additional header text, write it here after the linearization
2758 // parameter dictionary. 2877 // parameter dictionary.
2759 - write(m->extra_header_text); 2878 + write(extra_header_text);
2760 2879
2761 // Part 3: first page cross reference table and trailer. 2880 // Part 3: first page cross reference table and trailer.
2762 2881
2763 - qpdf_offset_t first_xref_offset = m->pipeline->getCount(); 2882 + qpdf_offset_t first_xref_offset = pipeline->getCount();
2764 qpdf_offset_t hint_offset = 0; 2883 qpdf_offset_t hint_offset = 0;
2765 if (pass == 2) { 2884 if (pass == 2) {
2766 - hint_offset = m->new_obj[hint_id].xref.getOffset(); 2885 + hint_offset = new_obj[hint_id].xref.getOffset();
2767 } 2886 }
2768 if (need_xref_stream) { 2887 if (need_xref_stream) {
2769 // Must pad here too. 2888 // Must pad here too.
@@ -2775,7 +2894,7 @@ QPDFWriter::writeLinearized() @@ -2775,7 +2894,7 @@ QPDFWriter::writeLinearized()
2775 // value for this, but it's okay if it's smaller. 2894 // value for this, but it's okay if it's smaller.
2776 first_half_max_obj_offset = 1 << 25; 2895 first_half_max_obj_offset = 1 << 25;
2777 } 2896 }
2778 - pos = m->pipeline->getCount(); 2897 + pos = pipeline->getCount();
2779 writeXRefStream( 2898 writeXRefStream(
2780 first_half_xref, 2899 first_half_xref,
2781 first_half_end, 2900 first_half_end,
@@ -2790,16 +2909,16 @@ QPDFWriter::writeLinearized() @@ -2790,16 +2909,16 @@ QPDFWriter::writeLinearized()
2790 hint_length, 2909 hint_length,
2791 (pass == 1), 2910 (pass == 1),
2792 pass); 2911 pass);
2793 - qpdf_offset_t endpos = m->pipeline->getCount(); 2912 + qpdf_offset_t endpos = pipeline->getCount();
2794 if (pass == 1) { 2913 if (pass == 1) {
2795 // Pad so we have enough room for the real xref stream. 2914 // Pad so we have enough room for the real xref stream.
2796 write(calculateXrefStreamPadding(endpos - pos), ' '); 2915 write(calculateXrefStreamPadding(endpos - pos), ' ');
2797 - first_xref_end = m->pipeline->getCount(); 2916 + first_xref_end = pipeline->getCount();
2798 } else { 2917 } else {
2799 // Pad so that the next object starts at the same place as in pass 1. 2918 // Pad so that the next object starts at the same place as in pass 1.
2800 write(QIntC::to_size(first_xref_end - endpos), ' '); 2919 write(QIntC::to_size(first_xref_end - endpos), ' ');
2801 2920
2802 - if (m->pipeline->getCount() != first_xref_end) { 2921 + if (pipeline->getCount() != first_xref_end) {
2803 throw std::logic_error( 2922 throw std::logic_error(
2804 "insufficient padding for first pass xref stream; first_xref_end=" + 2923 "insufficient padding for first pass xref stream; first_xref_end=" +
2805 std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos)); 2924 std::to_string(first_xref_end) + "; endpos=" + std::to_string(endpos));
@@ -2823,24 +2942,24 @@ QPDFWriter::writeLinearized() @@ -2823,24 +2942,24 @@ QPDFWriter::writeLinearized()
2823 2942
2824 // Parts 4 through 9 2943 // Parts 4 through 9
2825 2944
2826 - for (auto const& cur_object: m->object_queue) { 2945 + for (auto const& cur_object: object_queue) {
2827 if (cur_object.getObjectID() == part6_end_marker) { 2946 if (cur_object.getObjectID() == part6_end_marker) {
2828 - first_half_max_obj_offset = m->pipeline->getCount(); 2947 + first_half_max_obj_offset = pipeline->getCount();
2829 } 2948 }
2830 writeObject(cur_object); 2949 writeObject(cur_object);
2831 if (cur_object.getObjectID() == part4_end_marker) { 2950 if (cur_object.getObjectID() == part4_end_marker) {
2832 - if (m->encryption) { 2951 + if (encryption) {
2833 writeEncryptionDictionary(); 2952 writeEncryptionDictionary();
2834 } 2953 }
2835 if (pass == 1) { 2954 if (pass == 1) {
2836 - m->new_obj[hint_id].xref = QPDFXRefEntry(m->pipeline->getCount()); 2955 + new_obj[hint_id].xref = QPDFXRefEntry(pipeline->getCount());
2837 } else { 2956 } else {
2838 // Part 5: hint stream 2957 // Part 5: hint stream
2839 write(hint_buffer); 2958 write(hint_buffer);
2840 } 2959 }
2841 } 2960 }
2842 if (cur_object.getObjectID() == part6_end_marker) { 2961 if (cur_object.getObjectID() == part6_end_marker) {
2843 - part6_end_offset = m->pipeline->getCount(); 2962 + part6_end_offset = pipeline->getCount();
2844 } 2963 }
2845 } 2964 }
2846 2965
@@ -2848,9 +2967,9 @@ QPDFWriter::writeLinearized() @@ -2848,9 +2967,9 @@ QPDFWriter::writeLinearized()
2848 2967
2849 // Part 11: main cross reference table and trailer 2968 // Part 11: main cross reference table and trailer
2850 2969
2851 - second_xref_offset = m->pipeline->getCount(); 2970 + second_xref_offset = pipeline->getCount();
2852 if (need_xref_stream) { 2971 if (need_xref_stream) {
2853 - pos = m->pipeline->getCount(); 2972 + pos = pipeline->getCount();
2854 space_before_zero = writeXRefStream( 2973 space_before_zero = writeXRefStream(
2855 second_half_xref, 2974 second_half_xref,
2856 second_half_end, 2975 second_half_end,
@@ -2865,21 +2984,21 @@ QPDFWriter::writeLinearized() @@ -2865,21 +2984,21 @@ QPDFWriter::writeLinearized()
2865 0, 2984 0,
2866 (pass == 1), 2985 (pass == 1),
2867 pass); 2986 pass);
2868 - qpdf_offset_t endpos = m->pipeline->getCount(); 2987 + qpdf_offset_t endpos = pipeline->getCount();
2869 2988
2870 if (pass == 1) { 2989 if (pass == 1) {
2871 // Pad so we have enough room for the real xref stream. See comments for previous 2990 // Pad so we have enough room for the real xref stream. See comments for previous
2872 // xref stream on how we calculate the padding. 2991 // xref stream on how we calculate the padding.
2873 write(calculateXrefStreamPadding(endpos - pos), ' ').write("\n"); 2992 write(calculateXrefStreamPadding(endpos - pos), ' ').write("\n");
2874 - second_xref_end = m->pipeline->getCount(); 2993 + second_xref_end = pipeline->getCount();
2875 } else { 2994 } else {
2876 // Make the file size the same. 2995 // Make the file size the same.
2877 auto padding = 2996 auto padding =
2878 - QIntC::to_size(second_xref_end + hint_length - 1 - m->pipeline->getCount()); 2997 + QIntC::to_size(second_xref_end + hint_length - 1 - pipeline->getCount());
2879 write(padding, ' ').write("\n"); 2998 write(padding, ' ').write("\n");
2880 2999
2881 // If this assertion fails, maybe we didn't have enough padding above. 3000 // If this assertion fails, maybe we didn't have enough padding above.
2882 - if (m->pipeline->getCount() != second_xref_end + hint_length) { 3001 + if (pipeline->getCount() != second_xref_end + hint_length) {
2883 throw std::logic_error( 3002 throw std::logic_error(
2884 "count mismatch after xref stream; possible insufficient padding?"); 3003 "count mismatch after xref stream; possible insufficient padding?");
2885 } 3004 }
@@ -2891,28 +3010,28 @@ QPDFWriter::writeLinearized() @@ -2891,28 +3010,28 @@ QPDFWriter::writeLinearized()
2891 write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); 3010 write("startxref\n").write(first_xref_offset).write("\n%%EOF\n");
2892 3011
2893 if (pass == 1) { 3012 if (pass == 1) {
2894 - if (m->deterministic_id) { 3013 + if (deterministic_id) {
2895 QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); 3014 QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1);
2896 computeDeterministicIDData(); 3015 computeDeterministicIDData();
2897 pp_md5.pop(); 3016 pp_md5.pop();
2898 } 3017 }
2899 3018
2900 // Close first pass pipeline 3019 // Close first pass pipeline
2901 - file_size = m->pipeline->getCount(); 3020 + file_size = pipeline->getCount();
2902 pp_pass1.pop(); 3021 pp_pass1.pop();
2903 3022
2904 // Save hint offset since it will be set to zero by calling openObject. 3023 // Save hint offset since it will be set to zero by calling openObject.
2905 - qpdf_offset_t hint_offset1 = m->new_obj[hint_id].xref.getOffset(); 3024 + qpdf_offset_t hint_offset1 = new_obj[hint_id].xref.getOffset();
2906 3025
2907 // Write hint stream to a buffer 3026 // Write hint stream to a buffer
2908 { 3027 {
2909 - auto pp_hint = m->pipeline_stack.activate(hint_buffer); 3028 + auto pp_hint = pipeline_stack.activate(hint_buffer);
2910 writeHintStream(hint_id); 3029 writeHintStream(hint_id);
2911 } 3030 }
2912 hint_length = QIntC::to_offset(hint_buffer.size()); 3031 hint_length = QIntC::to_offset(hint_buffer.size());
2913 3032
2914 // Restore hint offset 3033 // Restore hint offset
2915 - m->new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); 3034 + new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1);
2916 if (lin_pass1_file) { 3035 if (lin_pass1_file) {
2917 // Write some debugging information 3036 // Write some debugging information
2918 fprintf( 3037 fprintf(
@@ -2934,11 +3053,10 @@ QPDFWriter::writeLinearized() @@ -2934,11 +3053,10 @@ QPDFWriter::writeLinearized()
2934 } 3053 }
2935 3054
2936 void 3055 void
2937 -QPDFWriter::enqueueObjectsStandard() 3056 +QPDFWriter::Members::enqueueObjectsStandard()
2938 { 3057 {
2939 - if (m->preserve_unreferenced_objects) {  
2940 - QTC::TC("qpdf", "QPDFWriter preserve unreferenced standard");  
2941 - for (auto const& oh: m->pdf.getAllObjects()) { 3058 + if (preserve_unreferenced_objects) {
  3059 + for (auto const& oh: pdf.getAllObjects()) {
2942 enqueueObject(oh); 3060 enqueueObject(oh);
2943 } 3061 }
2944 } 3062 }
@@ -2957,14 +3075,14 @@ QPDFWriter::enqueueObjectsStandard() @@ -2957,14 +3075,14 @@ QPDFWriter::enqueueObjectsStandard()
2957 } 3075 }
2958 3076
2959 void 3077 void
2960 -QPDFWriter::enqueueObjectsPCLm() 3078 +QPDFWriter::Members::enqueueObjectsPCLm()
2961 { 3079 {
2962 // Image transform stream content for page strip images. Each of this new stream has to come 3080 // Image transform stream content for page strip images. Each of this new stream has to come
2963 // after every page image strip written in the pclm file. 3081 // after every page image strip written in the pclm file.
2964 std::string image_transform_content = "q /image Do Q\n"; 3082 std::string image_transform_content = "q /image Do Q\n";
2965 3083
2966 // enqueue all pages first 3084 // enqueue all pages first
2967 - std::vector<QPDFObjectHandle> all = m->pdf.getAllPages(); 3085 + std::vector<QPDFObjectHandle> all = pdf.getAllPages();
2968 for (auto& page: all) { 3086 for (auto& page: all) {
2969 // enqueue page 3087 // enqueue page
2970 enqueueObject(page); 3088 enqueueObject(page);
@@ -2977,7 +3095,7 @@ QPDFWriter::enqueueObjectsPCLm() @@ -2977,7 +3095,7 @@ QPDFWriter::enqueueObjectsPCLm()
2977 for (auto& image: strips.as_dictionary()) { 3095 for (auto& image: strips.as_dictionary()) {
2978 if (!image.second.null()) { 3096 if (!image.second.null()) {
2979 enqueueObject(image.second); 3097 enqueueObject(image.second);
2980 - enqueueObject(QPDFObjectHandle::newStream(&m->pdf, image_transform_content)); 3098 + enqueueObject(QPDFObjectHandle::newStream(&pdf, image_transform_content));
2981 } 3099 }
2982 } 3100 }
2983 } 3101 }
@@ -2988,30 +3106,30 @@ QPDFWriter::enqueueObjectsPCLm() @@ -2988,30 +3106,30 @@ QPDFWriter::enqueueObjectsPCLm()
2988 } 3106 }
2989 3107
2990 void 3108 void
2991 -QPDFWriter::indicateProgress(bool decrement, bool finished) 3109 +QPDFWriter::Members::indicateProgress(bool decrement, bool finished)
2992 { 3110 {
2993 if (decrement) { 3111 if (decrement) {
2994 - --m->events_seen; 3112 + --events_seen;
2995 return; 3113 return;
2996 } 3114 }
2997 3115
2998 - ++m->events_seen; 3116 + ++events_seen;
2999 3117
3000 - if (!m->progress_reporter.get()) { 3118 + if (!progress_reporter.get()) {
3001 return; 3119 return;
3002 } 3120 }
3003 3121
3004 - if (finished || (m->events_seen >= m->next_progress_report)) { 3122 + if (finished || events_seen >= next_progress_report) {
3005 int percentage = 3123 int percentage =
3006 (finished ? 100 3124 (finished ? 100
3007 - : m->next_progress_report == 0 3125 + : next_progress_report == 0
3008 ? 0 3126 ? 0
3009 - : std::min(99, 1 + ((100 * m->events_seen) / m->events_expected)));  
3010 - m->progress_reporter->reportProgress(percentage); 3127 + : std::min(99, 1 + ((100 * events_seen) / events_expected)));
  3128 + progress_reporter->reportProgress(percentage);
3011 } 3129 }
3012 - int increment = std::max(1, (m->events_expected / 100));  
3013 - while (m->events_seen >= m->next_progress_report) {  
3014 - m->next_progress_report += increment; 3130 + int increment = std::max(1, (events_expected / 100));
  3131 + while (events_seen >= next_progress_report) {
  3132 + next_progress_report += increment;
3015 } 3133 }
3016 } 3134 }
3017 3135
@@ -3022,53 +3140,52 @@ QPDFWriter::registerProgressReporter(std::shared_ptr&lt;ProgressReporter&gt; pr) @@ -3022,53 +3140,52 @@ QPDFWriter::registerProgressReporter(std::shared_ptr&lt;ProgressReporter&gt; pr)
3022 } 3140 }
3023 3141
3024 void 3142 void
3025 -QPDFWriter::writeStandard() 3143 +QPDFWriter::Members::writeStandard()
3026 { 3144 {
3027 - auto pp_md5 = m->pipeline_stack.popper();  
3028 - if (m->deterministic_id) {  
3029 - m->pipeline_stack.activate_md5(pp_md5); 3145 + auto pp_md5 = pipeline_stack.popper();
  3146 + if (deterministic_id) {
  3147 + pipeline_stack.activate_md5(pp_md5);
3030 } 3148 }
3031 3149
3032 // Start writing 3150 // Start writing
3033 3151
3034 writeHeader(); 3152 writeHeader();
3035 - write(m->extra_header_text); 3153 + write(extra_header_text);
3036 3154
3037 - if (m->pclm) { 3155 + if (pclm) {
3038 enqueueObjectsPCLm(); 3156 enqueueObjectsPCLm();
3039 } else { 3157 } else {
3040 enqueueObjectsStandard(); 3158 enqueueObjectsStandard();
3041 } 3159 }
3042 3160
3043 // Now start walking queue, outputting each object. 3161 // Now start walking queue, outputting each object.
3044 - while (m->object_queue_front < m->object_queue.size()) {  
3045 - QPDFObjectHandle cur_object = m->object_queue.at(m->object_queue_front);  
3046 - ++m->object_queue_front; 3162 + while (object_queue_front < object_queue.size()) {
  3163 + QPDFObjectHandle cur_object = object_queue.at(object_queue_front);
  3164 + ++object_queue_front;
3047 writeObject(cur_object); 3165 writeObject(cur_object);
3048 } 3166 }
3049 3167
3050 // Write out the encryption dictionary, if any 3168 // Write out the encryption dictionary, if any
3051 - if (m->encryption) { 3169 + if (encryption) {
3052 writeEncryptionDictionary(); 3170 writeEncryptionDictionary();
3053 } 3171 }
3054 3172
3055 // Now write out xref. next_objid is now the number of objects. 3173 // Now write out xref. next_objid is now the number of objects.
3056 - qpdf_offset_t xref_offset = m->pipeline->getCount();  
3057 - if (m->object_stream_to_objects.empty()) { 3174 + qpdf_offset_t xref_offset = pipeline->getCount();
  3175 + if (object_stream_to_objects.empty()) {
3058 // Write regular cross-reference table 3176 // Write regular cross-reference table
3059 - writeXRefTable(t_normal, 0, m->next_objid - 1, m->next_objid); 3177 + writeXRefTable(t_normal, 0, next_objid - 1, next_objid);
3060 } else { 3178 } else {
3061 // Write cross-reference stream. 3179 // Write cross-reference stream.
3062 - int xref_id = m->next_objid++;  
3063 - writeXRefStream(  
3064 - xref_id, xref_id, xref_offset, t_normal, 0, m->next_objid - 1, m->next_objid); 3180 + int xref_id = next_objid++;
  3181 + writeXRefStream(xref_id, xref_id, xref_offset, t_normal, 0, next_objid - 1, next_objid);
3065 } 3182 }
3066 write("startxref\n").write(xref_offset).write("\n%%EOF\n"); 3183 write("startxref\n").write(xref_offset).write("\n%%EOF\n");
3067 3184
3068 - if (m->deterministic_id) { 3185 + if (deterministic_id) {
3069 QTC::TC( 3186 QTC::TC(
3070 "qpdf", 3187 "qpdf",
3071 "QPDFWriter standard deterministic ID", 3188 "QPDFWriter standard deterministic ID",
3072 - m->object_stream_to_objects.empty() ? 0 : 1); 3189 + object_stream_to_objects.empty() ? 0 : 1);
3073 } 3190 }
3074 } 3191 }
qpdf/qpdf.testcov
@@ -40,8 +40,6 @@ main QTest array indirect 1 @@ -40,8 +40,6 @@ main QTest array indirect 1
40 main QTest dictionary 0 40 main QTest dictionary 0
41 main QTest dictionary indirect 1 41 main QTest dictionary indirect 1
42 main QTest stream 0 42 main QTest stream 0
43 -QPDFWriter write to stdout 0  
44 -QPDFWriter write to file 0  
45 QPDF lin write nshared_total > nshared_first_page 1 43 QPDF lin write nshared_total > nshared_first_page 1
46 QPDFWriter encrypted hint stream 0 44 QPDFWriter encrypted hint stream 0
47 QPDF opt inherited scalar 0 45 QPDF opt inherited scalar 0
@@ -83,11 +81,7 @@ QPDF xref deleted object 0 @@ -83,11 +81,7 @@ QPDF xref deleted object 0
83 SF_FlateLzwDecode PNG filter 0 81 SF_FlateLzwDecode PNG filter 0
84 QPDF xref /Index is array 1 82 QPDF xref /Index is array 1
85 QPDFWriter encrypt object stream 0 83 QPDFWriter encrypt object stream 0
86 -QPDFWriter uncompressing page dictionary 0  
87 -QPDFWriter uncompressing root 0  
88 -QPDFWriter compressing uncompressed stream 0  
89 QPDF exclude indirect length 0 84 QPDF exclude indirect length 0
90 -QPDFWriter generate >1 ostream 0  
91 QPDF exclude encryption dictionary 0 85 QPDF exclude encryption dictionary 0
92 QPDF loop detected traversing objects 0 86 QPDF loop detected traversing objects 0
93 QPDF reconstructed xref table 0 87 QPDF reconstructed xref table 0
@@ -95,7 +89,6 @@ QPDF recovered in readObjectAtOffset 0 @@ -95,7 +89,6 @@ QPDF recovered in readObjectAtOffset 0
95 QPDF recovered stream length 0 89 QPDF recovered stream length 0
96 QPDF found wrong endstream in recovery 0 90 QPDF found wrong endstream in recovery 0
97 QPDF_Stream pipeStreamData with null pipeline 0 91 QPDF_Stream pipeStreamData with null pipeline 0
98 -QPDFWriter not recompressing /FlateDecode 0  
99 QPDFJob unable to filter 0 92 QPDFJob unable to filter 0
100 QUtil non-trivial UTF-16 0 93 QUtil non-trivial UTF-16 0
101 QPDF xref overwrite invalid objgen 0 94 QPDF xref overwrite invalid objgen 0
@@ -135,14 +128,11 @@ qpdf-c called qpdf_allow_modify_annotation 0 @@ -135,14 +128,11 @@ qpdf-c called qpdf_allow_modify_annotation 0
135 qpdf-c called qpdf_allow_modify_other 0 128 qpdf-c called qpdf_allow_modify_other 0
136 qpdf-c called qpdf_allow_modify_all 0 129 qpdf-c called qpdf_allow_modify_all 0
137 QPDFWriter increasing minimum version 1 130 QPDFWriter increasing minimum version 1
138 -QPDFWriter using forced PDF version 0  
139 qpdf-c called qpdf_set_minimum_pdf_version 0 131 qpdf-c called qpdf_set_minimum_pdf_version 0
140 qpdf-c called qpdf_force_pdf_version 0 132 qpdf-c called qpdf_force_pdf_version 0
141 qpdf-c called qpdf_init_write multiple times 0 133 qpdf-c called qpdf_init_write multiple times 0
142 QPDF_encryption rc4 decode string 0 134 QPDF_encryption rc4 decode string 0
143 -QPDFWriter not compressing metadata 0  
144 QPDF_encryption aes decode string 0 135 QPDF_encryption aes decode string 0
145 -QPDFWriter forcing object stream disable 0  
146 QPDFWriter forced version disabled encryption 0 136 QPDFWriter forced version disabled encryption 0
147 qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0 137 qpdf-c called qpdf_set_r4_encryption_parameters_insecure 0
148 qpdf-c called qpdf_set_static_aes_IV 0 138 qpdf-c called qpdf_set_static_aes_IV 0
@@ -195,7 +185,6 @@ QPDF replace dictionary 0 @@ -195,7 +185,6 @@ QPDF replace dictionary 0
195 QPDF replace stream 0 185 QPDF replace stream 0
196 QPDF replace foreign indirect with null 0 186 QPDF replace foreign indirect with null 0
197 QPDF insert foreign page 0 187 QPDF insert foreign page 0
198 -QPDFWriter foreign object 0  
199 QPDFWriter copy use_aes 1 188 QPDFWriter copy use_aes 1
200 QPDFParser indirect without context 0 189 QPDFParser indirect without context 0
201 QPDFObjectHandle trailing data in parse 0 190 QPDFObjectHandle trailing data in parse 0
@@ -203,17 +192,13 @@ QPDFJob pages encryption password 0 @@ -203,17 +192,13 @@ QPDFJob pages encryption password 0
203 QPDFTokenizer EOF reading token 0 192 QPDFTokenizer EOF reading token 0
204 QPDFTokenizer EOF reading appendable token 0 193 QPDFTokenizer EOF reading appendable token 0
205 QPDFWriter extra header text no newline 0 194 QPDFWriter extra header text no newline 0
206 -QPDFWriter extra header text add newline 0  
207 QPDF bogus 0 offset 0 195 QPDF bogus 0 offset 0
208 QPDF global offset 0 196 QPDF global offset 0
209 -QPDFWriter increasing extension level 0  
210 QPDFWriter make Extensions direct 0 197 QPDFWriter make Extensions direct 0
211 QPDFWriter make ADBE direct 1 198 QPDFWriter make ADBE direct 1
212 QPDFWriter preserve Extensions 0 199 QPDFWriter preserve Extensions 0
213 QPDFWriter create Extensions 1 200 QPDFWriter create Extensions 1
214 -QPDFWriter remove ADBE 0  
215 QPDFWriter remove existing Extensions 0 201 QPDFWriter remove existing Extensions 0
216 -QPDFWriter preserve ADBE 0  
217 QPDF_encryption skip 0x28 0 202 QPDF_encryption skip 0x28 0
218 qpdf-c called qpdf_get_pdf_extension_level 0 203 qpdf-c called qpdf_get_pdf_extension_level 0
219 qpdf-c called qpdf_set_r5_encryption_parameters 0 204 qpdf-c called qpdf_set_r5_encryption_parameters 0
@@ -221,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0 @@ -221,7 +206,6 @@ qpdf-c called qpdf_set_r6_encryption_parameters 0
221 QPDFObjectHandle EOF in inline image 0 206 QPDFObjectHandle EOF in inline image 0
222 QPDFObjectHandle inline image token 0 207 QPDFObjectHandle inline image token 0
223 QPDF not caching overridden objstm object 0 208 QPDF not caching overridden objstm object 0
224 -QPDFWriter original obj non-zero gen 0  
225 QPDF_optimization indirect outlines 0 209 QPDF_optimization indirect outlines 0
226 QPDF xref space 2 210 QPDF xref space 2
227 QPDFJob pages range omitted in middle 0 211 QPDFJob pages range omitted in middle 0
@@ -237,7 +221,6 @@ QPDFParser treat word as string in parseRemainder 0 @@ -237,7 +221,6 @@ QPDFParser treat word as string in parseRemainder 0
237 QPDFParser found fake 1 221 QPDFParser found fake 1
238 QPDFParser no val for last key 0 222 QPDFParser no val for last key 0
239 QPDF resolve failure to null 0 223 QPDF resolve failure to null 0
240 -QPDFWriter preserve unreferenced standard 0  
241 QPDFObjectHandle errors in parsecontent 0 224 QPDFObjectHandle errors in parsecontent 0
242 QPDFJob same file error 0 225 QPDFJob same file error 0
243 QPDFJob split-pages %d 0 226 QPDFJob split-pages %d 0
@@ -374,7 +357,6 @@ QPDF_encryption same password 1 @@ -374,7 +357,6 @@ QPDF_encryption same password 1
374 QPDFParser duplicate dict key 0 357 QPDFParser duplicate dict key 0
375 QPDFWriter no encryption sig contents 0 358 QPDFWriter no encryption sig contents 0
376 QPDFPageObjectHelper colorspace lookup 0 359 QPDFPageObjectHelper colorspace lookup 0
377 -QPDFWriter ignore XRef in qdf mode 0  
378 QPDFPageObjectHelper filter form xobject 0 360 QPDFPageObjectHelper filter form xobject 0
379 QPDFJob found resources in non-leaf 0 361 QPDFJob found resources in non-leaf 0
380 QPDFJob found shared resources in leaf 0 362 QPDFJob found shared resources in leaf 0
@@ -463,7 +445,6 @@ qpdf-c called qpdf_oh_get_generation 0 @@ -463,7 +445,6 @@ qpdf-c called qpdf_oh_get_generation 0
463 qpdf-c called qpdf_oh_unparse 0 445 qpdf-c called qpdf_oh_unparse 0
464 qpdf-c called qpdf_oh_unparse_resolved 0 446 qpdf-c called qpdf_oh_unparse_resolved 0
465 qpdf-c called qpdf_oh_unparse_binary 0 447 qpdf-c called qpdf_oh_unparse_binary 0
466 -QPDFWriter getFilterOnWrite false 0  
467 QPDFPageObjectHelper::forEachXObject 3 448 QPDFPageObjectHelper::forEachXObject 3
468 NNTree erased last kid/item in tree 1 449 NNTree erased last kid/item in tree 1
469 QPDFPageObjectHelper unresolved names 0 450 QPDFPageObjectHelper unresolved names 0
@@ -481,8 +462,6 @@ QPDFAcroFormDocumentHelper AP parse error 1 @@ -481,8 +462,6 @@ QPDFAcroFormDocumentHelper AP parse error 1
481 QPDFJob copy fields not this file 0 462 QPDFJob copy fields not this file 0
482 QPDFJob copy fields non-first from orig 0 463 QPDFJob copy fields non-first from orig 0
483 QPDF resolve duplicated page in insert 0 464 QPDF resolve duplicated page in insert 0
484 -QPDFWriter preserve object streams 0  
485 -QPDFWriter preserve object streams preserve unreferenced 0  
486 QPDFWriter exclude from object stream 0 465 QPDFWriter exclude from object stream 0
487 QPDF_pages findPage not found 0 466 QPDF_pages findPage not found 0
488 QPDFJob weak crypto error 0 467 QPDFJob weak crypto error 0
qpdf/test_driver.cc
@@ -2624,7 +2624,7 @@ test_76(QPDF&amp; pdf, char const* arg2) @@ -2624,7 +2624,7 @@ test_76(QPDF&amp; pdf, char const* arg2)
2624 { 2624 {
2625 // Embedded files. arg2 is a file to attach. Hard-code the 2625 // Embedded files. arg2 is a file to attach. Hard-code the
2626 // mime type and file name for test purposes. 2626 // mime type and file name for test purposes.
2627 - auto &efdh = QPDFEmbeddedFileDocumentHelper::get(pdf); 2627 + auto& efdh = QPDFEmbeddedFileDocumentHelper::get(pdf);
2628 auto fs1 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att1.txt", arg2); 2628 auto fs1 = QPDFFileSpecObjectHelper::createFileSpec(pdf, "att1.txt", arg2);
2629 fs1.setDescription("some text"); 2629 fs1.setDescription("some text");
2630 auto efs1 = QPDFEFStreamObjectHelper(fs1.getEmbeddedFileStream()); 2630 auto efs1 = QPDFEFStreamObjectHelper(fs1.getEmbeddedFileStream());