Commit 7db44e260e5079b1b2647f185a852287ed10799c

Authored by m-holger
1 parent 6408d5cd

Refactor `QPDFWriter`: move configuration logic to `Config` methods, encapsulate…

… parameter handling, and adjust related method calls for improved maintainability and readability.
libqpdf/QPDFWriter.cc
@@ -28,6 +28,7 @@ using namespace std::literals; @@ -28,6 +28,7 @@ using namespace std::literals;
28 using namespace qpdf; 28 using namespace qpdf;
29 29
30 using Encryption = impl::Doc::Encryption; 30 using Encryption = impl::Doc::Encryption;
  31 +using Config = Writer::Config;
31 32
32 QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) 33 QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default)
33 { 34 {
@@ -305,32 +306,32 @@ namespace qpdf::impl @@ -305,32 +306,32 @@ namespace qpdf::impl
305 void doWriteSetup(); 306 void doWriteSetup();
306 void prepareFileForWrite(); 307 void prepareFileForWrite();
307 308
308 - void disableIncompatibleEncryption(int major, int minor, int extension_level);  
309 - void interpretR3EncryptionParameters(  
310 - bool allow_accessibility,  
311 - bool allow_extract,  
312 - bool allow_assemble,  
313 - bool allow_annotate_and_form,  
314 - bool allow_form_filling,  
315 - bool allow_modify_other,  
316 - qpdf_r3_print_e print,  
317 - qpdf_r3_modify_e modify);  
318 - void setEncryptionParameters(char const* user_password, char const* owner_password);  
319 - void setEncryptionMinimumVersion();  
320 - void parseVersion(std::string const& version, int& major, int& minor) const;  
321 - int compareVersions(int major1, int minor1, int major2, int minor2) const;  
322 - void generateID(bool encrypted);  
323 - std::string getOriginalID1();  
324 - void initializeTables(size_t extra = 0);  
325 - void preserveObjectStreams();  
326 - void generateObjectStreams();  
327 - void initializeSpecialStreams();  
328 - void enqueue(QPDFObjectHandle const& object);  
329 - void enqueueObjectsStandard();  
330 - void enqueueObjectsPCLm();  
331 - void enqueuePart(std::vector<QPDFObjectHandle>& part);  
332 - void assignCompressedObjectNumbers(QPDFObjGen og);  
333 - Dictionary trimmed_trailer(); 309 + void disableIncompatibleEncryption(int major, int minor, int extension_level);
  310 + void interpretR3EncryptionParameters(
  311 + bool allow_accessibility,
  312 + bool allow_extract,
  313 + bool allow_assemble,
  314 + bool allow_annotate_and_form,
  315 + bool allow_form_filling,
  316 + bool allow_modify_other,
  317 + qpdf_r3_print_e print,
  318 + qpdf_r3_modify_e modify);
  319 + void setEncryptionParameters(char const* user_password, char const* owner_password);
  320 + void setEncryptionMinimumVersion();
  321 + void parseVersion(std::string const& version, int& major, int& minor) const;
  322 + int compareVersions(int major1, int minor1, int major2, int minor2) const;
  323 + void generateID(bool encrypted);
  324 + std::string getOriginalID1();
  325 + void initializeTables(size_t extra = 0);
  326 + void preserveObjectStreams();
  327 + void generateObjectStreams();
  328 + void initializeSpecialStreams();
  329 + void enqueue(QPDFObjectHandle const& object);
  330 + void enqueueObjectsStandard();
  331 + void enqueueObjectsPCLm();
  332 + void enqueuePart(std::vector<QPDFObjectHandle>& part);
  333 + void assignCompressedObjectNumbers(QPDFObjGen og);
  334 + Dictionary trimmed_trailer();
334 335
335 // Returns tuple<filter, compress_stream, is_root_metadata> 336 // Returns tuple<filter, compress_stream, is_root_metadata>
336 std::tuple<const bool, const bool, const bool> 337 std::tuple<const bool, const bool, const bool>
@@ -557,75 +558,110 @@ QPDFWriter::setOutputPipeline(Pipeline* p) @@ -557,75 +558,110 @@ QPDFWriter::setOutputPipeline(Pipeline* p)
557 void 558 void
558 QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) 559 QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode)
559 { 560 {
560 - m->cfg.object_stream_mode_ = mode; 561 + m->cfg.object_streams(mode);
561 } 562 }
562 563
563 void 564 void
564 QPDFWriter::setStreamDataMode(qpdf_stream_data_e mode) 565 QPDFWriter::setStreamDataMode(qpdf_stream_data_e mode)
565 { 566 {
  567 + m->cfg.stream_data(mode);
  568 +}
  569 +
  570 +Config&
  571 +Config::stream_data(qpdf_stream_data_e mode)
  572 +{
566 switch (mode) { 573 switch (mode) {
567 case qpdf_s_uncompress: 574 case qpdf_s_uncompress:
568 - m->cfg.stream_decode_level_ = std::max(qpdf_dl_generalized, m->cfg.stream_decode_level_);  
569 - m->cfg.compress_streams_ = false;  
570 - break; 575 + stream_decode_level(std::max(qpdf_dl_generalized, stream_decode_level_));
  576 + compress_streams(false);
  577 + return *this;
571 578
572 case qpdf_s_preserve: 579 case qpdf_s_preserve:
573 - m->cfg.stream_decode_level_ = qpdf_dl_none;  
574 - m->cfg.compress_streams_ = false;  
575 - break; 580 + stream_decode_level(qpdf_dl_none);
  581 + compress_streams(false);
  582 + return *this;
576 583
577 case qpdf_s_compress: 584 case qpdf_s_compress:
578 - m->cfg.stream_decode_level_ = std::max(qpdf_dl_generalized, m->cfg.stream_decode_level_);  
579 - m->cfg.compress_streams_ = true;  
580 - break; 585 + stream_decode_level(std::max(qpdf_dl_generalized, stream_decode_level_));
  586 + compress_streams(true);
581 } 587 }
582 - m->cfg.stream_decode_level_set_ = true;  
583 - m->cfg.compress_streams_set_ = true; 588 + return *this;
584 } 589 }
585 590
586 void 591 void
587 QPDFWriter::setCompressStreams(bool val) 592 QPDFWriter::setCompressStreams(bool val)
588 { 593 {
589 - m->cfg.compress_streams_ = val;  
590 - m->cfg.compress_streams_set_ = true; 594 + m->cfg.compress_streams(val);
  595 +}
  596 +
  597 +Config&
  598 +Config::compress_streams(bool val)
  599 +{
  600 + if (pclm_) {
  601 + usage("compress_streams cannot be set when pclm is set");
  602 + return *this;
  603 + }
  604 + compress_streams_set_ = true;
  605 + compress_streams_ = val;
  606 + return *this;
591 } 607 }
592 608
593 void 609 void
594 QPDFWriter::setDecodeLevel(qpdf_stream_decode_level_e val) 610 QPDFWriter::setDecodeLevel(qpdf_stream_decode_level_e val)
595 { 611 {
596 - m->cfg.stream_decode_level_ = val;  
597 - m->cfg.stream_decode_level_set_ = true; 612 + m->cfg.stream_decode_level(val);
  613 +}
  614 +
  615 +Config&
  616 +Config::stream_decode_level(qpdf_stream_decode_level_e val)
  617 +{
  618 + if (pclm_) {
  619 + usage("stream_decode_level cannot be set when pclm is set");
  620 + return *this;
  621 + }
  622 + stream_decode_level_set_ = true;
  623 + stream_decode_level_ = val;
  624 + return *this;
598 } 625 }
599 626
600 void 627 void
601 QPDFWriter::setRecompressFlate(bool val) 628 QPDFWriter::setRecompressFlate(bool val)
602 { 629 {
603 - m->cfg.recompress_flate_ = val; 630 + m->cfg.recompress_flate(val);
604 } 631 }
605 632
606 void 633 void
607 QPDFWriter::setContentNormalization(bool val) 634 QPDFWriter::setContentNormalization(bool val)
608 { 635 {
609 - m->cfg.normalize_content_set_ = true;  
610 - m->cfg.normalize_content_ = val; 636 + m->cfg.normalize_content(val);
611 } 637 }
612 638
613 void 639 void
614 QPDFWriter::setQDFMode(bool val) 640 QPDFWriter::setQDFMode(bool val)
615 { 641 {
616 - m->cfg.qdf_mode_ = val; 642 + m->cfg.qdf(val);
  643 +}
  644 +
  645 +Config&
  646 +Config::qdf(bool val)
  647 +{
  648 + if (pclm_ || linearize_) {
  649 + usage("qdf cannot be set when linearize or pclm are set");
  650 + }
  651 + qdf_ = val;
  652 + return *this;
617 } 653 }
618 654
619 void 655 void
620 QPDFWriter::setPreserveUnreferencedObjects(bool val) 656 QPDFWriter::setPreserveUnreferencedObjects(bool val)
621 { 657 {
622 - m->cfg.preserve_unreferenced_objects_ = val; 658 + m->cfg.preserve_unreferenced(val);
623 } 659 }
624 660
625 void 661 void
626 QPDFWriter::setNewlineBeforeEndstream(bool val) 662 QPDFWriter::setNewlineBeforeEndstream(bool val)
627 { 663 {
628 - m->cfg.newline_before_endstream_ = val; 664 + m->cfg.newline_before_endstream(val);
629 } 665 }
630 666
631 void 667 void
@@ -681,31 +717,37 @@ QPDFWriter::setMinimumPDFVersion(PDFVersion const&amp; v) @@ -681,31 +717,37 @@ QPDFWriter::setMinimumPDFVersion(PDFVersion const&amp; v)
681 void 717 void
682 QPDFWriter::forcePDFVersion(std::string const& version, int extension_level) 718 QPDFWriter::forcePDFVersion(std::string const& version, int extension_level)
683 { 719 {
684 - m->cfg.forced_pdf_version_ = version;  
685 - m->cfg.forced_extension_level_ = extension_level; 720 + m->cfg.forced_pdf_version(version, extension_level);
686 } 721 }
687 722
688 void 723 void
689 QPDFWriter::setExtraHeaderText(std::string const& text) 724 QPDFWriter::setExtraHeaderText(std::string const& text)
690 { 725 {
691 - m->cfg.extra_header_text_ = text;  
692 - if (!m->cfg.extra_header_text_.empty() && m->cfg.extra_header_text_.back() != '\n') {  
693 - m->cfg.extra_header_text_ += "\n"; 726 + m->cfg.extra_header_text(text);
  727 +}
  728 +
  729 +Config&
  730 +Config::extra_header_text(std::string const& val)
  731 +{
  732 + extra_header_text_ = val;
  733 + if (!extra_header_text_.empty() && extra_header_text_.back() != '\n') {
  734 + extra_header_text_ += "\n";
694 } else { 735 } else {
695 QTC::TC("qpdf", "QPDFWriter extra header text no newline"); 736 QTC::TC("qpdf", "QPDFWriter extra header text no newline");
696 } 737 }
  738 + return *this;
697 } 739 }
698 740
699 void 741 void
700 QPDFWriter::setStaticID(bool val) 742 QPDFWriter::setStaticID(bool val)
701 { 743 {
702 - m->cfg.static_id_ = val; 744 + m->cfg.static_id(val);
703 } 745 }
704 746
705 void 747 void
706 QPDFWriter::setDeterministicID(bool val) 748 QPDFWriter::setDeterministicID(bool val)
707 { 749 {
708 - m->cfg.deterministic_id_ = val; 750 + m->cfg.deterministic_id(val);
709 } 751 }
710 752
711 void 753 void
@@ -719,37 +761,61 @@ QPDFWriter::setStaticAesIV(bool val) @@ -719,37 +761,61 @@ QPDFWriter::setStaticAesIV(bool val)
719 void 761 void
720 QPDFWriter::setSuppressOriginalObjectIDs(bool val) 762 QPDFWriter::setSuppressOriginalObjectIDs(bool val)
721 { 763 {
722 - m->cfg.suppress_original_object_ids_ = val; 764 + m->cfg.suppress_original_object_ids(val);
723 } 765 }
724 766
725 void 767 void
726 QPDFWriter::setPreserveEncryption(bool val) 768 QPDFWriter::setPreserveEncryption(bool val)
727 { 769 {
728 - m->cfg.preserve_encryption_ = val; 770 + m->cfg.preserve_encryption(val);
729 } 771 }
730 772
731 void 773 void
732 QPDFWriter::setLinearization(bool val) 774 QPDFWriter::setLinearization(bool val)
733 { 775 {
734 - m->cfg.linearized_ = val;  
735 - if (val) {  
736 - m->cfg.pclm_ = false; 776 + m->cfg.linearize(val);
  777 +}
  778 +
  779 +Config&
  780 +Config::linearize(bool val)
  781 +{
  782 + if (pclm_ || qdf_) {
  783 + usage("linearize cannot be set when qdf or pclm are set");
  784 + return *this;
737 } 785 }
  786 + linearize_ = val;
  787 + return *this;
738 } 788 }
739 789
740 void 790 void
741 QPDFWriter::setLinearizationPass1Filename(std::string const& filename) 791 QPDFWriter::setLinearizationPass1Filename(std::string const& filename)
742 { 792 {
743 - m->cfg.lin_pass1_filename_ = filename; 793 + m->cfg.lin_pass1_filename(filename);
744 } 794 }
745 795
746 void 796 void
747 QPDFWriter::setPCLm(bool val) 797 QPDFWriter::setPCLm(bool val)
748 { 798 {
749 - m->cfg.pclm_ = val; 799 + m->cfg.pclm(val);
  800 +}
  801 +
  802 +Config&
  803 +Config::pclm(bool val)
  804 +{
  805 + if (stream_decode_level_set_ || compress_streams_set_ || linearize_) {
  806 + usage(
  807 + "pclm cannot be set when stream_decode_level, compress_streams, linearize or qdf are "
  808 + "set");
  809 + return *this;
  810 + }
  811 + pclm_ = val;
750 if (val) { 812 if (val) {
751 - m->cfg.linearized_ = false; 813 + stream_decode_level_ = qpdf_dl_none;
  814 + compress_streams_ = false;
  815 + linearize_ = false;
752 } 816 }
  817 +
  818 + return *this;
753 } 819 }
754 820
755 void 821 void
@@ -817,7 +883,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( @@ -817,7 +883,7 @@ QPDFWriter::setR4EncryptionParametersInsecure(
817 bool use_aes) 883 bool use_aes)
818 { 884 {
819 m->encryption = std::make_unique<Encryption>(4, 4, 16, encrypt_metadata); 885 m->encryption = std::make_unique<Encryption>(4, 4, 16, encrypt_metadata);
820 - m->cfg.encrypt_use_aes_ = use_aes; 886 + m->cfg.encrypt_use_aes(use_aes);
821 m->interpretR3EncryptionParameters( 887 m->interpretR3EncryptionParameters(
822 allow_accessibility, 888 allow_accessibility,
823 allow_extract, 889 allow_extract,
@@ -844,7 +910,7 @@ QPDFWriter::setR5EncryptionParameters( @@ -844,7 +910,7 @@ QPDFWriter::setR5EncryptionParameters(
844 bool encrypt_metadata) 910 bool encrypt_metadata)
845 { 911 {
846 m->encryption = std::make_unique<Encryption>(5, 5, 32, encrypt_metadata); 912 m->encryption = std::make_unique<Encryption>(5, 5, 32, encrypt_metadata);
847 - m->cfg.encrypt_use_aes_ = true; 913 + m->cfg.encrypt_use_aes(true);
848 m->interpretR3EncryptionParameters( 914 m->interpretR3EncryptionParameters(
849 allow_accessibility, 915 allow_accessibility,
850 allow_extract, 916 allow_extract,
@@ -880,7 +946,7 @@ QPDFWriter::setR6EncryptionParameters( @@ -880,7 +946,7 @@ QPDFWriter::setR6EncryptionParameters(
880 allow_modify_other, 946 allow_modify_other,
881 print, 947 print,
882 qpdf_r3m_all); 948 qpdf_r3m_all);
883 - m->cfg.encrypt_use_aes_ = true; 949 + m->cfg.encrypt_use_aes(true);
884 m->setEncryptionParameters(user_password, owner_password); 950 m->setEncryptionParameters(user_password, owner_password);
885 } 951 }
886 952
@@ -1001,7 +1067,7 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf) @@ -1001,7 +1067,7 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf)
1001 void 1067 void
1002 impl::Writer::copyEncryptionParameters(QPDF& qpdf) 1068 impl::Writer::copyEncryptionParameters(QPDF& qpdf)
1003 { 1069 {
1004 - cfg.preserve_encryption_ = false; 1070 + cfg.preserve_encryption(false);
1005 QPDFObjectHandle trailer = qpdf.getTrailer(); 1071 QPDFObjectHandle trailer = qpdf.getTrailer();
1006 if (trailer.hasKey("/Encrypt")) { 1072 if (trailer.hasKey("/Encrypt")) {
1007 generateID(true); 1073 generateID(true);
@@ -1021,10 +1087,10 @@ impl::Writer::copyEncryptionParameters(QPDF&amp; qpdf) @@ -1021,10 +1087,10 @@ impl::Writer::copyEncryptionParameters(QPDF&amp; qpdf)
1021 // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of 1087 // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of
1022 // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF 1088 // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF
1023 // all potentially having different values. 1089 // all potentially having different values.
1024 - cfg.encrypt_use_aes_ = true; 1090 + cfg.encrypt_use_aes(true);
1025 } 1091 }
1026 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); 1092 QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1);
1027 - QTC::TC("qpdf", "QPDFWriter copy use_aes", cfg.encrypt_use_aes_ ? 0 : 1); 1093 + QTC::TC("qpdf", "QPDFWriter copy use_aes", cfg.encrypt_use_aes() ? 0 : 1);
1028 1094
1029 encryption = std::make_unique<Encryption>( 1095 encryption = std::make_unique<Encryption>(
1030 V, 1096 V,
@@ -1065,7 +1131,7 @@ impl::Writer::disableIncompatibleEncryption(int major, int minor, int extension_ @@ -1065,7 +1131,7 @@ impl::Writer::disableIncompatibleEncryption(int major, int minor, int extension_
1065 encryption = nullptr; 1131 encryption = nullptr;
1066 } 1132 }
1067 } else if (compareVersions(major, minor, 1, 6) < 0) { 1133 } else if (compareVersions(major, minor, 1, 6) < 0) {
1068 - if (cfg.encrypt_use_aes_) { 1134 + if (cfg.encrypt_use_aes()) {
1069 encryption = nullptr; 1135 encryption = nullptr;
1070 } 1136 }
1071 } else if ( 1137 } else if (
@@ -1122,7 +1188,7 @@ impl::Writer::setEncryptionMinimumVersion() @@ -1122,7 +1188,7 @@ impl::Writer::setEncryptionMinimumVersion()
1122 } else if (R == 5) { 1188 } else if (R == 5) {
1123 setMinimumPDFVersion("1.7", 3); 1189 setMinimumPDFVersion("1.7", 3);
1124 } else if (R == 4) { 1190 } else if (R == 4) {
1125 - setMinimumPDFVersion(cfg.encrypt_use_aes_ ? "1.6" : "1.5"); 1191 + setMinimumPDFVersion(cfg.encrypt_use_aes() ? "1.6" : "1.5");
1126 } else if (R == 3) { 1192 } else if (R == 3) {
1127 setMinimumPDFVersion("1.4"); 1193 setMinimumPDFVersion("1.4");
1128 } else { 1194 } else {
@@ -1135,7 +1201,12 @@ impl::Writer::setDataKey(int objid) @@ -1135,7 +1201,12 @@ impl::Writer::setDataKey(int objid)
1135 { 1201 {
1136 if (encryption) { 1202 if (encryption) {
1137 cur_data_key = QPDF::compute_data_key( 1203 cur_data_key = QPDF::compute_data_key(
1138 - encryption_key, objid, 0, cfg.encrypt_use_aes_, encryption->getV(), encryption->getR()); 1204 + encryption_key,
  1205 + objid,
  1206 + 0,
  1207 + cfg.encrypt_use_aes(),
  1208 + encryption->getV(),
  1209 + encryption->getR());
1139 } 1210 }
1140 } 1211 }
1141 1212
@@ -1203,7 +1274,7 @@ template &lt;typename... Args&gt; @@ -1203,7 +1274,7 @@ template &lt;typename... Args&gt;
1203 impl::Writer& 1274 impl::Writer&
1204 impl::Writer::write_qdf(Args&&... args) 1275 impl::Writer::write_qdf(Args&&... args)
1205 { 1276 {
1206 - if (cfg.qdf_mode_) { 1277 + if (cfg.qdf()) {
1207 pipeline->write(std::forward<Args>(args)...); 1278 pipeline->write(std::forward<Args>(args)...);
1208 } 1279 }
1209 return *this; 1280 return *this;
@@ -1213,7 +1284,7 @@ template &lt;typename... Args&gt; @@ -1213,7 +1284,7 @@ template &lt;typename... Args&gt;
1213 impl::Writer& 1284 impl::Writer&
1214 impl::Writer::write_no_qdf(Args&&... args) 1285 impl::Writer::write_no_qdf(Args&&... args)
1215 { 1286 {
1216 - if (!cfg.qdf_mode_) { 1287 + if (!cfg.qdf()) {
1217 pipeline->write(std::forward<Args>(args)...); 1288 pipeline->write(std::forward<Args>(args)...);
1218 } 1289 }
1219 return *this; 1290 return *this;
@@ -1222,7 +1293,7 @@ impl::Writer::write_no_qdf(Args&amp;&amp;... args) @@ -1222,7 +1293,7 @@ impl::Writer::write_no_qdf(Args&amp;&amp;... args)
1222 void 1293 void
1223 impl::Writer::adjustAESStreamLength(size_t& length) 1294 impl::Writer::adjustAESStreamLength(size_t& length)
1224 { 1295 {
1225 - if (encryption && !cur_data_key.empty() && cfg.encrypt_use_aes_) { 1296 + if (encryption && !cur_data_key.empty() && cfg.encrypt_use_aes()) {
1226 // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will 1297 // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will
1227 // also be prepended by 16 bits of random data. 1298 // also be prepended by 16 bits of random data.
1228 length += 32 - (length & 0xf); 1299 length += 32 - (length & 0xf);
@@ -1234,7 +1305,7 @@ impl::Writer::write_encrypted(std::string_view str) @@ -1234,7 +1305,7 @@ impl::Writer::write_encrypted(std::string_view str)
1234 { 1305 {
1235 if (!(encryption && !cur_data_key.empty())) { 1306 if (!(encryption && !cur_data_key.empty())) {
1236 write(str); 1307 write(str);
1237 - } else if (cfg.encrypt_use_aes_) { 1308 + } else if (cfg.encrypt_use_aes()) {
1238 write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key)); 1309 write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key));
1239 } else { 1310 } else {
1240 write(pl::pipe<Pl_RC4>(str, cur_data_key)); 1311 write(pl::pipe<Pl_RC4>(str, cur_data_key));
@@ -1305,7 +1376,7 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object) @@ -1305,7 +1376,7 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object)
1305 "Use QPDF::copyForeignObject to add objects from another file." // 1376 "Use QPDF::copyForeignObject to add objects from another file." //
1306 ); 1377 );
1307 1378
1308 - if (cfg.qdf_mode_ && object.isStreamOfType("/XRef")) { 1379 + if (cfg.qdf() && object.isStreamOfType("/XRef")) {
1309 // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so 1380 // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so
1310 // will confuse fix-qdf, which expects to see only one XRef stream at the end of the 1381 // will confuse fix-qdf, which expects to see only one XRef stream at the end of the
1311 // file. This case can occur when creating a QDF from a file with object streams when 1382 // file. This case can occur when creating a QDF from a file with object streams when
@@ -1331,10 +1402,10 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object) @@ -1331,10 +1402,10 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object)
1331 if (og.getGen() == 0 && object_stream_to_objects.contains(og.getObj())) { 1402 if (og.getGen() == 0 && object_stream_to_objects.contains(og.getObj())) {
1332 // For linearized files, uncompressed objects go at end, and we take care of 1403 // For linearized files, uncompressed objects go at end, and we take care of
1333 // assigning numbers to them elsewhere. 1404 // assigning numbers to them elsewhere.
1334 - if (!cfg.linearized_) { 1405 + if (!cfg.linearize()) {
1335 assignCompressedObjectNumbers(og); 1406 assignCompressedObjectNumbers(og);
1336 } 1407 }
1337 - } else if (!cfg.direct_stream_lengths_ && object.isStream()) { 1408 + } else if (!cfg.direct_stream_lengths() && object.isStream()) {
1338 // reserve next object ID for length 1409 // reserve next object ID for length
1339 ++next_objid; 1410 ++next_objid;
1340 } 1411 }
@@ -1343,7 +1414,7 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object) @@ -1343,7 +1414,7 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object)
1343 return; 1414 return;
1344 } 1415 }
1345 1416
1346 - if (cfg.linearized_) { 1417 + if (cfg.linearize()) {
1347 return; 1418 return;
1348 } 1419 }
1349 1420
@@ -1364,7 +1435,7 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object) @@ -1364,7 +1435,7 @@ impl::Writer::enqueue(QPDFObjectHandle const&amp; object)
1364 void 1435 void
1365 impl::Writer::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) 1436 impl::Writer::unparseChild(QPDFObjectHandle const& child, size_t level, int flags)
1366 { 1437 {
1367 - if (!cfg.linearized_) { 1438 + if (!cfg.linearize()) {
1368 enqueue(child); 1439 enqueue(child);
1369 } 1440 }
1370 if (child.indirect()) { 1441 if (child.indirect()) {
@@ -1423,7 +1494,7 @@ impl::Writer::writeTrailer( @@ -1423,7 +1494,7 @@ impl::Writer::writeTrailer(
1423 } 1494 }
1424 write("<00000000000000000000000000000000>"); 1495 write("<00000000000000000000000000000000>");
1425 } else { 1496 } else {
1426 - if (linearization_pass == 0 && cfg.deterministic_id_) { 1497 + if (linearization_pass == 0 && cfg.deterministic_id()) {
1427 computeDeterministicIDData(); 1498 computeDeterministicIDData();
1428 } 1499 }
1429 generateID(encryption.get()); 1500 generateID(encryption.get());
@@ -1454,19 +1525,19 @@ impl::Writer::will_filter_stream(QPDFObjectHandle stream, std::string* stream_da @@ -1454,19 +1525,19 @@ impl::Writer::will_filter_stream(QPDFObjectHandle stream, std::string* stream_da
1454 { 1525 {
1455 const bool is_root_metadata = stream.isRootMetadata(); 1526 const bool is_root_metadata = stream.isRootMetadata();
1456 bool filter = false; 1527 bool filter = false;
1457 - auto decode_level = cfg.stream_decode_level_; 1528 + auto decode_level = cfg.stream_decode_level();
1458 int encode_flags = 0; 1529 int encode_flags = 0;
1459 Dictionary stream_dict = stream.getDict(); 1530 Dictionary stream_dict = stream.getDict();
1460 1531
1461 if (stream.getFilterOnWrite()) { 1532 if (stream.getFilterOnWrite()) {
1462 - filter = stream.isDataModified() || cfg.compress_streams_ || decode_level != qpdf_dl_none;  
1463 - if (cfg.compress_streams_) { 1533 + filter = stream.isDataModified() || cfg.compress_streams() || decode_level != qpdf_dl_none;
  1534 + if (cfg.compress_streams()) {
1464 // Don't filter if the stream is already compressed with FlateDecode. This way we don't 1535 // Don't filter if the stream is already compressed with FlateDecode. This way we don't
1465 // make it worse if the original file used a better Flate algorithm, and we don't spend 1536 // make it worse if the original file used a better Flate algorithm, and we don't spend
1466 // time and CPU cycles uncompressing and recompressing stuff. This can be overridden 1537 // time and CPU cycles uncompressing and recompressing stuff. This can be overridden
1467 // with setRecompressFlate(true). 1538 // with setRecompressFlate(true).
1468 Name Filter = stream_dict["/Filter"]; 1539 Name Filter = stream_dict["/Filter"];
1469 - if (Filter && !cfg.recompress_flate_ && !stream.isDataModified() && 1540 + if (Filter && !cfg.recompress_flate() && !stream.isDataModified() &&
1470 (Filter == "/FlateDecode" || Filter == "/Fl")) { 1541 (Filter == "/FlateDecode" || Filter == "/Fl")) {
1471 filter = false; 1542 filter = false;
1472 } 1543 }
@@ -1474,10 +1545,10 @@ impl::Writer::will_filter_stream(QPDFObjectHandle stream, std::string* stream_da @@ -1474,10 +1545,10 @@ impl::Writer::will_filter_stream(QPDFObjectHandle stream, std::string* stream_da
1474 if (is_root_metadata && (!encryption || !encryption->getEncryptMetadata())) { 1545 if (is_root_metadata && (!encryption || !encryption->getEncryptMetadata())) {
1475 filter = true; 1546 filter = true;
1476 decode_level = qpdf_dl_all; 1547 decode_level = qpdf_dl_all;
1477 - } else if (cfg.normalize_content_ && normalized_streams.contains(stream)) { 1548 + } else if (cfg.normalize_content() && normalized_streams.contains(stream)) {
1478 encode_flags = qpdf_ef_normalize; 1549 encode_flags = qpdf_ef_normalize;
1479 filter = true; 1550 filter = true;
1480 - } else if (filter && cfg.compress_streams_) { 1551 + } else if (filter && cfg.compress_streams()) {
1481 encode_flags = qpdf_ef_compress; 1552 encode_flags = qpdf_ef_compress;
1482 } 1553 }
1483 } 1554 }
@@ -1531,11 +1602,11 @@ impl::Writer::unparseObject( @@ -1531,11 +1602,11 @@ impl::Writer::unparseObject(
1531 // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they 1602 // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they
1532 // include the preceding newline. 1603 // include the preceding newline.
1533 std::string indent_large = " "; 1604 std::string indent_large = " ";
1534 - if (cfg.qdf_mode_) { 1605 + if (cfg.qdf()) {
1535 indent_large.append(2 * (level + 1), ' '); 1606 indent_large.append(2 * (level + 1), ' ');
1536 indent_large[0] = '\n'; 1607 indent_large[0] = '\n';
1537 } 1608 }
1538 - std::string_view indent{indent_large.data(), cfg.qdf_mode_ ? indent_large.size() - 2 : 1}; 1609 + std::string_view indent{indent_large.data(), cfg.qdf() ? indent_large.size() - 2 : 1};
1539 1610
1540 if (auto const tc = object.getTypeCode(); tc == ::ot_array) { 1611 if (auto const tc = object.getTypeCode(); tc == ::ot_array) {
1541 // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the 1612 // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the
@@ -1591,7 +1662,7 @@ impl::Writer::unparseObject( @@ -1591,7 +1662,7 @@ impl::Writer::unparseObject(
1591 if (need_extensions_adbe) { 1662 if (need_extensions_adbe) {
1592 if (!(have_extensions_other || have_extensions_adbe)) { 1663 if (!(have_extensions_other || have_extensions_adbe)) {
1593 // We need Extensions and don't have it. Create it here. 1664 // We need Extensions and don't have it. Create it here.
1594 - QTC::TC("qpdf", "QPDFWriter create Extensions", cfg.qdf_mode_ ? 0 : 1); 1665 + QTC::TC("qpdf", "QPDFWriter create Extensions", cfg.qdf() ? 0 : 1);
1595 extensions = object.replaceKeyAndGetNew( 1666 extensions = object.replaceKeyAndGetNew(
1596 "/Extensions", QPDFObjectHandle::newDictionary()); 1667 "/Extensions", QPDFObjectHandle::newDictionary());
1597 } 1668 }
@@ -1696,7 +1767,7 @@ impl::Writer::unparseObject( @@ -1696,7 +1767,7 @@ impl::Writer::unparseObject(
1696 if (flags & f_stream) { 1767 if (flags & f_stream) {
1697 write(indent_large).write("/Length "); 1768 write(indent_large).write("/Length ");
1698 1769
1699 - if (cfg.direct_stream_lengths_) { 1770 + if (cfg.direct_stream_lengths()) {
1700 write(stream_length); 1771 write(stream_length);
1701 } else { 1772 } else {
1702 write(cur_stream_length_id).write(" 0 R"); 1773 write(cur_stream_length_id).write(" 0 R");
@@ -1709,7 +1780,7 @@ impl::Writer::unparseObject( @@ -1709,7 +1780,7 @@ impl::Writer::unparseObject(
1709 write(indent).write(">>"); 1780 write(indent).write(">>");
1710 } else if (tc == ::ot_stream) { 1781 } else if (tc == ::ot_stream) {
1711 // Write stream data to a buffer. 1782 // Write stream data to a buffer.
1712 - if (!cfg.direct_stream_lengths_) { 1783 + if (!cfg.direct_stream_lengths()) {
1713 cur_stream_length_id = obj[old_og].renumber + 1; 1784 cur_stream_length_id = obj[old_og].renumber + 1;
1714 } 1785 }
1715 1786
@@ -1730,14 +1801,14 @@ impl::Writer::unparseObject( @@ -1730,14 +1801,14 @@ impl::Writer::unparseObject(
1730 unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream); 1801 unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream);
1731 char last_char = stream_data.empty() ? '\0' : stream_data.back(); 1802 char last_char = stream_data.empty() ? '\0' : stream_data.back();
1732 write("\nstream\n").write_encrypted(stream_data); 1803 write("\nstream\n").write_encrypted(stream_data);
1733 - added_newline = cfg.newline_before_endstream_ || (cfg.qdf_mode_ && last_char != '\n'); 1804 + added_newline = cfg.newline_before_endstream() || (cfg.qdf() && last_char != '\n');
1734 write(added_newline ? "\nendstream" : "endstream"); 1805 write(added_newline ? "\nendstream" : "endstream");
1735 } else if (tc == ::ot_string) { 1806 } else if (tc == ::ot_string) {
1736 std::string val; 1807 std::string val;
1737 if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && 1808 if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) &&
1738 !cur_data_key.empty()) { 1809 !cur_data_key.empty()) {
1739 val = object.getStringValue(); 1810 val = object.getStringValue();
1740 - if (cfg.encrypt_use_aes_) { 1811 + if (cfg.encrypt_use_aes()) {
1741 Pl_Buffer bufpl("encrypted string"); 1812 Pl_Buffer bufpl("encrypted string");
1742 Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key); 1813 Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key);
1743 pl.writeString(val); 1814 pl.writeString(val);
@@ -1803,7 +1874,7 @@ impl::Writer::writeObjectStream(QPDFObjectHandle object) @@ -1803,7 +1874,7 @@ impl::Writer::writeObjectStream(QPDFObjectHandle object)
1803 std::string stream_buffer_pass1; 1874 std::string stream_buffer_pass1;
1804 std::string stream_buffer_pass2; 1875 std::string stream_buffer_pass2;
1805 int first_obj = -1; 1876 int first_obj = -1;
1806 - const bool compressed = cfg.compress_streams_ && !cfg.qdf_mode_; 1877 + const bool compressed = cfg.compress_streams() && !cfg.qdf();
1807 { 1878 {
1808 // Pass 1 1879 // Pass 1
1809 auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1); 1880 auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1);
@@ -1815,9 +1886,9 @@ impl::Writer::writeObjectStream(QPDFObjectHandle object) @@ -1815,9 +1886,9 @@ impl::Writer::writeObjectStream(QPDFObjectHandle object)
1815 if (first_obj == -1) { 1886 if (first_obj == -1) {
1816 first_obj = new_o; 1887 first_obj = new_o;
1817 } 1888 }
1818 - if (cfg.qdf_mode_) { 1889 + if (cfg.qdf()) {
1819 write("%% Object stream: object ").write(new_o).write(", index ").write(count); 1890 write("%% Object stream: object ").write(new_o).write(", index ").write(count);
1820 - if (!cfg.suppress_original_object_ids_) { 1891 + if (!cfg.suppress_original_object_ids()) {
1821 write("; original object ID: ").write(og.getObj()); 1892 write("; original object ID: ").write(og.getObj());
1822 // For compatibility, only write the generation if non-zero. While object 1893 // For compatibility, only write the generation if non-zero. While object
1823 // streams only allow objects with generation 0, if we are generating object 1894 // streams only allow objects with generation 0, if we are generating object
@@ -1893,11 +1964,10 @@ impl::Writer::writeObjectStream(QPDFObjectHandle object) @@ -1893,11 +1964,10 @@ impl::Writer::writeObjectStream(QPDFObjectHandle object)
1893 } 1964 }
1894 } 1965 }
1895 write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); 1966 write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2);
  1967 + write(cfg.newline_before_endstream() ? "\nendstream" : "endstream");
1896 if (encryption) { 1968 if (encryption) {
1897 - QTC::TC("qpdf", "QPDFWriter encrypt object stream"); 1969 + cur_data_key.clear();
1898 } 1970 }
1899 - write(cfg.newline_before_endstream_ ? "\nendstream" : "endstream");  
1900 - cur_data_key.clear();  
1901 closeObject(new_stream_id); 1971 closeObject(new_stream_id);
1902 } 1972 }
1903 1973
@@ -1914,7 +1984,7 @@ impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index) @@ -1914,7 +1984,7 @@ impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index)
1914 1984
1915 indicateProgress(false, false); 1985 indicateProgress(false, false);
1916 auto new_id = obj[old_og].renumber; 1986 auto new_id = obj[old_og].renumber;
1917 - if (cfg.qdf_mode_) { 1987 + if (cfg.qdf()) {
1918 if (page_object_to_seq.contains(old_og)) { 1988 if (page_object_to_seq.contains(old_og)) {
1919 write("%% Page ").write(page_object_to_seq[old_og]).write("\n"); 1989 write("%% Page ").write(page_object_to_seq[old_og]).write("\n");
1920 } 1990 }
@@ -1923,7 +1993,7 @@ impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index) @@ -1923,7 +1993,7 @@ impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index)
1923 } 1993 }
1924 } 1994 }
1925 if (object_stream_index == -1) { 1995 if (object_stream_index == -1) {
1926 - if (cfg.qdf_mode_ && !cfg.suppress_original_object_ids_) { 1996 + if (cfg.qdf() && !cfg.suppress_original_object_ids()) {
1927 write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); 1997 write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n");
1928 } 1998 }
1929 openObject(new_id); 1999 openObject(new_id);
@@ -1936,8 +2006,8 @@ impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index) @@ -1936,8 +2006,8 @@ impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index)
1936 write("\n"); 2006 write("\n");
1937 } 2007 }
1938 2008
1939 - if (!cfg.direct_stream_lengths_ && object.isStream()) {  
1940 - if (cfg.qdf_mode_) { 2009 + if (!cfg.direct_stream_lengths() && object.isStream()) {
  2010 + if (cfg.qdf()) {
1941 if (added_newline) { 2011 if (added_newline) {
1942 write("%QDF: ignore_newline\n"); 2012 write("%QDF: ignore_newline\n");
1943 } 2013 }
@@ -1973,7 +2043,7 @@ impl::Writer::generateID(bool encrypted) @@ -1973,7 +2043,7 @@ impl::Writer::generateID(bool encrypted)
1973 2043
1974 std::string result; 2044 std::string result;
1975 2045
1976 - if (cfg.static_id_) { 2046 + if (cfg.static_id()) {
1977 // For test suite use only... 2047 // For test suite use only...
1978 static unsigned char tmp[] = { 2048 static unsigned char tmp[] = {
1979 0x31, 2049 0x31,
@@ -2005,7 +2075,7 @@ impl::Writer::generateID(bool encrypted) @@ -2005,7 +2075,7 @@ impl::Writer::generateID(bool encrypted)
2005 // that case, would have the same ID regardless of the output file's name. 2075 // that case, would have the same ID regardless of the output file's name.
2006 2076
2007 std::string seed; 2077 std::string seed;
2008 - if (cfg.deterministic_id_) { 2078 + if (cfg.deterministic_id()) {
2009 if (encrypted) { 2079 if (encrypted) {
2010 throw std::runtime_error( 2080 throw std::runtime_error(
2011 "QPDFWriter: unable to generated a deterministic ID because the file to be " 2081 "QPDFWriter: unable to generated a deterministic ID because the file to be "
@@ -2087,7 +2157,7 @@ impl::Writer::preserveObjectStreams() @@ -2087,7 +2157,7 @@ impl::Writer::preserveObjectStreams()
2087 // objects from being included. 2157 // objects from being included.
2088 auto end = xref.cend(); 2158 auto end = xref.cend();
2089 obj.streams_empty = true; 2159 obj.streams_empty = true;
2090 - if (cfg.preserve_unreferenced_objects_) { 2160 + if (cfg.preserve_unreferenced()) {
2091 for (auto iter = xref.cbegin(); iter != end; ++iter) { 2161 for (auto iter = xref.cbegin(); iter != end; ++iter) {
2092 if (iter->second.getType() == 2) { 2162 if (iter->second.getType() == 2) {
2093 // Pdf contains object streams. 2163 // Pdf contains object streams.
@@ -2229,63 +2299,61 @@ impl::Writer::doWriteSetup() @@ -2229,63 +2299,61 @@ impl::Writer::doWriteSetup()
2229 2299
2230 // Do preliminary setup 2300 // Do preliminary setup
2231 2301
2232 - if (cfg.linearized_) {  
2233 - cfg.qdf_mode_ = false; 2302 + if (cfg.linearize()) {
  2303 + cfg.qdf(false);
2234 } 2304 }
2235 2305
2236 - if (cfg.pclm_) {  
2237 - cfg.stream_decode_level_ = qpdf_dl_none;  
2238 - cfg.compress_streams_ = false; 2306 + if (cfg.pclm()) {
2239 encryption = nullptr; 2307 encryption = nullptr;
2240 } 2308 }
2241 2309
2242 - if (cfg.qdf_mode_) { 2310 + if (cfg.qdf()) {
2243 if (!cfg.normalize_content_set_) { 2311 if (!cfg.normalize_content_set_) {
2244 - cfg.normalize_content_ = true; 2312 + cfg.normalize_content(true);
2245 } 2313 }
2246 if (!cfg.compress_streams_set_) { 2314 if (!cfg.compress_streams_set_) {
2247 - cfg.compress_streams_ = false; 2315 + cfg.compress_streams(false);
2248 } 2316 }
2249 if (!cfg.stream_decode_level_set_) { 2317 if (!cfg.stream_decode_level_set_) {
2250 - cfg.stream_decode_level_ = qpdf_dl_generalized; 2318 + cfg.stream_decode_level(qpdf_dl_generalized);
2251 } 2319 }
2252 } 2320 }
2253 2321
2254 if (encryption) { 2322 if (encryption) {
2255 // Encryption has been explicitly set 2323 // Encryption has been explicitly set
2256 - cfg.preserve_encryption_ = false;  
2257 - } else if (cfg.normalize_content_ || cfg.pclm_ || cfg.qdf_mode_) { 2324 + cfg.preserve_encryption(false);
  2325 + } else if (cfg.normalize_content() || cfg.pclm() || cfg.qdf()) {
2258 // Encryption makes looking at contents pretty useless. If the user explicitly encrypted 2326 // Encryption makes looking at contents pretty useless. If the user explicitly encrypted
2259 // though, we still obey that. 2327 // though, we still obey that.
2260 - cfg.preserve_encryption_ = false; 2328 + cfg.preserve_encryption(false);
2261 } 2329 }
2262 2330
2263 - if (cfg.preserve_encryption_) { 2331 + if (cfg.preserve_encryption()) {
2264 copyEncryptionParameters(qpdf); 2332 copyEncryptionParameters(qpdf);
2265 } 2333 }
2266 2334
2267 - if (!cfg.forced_pdf_version_.empty()) { 2335 + if (!cfg.forced_pdf_version().empty()) {
2268 int major = 0; 2336 int major = 0;
2269 int minor = 0; 2337 int minor = 0;
2270 - parseVersion(cfg.forced_pdf_version_, major, minor);  
2271 - disableIncompatibleEncryption(major, minor, cfg.forced_extension_level_); 2338 + parseVersion(cfg.forced_pdf_version(), major, minor);
  2339 + disableIncompatibleEncryption(major, minor, cfg.forced_extension_level());
2272 if (compareVersions(major, minor, 1, 5) < 0) { 2340 if (compareVersions(major, minor, 1, 5) < 0) {
2273 - cfg.object_stream_mode_ = qpdf_o_disable; 2341 + cfg.object_streams(qpdf_o_disable);
2274 } 2342 }
2275 } 2343 }
2276 2344
2277 - if (cfg.qdf_mode_ || cfg.normalize_content_) { 2345 + if (cfg.qdf() || cfg.normalize_content()) {
2278 initializeSpecialStreams(); 2346 initializeSpecialStreams();
2279 } 2347 }
2280 2348
2281 - if (cfg.qdf_mode_) { 2349 + if (cfg.qdf()) {
2282 // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing 2350 // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing
2283 // recomputed stream length data. Certain streams such as object streams, xref streams, and 2351 // recomputed stream length data. Certain streams such as object streams, xref streams, and
2284 // hint streams always get direct stream lengths. 2352 // hint streams always get direct stream lengths.
2285 cfg.direct_stream_lengths_ = false; 2353 cfg.direct_stream_lengths_ = false;
2286 } 2354 }
2287 2355
2288 - switch (cfg.object_stream_mode_) { 2356 + switch (cfg.object_streams()) {
2289 case qpdf_o_disable: 2357 case qpdf_o_disable:
2290 initializeTables(); 2358 initializeTables();
2291 obj.streams_empty = true; 2359 obj.streams_empty = true;
@@ -2299,12 +2367,10 @@ impl::Writer::doWriteSetup() @@ -2299,12 +2367,10 @@ impl::Writer::doWriteSetup()
2299 case qpdf_o_generate: 2367 case qpdf_o_generate:
2300 generateObjectStreams(); 2368 generateObjectStreams();
2301 break; 2369 break;
2302 -  
2303 - // no default so gcc will warn for missing case tag  
2304 } 2370 }
2305 2371
2306 if (!obj.streams_empty) { 2372 if (!obj.streams_empty) {
2307 - if (cfg.linearized_) { 2373 + if (cfg.linearize()) {
2308 // Page dictionaries are not allowed to be compressed objects. 2374 // Page dictionaries are not allowed to be compressed objects.
2309 for (auto& page: pages) { 2375 for (auto& page: pages) {
2310 if (obj[page].object_stream > 0) { 2376 if (obj[page].object_stream > 0) {
@@ -2313,7 +2379,7 @@ impl::Writer::doWriteSetup() @@ -2313,7 +2379,7 @@ impl::Writer::doWriteSetup()
2313 } 2379 }
2314 } 2380 }
2315 2381
2316 - if (cfg.linearized_ || encryption) { 2382 + if (cfg.linearize() || encryption) {
2317 // The document catalog is not allowed to be compressed in cfg.linearized_ files either. 2383 // The document catalog is not allowed to be compressed in cfg.linearized_ files either.
2318 // It also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to 2384 // It also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to
2319 // handle encrypted files with compressed document catalogs, so we disable them in that 2385 // handle encrypted files with compressed document catalogs, so we disable them in that
@@ -2345,9 +2411,9 @@ impl::Writer::doWriteSetup() @@ -2345,9 +2411,9 @@ impl::Writer::doWriteSetup()
2345 setMinimumPDFVersion(qpdf.getPDFVersion(), qpdf.getExtensionLevel()); 2411 setMinimumPDFVersion(qpdf.getPDFVersion(), qpdf.getExtensionLevel());
2346 final_pdf_version = min_pdf_version; 2412 final_pdf_version = min_pdf_version;
2347 final_extension_level = min_extension_level; 2413 final_extension_level = min_extension_level;
2348 - if (!cfg.forced_pdf_version_.empty()) {  
2349 - final_pdf_version = cfg.forced_pdf_version_;  
2350 - final_extension_level = cfg.forced_extension_level_; 2414 + if (!cfg.forced_pdf_version().empty()) {
  2415 + final_pdf_version = cfg.forced_pdf_version();
  2416 + final_extension_level = cfg.forced_extension_level();
2351 } 2417 }
2352 } 2418 }
2353 2419
@@ -2364,11 +2430,11 @@ impl::Writer::write() @@ -2364,11 +2430,11 @@ impl::Writer::write()
2364 2430
2365 // Set up progress reporting. For linearized files, we write two passes. events_expected is an 2431 // Set up progress reporting. For linearized files, we write two passes. events_expected is an
2366 // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. 2432 // approximation, but it's good enough for progress reporting, which is mostly a guess anyway.
2367 - events_expected = QIntC::to_int(qpdf.getObjectCount() * (cfg.linearized_ ? 2 : 1)); 2433 + events_expected = QIntC::to_int(qpdf.getObjectCount() * (cfg.linearize() ? 2 : 1));
2368 2434
2369 prepareFileForWrite(); 2435 prepareFileForWrite();
2370 2436
2371 - if (cfg.linearized_) { 2437 + if (cfg.linearize()) {
2372 writeLinearized(); 2438 writeLinearized();
2373 } else { 2439 } else {
2374 writeStandard(); 2440 writeStandard();
@@ -2430,7 +2496,7 @@ impl::Writer::writeEncryptionDictionary() @@ -2430,7 +2496,7 @@ impl::Writer::writeEncryptionDictionary()
2430 write("<<"); 2496 write("<<");
2431 if (V >= 4) { 2497 if (V >= 4) {
2432 write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); 2498 write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM ");
2433 - write(cfg.encrypt_use_aes_ ? (V < 5 ? "/AESV2" : "/AESV3") : "/V2"); 2499 + write(cfg.encrypt_use_aes() ? (V < 5 ? "/AESV2" : "/AESV3") : "/V2");
2434 // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of 2500 // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of
2435 // MacOS won't open encrypted files without it. 2501 // MacOS won't open encrypted files without it.
2436 write(V < 5 ? " /Length 16 >> >>" : " /Length 32 >> >>"); 2502 write(V < 5 ? " /Length 16 >> >>" : " /Length 32 >> >>");
@@ -2471,7 +2537,7 @@ void @@ -2471,7 +2537,7 @@ void
2471 impl::Writer::writeHeader() 2537 impl::Writer::writeHeader()
2472 { 2538 {
2473 write("%PDF-").write(final_pdf_version); 2539 write("%PDF-").write(final_pdf_version);
2474 - if (cfg.pclm_) { 2540 + if (cfg.pclm()) {
2475 // PCLm version 2541 // PCLm version
2476 write("\n%PCLm 1.0\n"); 2542 write("\n%PCLm 1.0\n");
2477 } else { 2543 } else {
@@ -2493,7 +2559,7 @@ impl::Writer::writeHintStream(int hint_id) @@ -2493,7 +2559,7 @@ impl::Writer::writeHintStream(int hint_id)
2493 std::string hint_buffer; 2559 std::string hint_buffer;
2494 int S = 0; 2560 int S = 0;
2495 int O = 0; 2561 int O = 0;
2496 - bool compressed = cfg.compress_streams_; 2562 + bool compressed = cfg.compress_streams();
2497 lin.generateHintStream(new_obj, obj, hint_buffer, S, O, compressed); 2563 lin.generateHintStream(new_obj, obj, hint_buffer, S, O, compressed);
2498 2564
2499 openObject(hint_id); 2565 openObject(hint_id);
@@ -2606,7 +2672,7 @@ impl::Writer::writeXRefStream( @@ -2606,7 +2672,7 @@ impl::Writer::writeXRefStream(
2606 new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount()); 2672 new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount());
2607 2673
2608 std::string xref_data; 2674 std::string xref_data;
2609 - const bool compressed = cfg.compress_streams_ && !cfg.qdf_mode_; 2675 + const bool compressed = cfg.compress_streams() && !cfg.qdf();
2610 { 2676 {
2611 auto pp_xref = pipeline_stack.activate(xref_data); 2677 auto pp_xref = pipeline_stack.activate(xref_data);
2612 2678
@@ -2809,15 +2875,15 @@ impl::Writer::writeLinearized() @@ -2809,15 +2875,15 @@ impl::Writer::writeLinearized()
2809 auto pp_md5 = pipeline_stack.popper(); 2875 auto pp_md5 = pipeline_stack.popper();
2810 for (int pass: {1, 2}) { 2876 for (int pass: {1, 2}) {
2811 if (pass == 1) { 2877 if (pass == 1) {
2812 - if (!cfg.lin_pass1_filename_.empty()) {  
2813 - lin_pass1_file = QUtil::safe_fopen(cfg.lin_pass1_filename_.data(), "wb"); 2878 + if (!cfg.lin_pass1_filename().empty()) {
  2879 + lin_pass1_file = QUtil::safe_fopen(cfg.lin_pass1_filename().data(), "wb");
2814 pipeline_stack.activate( 2880 pipeline_stack.activate(
2815 pp_pass1, 2881 pp_pass1,
2816 std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); 2882 std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file));
2817 } else { 2883 } else {
2818 pipeline_stack.activate(pp_pass1, true); 2884 pipeline_stack.activate(pp_pass1, true);
2819 } 2885 }
2820 - if (cfg.deterministic_id_) { 2886 + if (cfg.deterministic_id()) {
2821 pipeline_stack.activate_md5(pp_md5); 2887 pipeline_stack.activate_md5(pp_md5);
2822 } 2888 }
2823 } 2889 }
@@ -2852,7 +2918,7 @@ impl::Writer::writeLinearized() @@ -2852,7 +2918,7 @@ impl::Writer::writeLinearized()
2852 2918
2853 // If the user supplied any additional header text, write it here after the linearization 2919 // If the user supplied any additional header text, write it here after the linearization
2854 // parameter dictionary. 2920 // parameter dictionary.
2855 - write(cfg.extra_header_text_); 2921 + write(cfg.extra_header_text());
2856 2922
2857 // Part 3: first page cross reference table and trailer. 2923 // Part 3: first page cross reference table and trailer.
2858 2924
@@ -2987,7 +3053,7 @@ impl::Writer::writeLinearized() @@ -2987,7 +3053,7 @@ impl::Writer::writeLinearized()
2987 write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); 3053 write("startxref\n").write(first_xref_offset).write("\n%%EOF\n");
2988 3054
2989 if (pass == 1) { 3055 if (pass == 1) {
2990 - if (cfg.deterministic_id_) { 3056 + if (cfg.deterministic_id()) {
2991 QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); 3057 QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1);
2992 computeDeterministicIDData(); 3058 computeDeterministicIDData();
2993 pp_md5.pop(); 3059 pp_md5.pop();
@@ -3032,7 +3098,7 @@ impl::Writer::writeLinearized() @@ -3032,7 +3098,7 @@ impl::Writer::writeLinearized()
3032 void 3098 void
3033 impl::Writer::enqueueObjectsStandard() 3099 impl::Writer::enqueueObjectsStandard()
3034 { 3100 {
3035 - if (cfg.preserve_unreferenced_objects_) { 3101 + if (cfg.preserve_unreferenced()) {
3036 for (auto const& oh: qpdf.getAllObjects()) { 3102 for (auto const& oh: qpdf.getAllObjects()) {
3037 enqueue(oh); 3103 enqueue(oh);
3038 } 3104 }
@@ -3113,16 +3179,16 @@ void @@ -3113,16 +3179,16 @@ void
3113 impl::Writer::writeStandard() 3179 impl::Writer::writeStandard()
3114 { 3180 {
3115 auto pp_md5 = pipeline_stack.popper(); 3181 auto pp_md5 = pipeline_stack.popper();
3116 - if (cfg.deterministic_id_) { 3182 + if (cfg.deterministic_id()) {
3117 pipeline_stack.activate_md5(pp_md5); 3183 pipeline_stack.activate_md5(pp_md5);
3118 } 3184 }
3119 3185
3120 // Start writing 3186 // Start writing
3121 3187
3122 writeHeader(); 3188 writeHeader();
3123 - write(cfg.extra_header_text_); 3189 + write(cfg.extra_header_text());
3124 3190
3125 - if (cfg.pclm_) { 3191 + if (cfg.pclm()) {
3126 enqueueObjectsPCLm(); 3192 enqueueObjectsPCLm();
3127 } else { 3193 } else {
3128 enqueueObjectsStandard(); 3194 enqueueObjectsStandard();
@@ -3152,7 +3218,7 @@ impl::Writer::writeStandard() @@ -3152,7 +3218,7 @@ impl::Writer::writeStandard()
3152 } 3218 }
3153 write("startxref\n").write(xref_offset).write("\n%%EOF\n"); 3219 write("startxref\n").write(xref_offset).write("\n%%EOF\n");
3154 3220
3155 - if (cfg.deterministic_id_) { 3221 + if (cfg.deterministic_id()) {
3156 QTC::TC( 3222 QTC::TC(
3157 "qpdf", 3223 "qpdf",
3158 "QPDFWriter standard deterministic ID", 3224 "QPDFWriter standard deterministic ID",
libqpdf/qpdf/QPDFWriter_private.hh
@@ -23,14 +23,252 @@ namespace qpdf @@ -23,14 +23,252 @@ namespace qpdf
23 class Config 23 class Config
24 { 24 {
25 friend class impl::Writer; 25 friend class impl::Writer;
26 - friend class ::QPDFWriter; 26 +
  27 + public:
  28 + bool
  29 + linearize() const
  30 + {
  31 + return linearize_;
  32 + }
  33 +
  34 + Config& linearize(bool val);
  35 +
  36 + std::string const&
  37 + lin_pass1_filename() const
  38 + {
  39 + return lin_pass1_filename_;
  40 + }
  41 +
  42 + Config&
  43 + lin_pass1_filename(std::string const& val)
  44 + {
  45 + lin_pass1_filename_ = val;
  46 + return *this;
  47 + }
  48 +
  49 + bool
  50 + preserve_encryption() const
  51 + {
  52 + return preserve_encryption_;
  53 + }
  54 +
  55 + Config&
  56 + preserve_encryption(bool val)
  57 + {
  58 + preserve_encryption_ = val;
  59 + return *this;
  60 + }
  61 +
  62 + bool
  63 + encrypt_use_aes() const
  64 + {
  65 + return encrypt_use_aes_;
  66 + }
  67 +
  68 + Config&
  69 + encrypt_use_aes(bool val)
  70 + {
  71 + encrypt_use_aes_ = val;
  72 + return *this;
  73 + }
  74 +
  75 + qpdf_stream_decode_level_e
  76 + stream_decode_level() const
  77 + {
  78 + return stream_decode_level_;
  79 + }
  80 +
  81 + Config& stream_decode_level(qpdf_stream_decode_level_e val);
  82 +
  83 + qpdf_object_stream_e
  84 + object_streams() const
  85 + {
  86 + return object_streams_;
  87 + }
  88 +
  89 + Config&
  90 + object_streams(qpdf_object_stream_e val)
  91 + {
  92 + object_streams_ = val;
  93 + return *this;
  94 + }
  95 +
  96 + bool
  97 + compress_streams() const
  98 + {
  99 + return compress_streams_;
  100 + }
  101 +
  102 + Config& compress_streams(bool val);
  103 +
  104 + bool
  105 + direct_stream_lengths() const
  106 + {
  107 + return direct_stream_lengths_;
  108 + }
  109 +
  110 + bool
  111 + newline_before_endstream() const
  112 + {
  113 + return newline_before_endstream_;
  114 + }
  115 +
  116 + Config&
  117 + newline_before_endstream(bool val)
  118 + {
  119 + newline_before_endstream_ = val;
  120 + return *this;
  121 + }
  122 +
  123 + bool
  124 + recompress_flate() const
  125 + {
  126 + return recompress_flate_;
  127 + }
  128 +
  129 + Config&
  130 + recompress_flate(bool val)
  131 + {
  132 + recompress_flate_ = val;
  133 + return *this;
  134 + }
  135 +
  136 + Config& stream_data(qpdf_stream_data_e val);
  137 +
  138 + std::string const&
  139 + forced_pdf_version() const
  140 + {
  141 + return forced_pdf_version_;
  142 + }
  143 +
  144 + Config&
  145 + forced_pdf_version(std::string const& val)
  146 + {
  147 + forced_pdf_version_ = val;
  148 + return *this;
  149 + }
  150 +
  151 + Config&
  152 + forced_pdf_version(std::string const& val, int ext)
  153 + {
  154 + forced_pdf_version_ = val;
  155 + forced_extension_level_ = ext;
  156 + return *this;
  157 + }
  158 +
  159 + int
  160 + forced_extension_level() const
  161 + {
  162 + return forced_extension_level_;
  163 + }
  164 +
  165 + Config&
  166 + forced_extension_level(int val)
  167 + {
  168 + forced_extension_level_ = val;
  169 + return *this;
  170 + }
  171 +
  172 + std::string const&
  173 + extra_header_text()
  174 + {
  175 + return extra_header_text_;
  176 + }
  177 +
  178 + Config& extra_header_text(std::string const& val);
  179 +
  180 + bool
  181 + preserve_unreferenced() const
  182 + {
  183 + return preserve_unreferenced_;
  184 + }
  185 +
  186 + Config&
  187 + preserve_unreferenced(bool val)
  188 + {
  189 + preserve_unreferenced_ = val;
  190 + return *this;
  191 + }
  192 +
  193 + bool
  194 + suppress_original_object_ids() const
  195 + {
  196 + return suppress_original_object_ids_;
  197 + }
  198 +
  199 + Config&
  200 + suppress_original_object_ids(bool val)
  201 + {
  202 + suppress_original_object_ids_ = val;
  203 + return *this;
  204 + }
  205 +
  206 + bool
  207 + qdf() const
  208 + {
  209 + return qdf_;
  210 + }
  211 +
  212 + Config& qdf(bool val);
  213 +
  214 + bool
  215 + normalize_content() const
  216 + {
  217 + return normalize_content_;
  218 + }
  219 +
  220 + Config&
  221 + normalize_content(bool val)
  222 + {
  223 + normalize_content_ = val;
  224 + normalize_content_set_ = true;
  225 + return *this;
  226 + }
  227 +
  228 + bool
  229 + deterministic_id() const
  230 + {
  231 + return deterministic_id_;
  232 + }
  233 +
  234 + Config&
  235 + deterministic_id(bool val)
  236 + {
  237 + deterministic_id_ = val;
  238 + return *this;
  239 + }
  240 +
  241 + bool
  242 + static_id() const
  243 + {
  244 + return static_id_;
  245 + }
  246 +
  247 + Config&
  248 + static_id(bool val)
  249 + {
  250 + static_id_ = val;
  251 + return *this;
  252 + }
  253 +
  254 + bool
  255 + pclm() const
  256 + {
  257 + return pclm_;
  258 + }
  259 +
  260 + Config& pclm(bool val);
  261 +
  262 + private:
  263 + void usage(std::string_view msg) const {};
27 264
28 std::string forced_pdf_version_; 265 std::string forced_pdf_version_;
29 std::string extra_header_text_; 266 std::string extra_header_text_;
30 // For linearization only 267 // For linearization only
31 std::string lin_pass1_filename_; 268 std::string lin_pass1_filename_;
32 269
33 - qpdf_object_stream_e object_stream_mode_{qpdf_o_preserve}; 270 + qpdf_object_stream_e object_streams_{qpdf_o_preserve};
  271 + qpdf_stream_decode_level_e stream_decode_level_{qpdf_dl_generalized};
34 272
35 int forced_extension_level_{0}; 273 int forced_extension_level_{0};
36 274
@@ -38,18 +276,17 @@ namespace qpdf @@ -38,18 +276,17 @@ namespace qpdf
38 bool normalize_content_{false}; 276 bool normalize_content_{false};
39 bool compress_streams_{true}; 277 bool compress_streams_{true};
40 bool compress_streams_set_{false}; 278 bool compress_streams_set_{false};
41 - qpdf_stream_decode_level_e stream_decode_level_{qpdf_dl_generalized};  
42 bool stream_decode_level_set_{false}; 279 bool stream_decode_level_set_{false};
43 bool recompress_flate_{false}; 280 bool recompress_flate_{false};
44 - bool qdf_mode_{false};  
45 - bool preserve_unreferenced_objects_{false}; 281 + bool qdf_{false};
  282 + bool preserve_unreferenced_{false};
46 bool newline_before_endstream_{false}; 283 bool newline_before_endstream_{false};
47 bool deterministic_id_{false}; 284 bool deterministic_id_{false};
48 bool static_id_{false}; 285 bool static_id_{false};
49 bool suppress_original_object_ids_{false}; 286 bool suppress_original_object_ids_{false};
50 bool direct_stream_lengths_{true}; 287 bool direct_stream_lengths_{true};
51 bool preserve_encryption_{true}; 288 bool preserve_encryption_{true};
52 - bool linearized_{false}; 289 + bool linearize_{false};
53 bool pclm_{false}; 290 bool pclm_{false};
54 bool encrypt_use_aes_{false}; 291 bool encrypt_use_aes_{false};
55 }; // class Writer::Config 292 }; // class Writer::Config
qpdf/qpdf.testcov
@@ -46,7 +46,6 @@ QPDFObjectHandle copy stream 1 @@ -46,7 +46,6 @@ QPDFObjectHandle copy stream 1
46 QPDF ignoring XRefStm in trailer 0 46 QPDF ignoring XRefStm in trailer 0
47 SF_FlateLzwDecode PNG filter 0 47 SF_FlateLzwDecode PNG filter 0
48 QPDF xref /Index is array 1 48 QPDF xref /Index is array 1
49 -QPDFWriter encrypt object stream 0  
50 QPDF exclude indirect length 0 49 QPDF exclude indirect length 0
51 QPDF exclude encryption dictionary 0 50 QPDF exclude encryption dictionary 0
52 QPDF_Stream pipeStreamData with null pipeline 0 51 QPDF_Stream pipeStreamData with null pipeline 0