Commit 2ef866db3c00e5b1617cff7b3774bf5addcd4ca1
Committed by
GitHub
Merge pull request #1565 from m-holger/writer
Refactor QPDFWriter configuration
Showing
14 changed files
with
930 additions
and
663 deletions
include/qpdf/QPDFJob.hh
| @@ -490,7 +490,7 @@ class QPDFJob | @@ -490,7 +490,7 @@ class QPDFJob | ||
| 490 | 490 | ||
| 491 | // Output generation | 491 | // Output generation |
| 492 | void doSplitPages(QPDF& pdf); | 492 | void doSplitPages(QPDF& pdf); |
| 493 | - void setWriterOptions(QPDFWriter&); | 493 | + void setWriterOptions(qpdf::Writer&); |
| 494 | void setEncryptionOptions(QPDFWriter&); | 494 | void setEncryptionOptions(QPDFWriter&); |
| 495 | void maybeFixWritePassword(int R, std::string& password); | 495 | void maybeFixWritePassword(int R, std::string& password); |
| 496 | void writeOutfile(QPDF& pdf); | 496 | void writeOutfile(QPDF& pdf); |
include/qpdf/QPDFWriter.hh
| @@ -43,6 +43,11 @@ | @@ -43,6 +43,11 @@ | ||
| 43 | #include <string_view> | 43 | #include <string_view> |
| 44 | #include <vector> | 44 | #include <vector> |
| 45 | 45 | ||
| 46 | +namespace qpdf | ||
| 47 | +{ | ||
| 48 | + class Writer; | ||
| 49 | +} | ||
| 50 | + | ||
| 46 | class QPDF; | 51 | class QPDF; |
| 47 | 52 | ||
| 48 | // This class implements a simple writer for saving QPDF objects to new PDF files. See comments | 53 | // This class implements a simple writer for saving QPDF objects to new PDF files. See comments |
| @@ -440,6 +445,8 @@ class QPDFWriter | @@ -440,6 +445,8 @@ class QPDFWriter | ||
| 440 | class NewObjTable; | 445 | class NewObjTable; |
| 441 | 446 | ||
| 442 | private: | 447 | private: |
| 448 | + friend class qpdf::Writer; | ||
| 449 | + | ||
| 443 | class Members; | 450 | class Members; |
| 444 | 451 | ||
| 445 | std::shared_ptr<Members> m; | 452 | std::shared_ptr<Members> m; |
libqpdf/QPDF.cc
| @@ -27,9 +27,8 @@ | @@ -27,9 +27,8 @@ | ||
| 27 | using namespace qpdf; | 27 | using namespace qpdf; |
| 28 | using namespace std::literals; | 28 | using namespace std::literals; |
| 29 | 29 | ||
| 30 | -using QDoc = QPDF::Doc; | ||
| 31 | -using Common = QDoc::Common; | ||
| 32 | -using Objects = QDoc::Objects; | 30 | +using Common = impl::Doc::Common; |
| 31 | +using Objects = impl::Doc::Objects; | ||
| 33 | using Foreign = Objects::Foreign; | 32 | using Foreign = Objects::Foreign; |
| 34 | using Streams = Objects::Streams; | 33 | using Streams = Objects::Streams; |
| 35 | 34 | ||
| @@ -724,11 +723,11 @@ QPDF::getRoot() | @@ -724,11 +723,11 @@ QPDF::getRoot() | ||
| 724 | std::map<QPDFObjGen, QPDFXRefEntry> | 723 | std::map<QPDFObjGen, QPDFXRefEntry> |
| 725 | QPDF::getXRefTable() | 724 | QPDF::getXRefTable() |
| 726 | { | 725 | { |
| 727 | - return m->objects.getXRefTableInternal(); | 726 | + return m->objects.xref_table(); |
| 728 | } | 727 | } |
| 729 | 728 | ||
| 730 | std::map<QPDFObjGen, QPDFXRefEntry> const& | 729 | std::map<QPDFObjGen, QPDFXRefEntry> const& |
| 731 | -Objects::getXRefTableInternal() | 730 | +Objects::xref_table() |
| 732 | { | 731 | { |
| 733 | if (!m->parsed) { | 732 | if (!m->parsed) { |
| 734 | throw std::logic_error("QPDF::getXRefTable called before parsing."); | 733 | throw std::logic_error("QPDF::getXRefTable called before parsing."); |
libqpdf/QPDFJob.cc
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | #include <qpdf/QPDFPageObjectHelper.hh> | 20 | #include <qpdf/QPDFPageObjectHelper.hh> |
| 21 | #include <qpdf/QPDFSystemError.hh> | 21 | #include <qpdf/QPDFSystemError.hh> |
| 22 | #include <qpdf/QPDFUsage.hh> | 22 | #include <qpdf/QPDFUsage.hh> |
| 23 | -#include <qpdf/QPDFWriter.hh> | 23 | +#include <qpdf/QPDFWriter_private.hh> |
| 24 | #include <qpdf/QPDF_private.hh> | 24 | #include <qpdf/QPDF_private.hh> |
| 25 | #include <qpdf/QTC.hh> | 25 | #include <qpdf/QTC.hh> |
| 26 | #include <qpdf/QUtil.hh> | 26 | #include <qpdf/QUtil.hh> |
| @@ -30,8 +30,7 @@ | @@ -30,8 +30,7 @@ | ||
| 30 | 30 | ||
| 31 | using namespace qpdf; | 31 | using namespace qpdf; |
| 32 | 32 | ||
| 33 | -using QDoc = QPDF::Doc; | ||
| 34 | -using Pages = QDoc::Pages; | 33 | +using Pages = impl::Doc::Pages; |
| 35 | 34 | ||
| 36 | namespace | 35 | namespace |
| 37 | { | 36 | { |
| @@ -477,7 +476,7 @@ QPDFJob::writeQPDF(QPDF& pdf) | @@ -477,7 +476,7 @@ QPDFJob::writeQPDF(QPDF& pdf) | ||
| 477 | if (!pdf.getWarnings().empty()) { | 476 | if (!pdf.getWarnings().empty()) { |
| 478 | m->warnings = true; | 477 | m->warnings = true; |
| 479 | } | 478 | } |
| 480 | - if (m->warnings && !m->qcf.suppress_warnings()) { | 479 | + if (m->warnings && !m->d_cfg.suppress_warnings()) { |
| 481 | if (createsOutput()) { | 480 | if (createsOutput()) { |
| 482 | *m->log->getWarn() | 481 | *m->log->getWarn() |
| 483 | << m->message_prefix | 482 | << m->message_prefix |
| @@ -745,7 +744,8 @@ QPDFJob::doCheck(QPDF& pdf) | @@ -745,7 +744,8 @@ QPDFJob::doCheck(QPDF& pdf) | ||
| 745 | 744 | ||
| 746 | // Write the file to nowhere, uncompressing streams. This causes full file traversal and | 745 | // Write the file to nowhere, uncompressing streams. This causes full file traversal and |
| 747 | // decoding of all streams we can decode. | 746 | // decoding of all streams we can decode. |
| 748 | - QPDFWriter w(pdf); | 747 | + Writer::Config cfg; |
| 748 | + Writer w(pdf, cfg); | ||
| 749 | Pl_Discard discard; | 749 | Pl_Discard discard; |
| 750 | w.setOutputPipeline(&discard); | 750 | w.setOutputPipeline(&discard); |
| 751 | w.setDecodeLevel(qpdf_dl_all); | 751 | w.setDecodeLevel(qpdf_dl_all); |
| @@ -804,7 +804,7 @@ QPDFJob::doShowObj(QPDF& pdf) | @@ -804,7 +804,7 @@ QPDFJob::doShowObj(QPDF& pdf) | ||
| 804 | m->log->saveToStandardOutput(true); | 804 | m->log->saveToStandardOutput(true); |
| 805 | obj.pipeStreamData( | 805 | obj.pipeStreamData( |
| 806 | m->log->getSave().get(), | 806 | m->log->getSave().get(), |
| 807 | - (filter && m->normalize) ? qpdf_ef_normalize : 0, | 807 | + filter && m->w_cfg.normalize_content() ? qpdf_ef_normalize : 0, |
| 808 | filter ? qpdf_dl_all : qpdf_dl_none); | 808 | filter ? qpdf_dl_all : qpdf_dl_none); |
| 809 | } | 809 | } |
| 810 | } else { | 810 | } else { |
| @@ -974,7 +974,7 @@ QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf) | @@ -974,7 +974,7 @@ QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf) | ||
| 974 | p, | 974 | p, |
| 975 | false, | 975 | false, |
| 976 | first, | 976 | first, |
| 977 | - m->decode_level, | 977 | + m->w_cfg.decode_level(), |
| 978 | m->json_stream_data, | 978 | m->json_stream_data, |
| 979 | m->json_stream_prefix, | 979 | m->json_stream_prefix, |
| 980 | json_objects); | 980 | json_objects); |
| @@ -1052,7 +1052,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | @@ -1052,7 +1052,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1052 | j_image.addDictionaryMember("decodeparms", dp_array.getJSON(m->json_version)); | 1052 | j_image.addDictionaryMember("decodeparms", dp_array.getJSON(m->json_version)); |
| 1053 | j_image.addDictionaryMember( | 1053 | j_image.addDictionaryMember( |
| 1054 | "filterable", | 1054 | "filterable", |
| 1055 | - JSON::makeBool(image.pipeStreamData(nullptr, 0, m->decode_level, true))); | 1055 | + JSON::makeBool(image.pipeStreamData(nullptr, 0, m->w_cfg.decode_level(), true))); |
| 1056 | } | 1056 | } |
| 1057 | j_page.addDictionaryMember("images", j_images); | 1057 | j_page.addDictionaryMember("images", j_images); |
| 1058 | JSON j_contents = j_page.addDictionaryMember("contents", JSON::makeArray()); | 1058 | JSON j_contents = j_page.addDictionaryMember("contents", JSON::makeArray()); |
| @@ -1569,7 +1569,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p) | @@ -1569,7 +1569,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p) | ||
| 1569 | JSON::writeDictionaryItem(p, first, "version", JSON::makeInt(m->json_version), 1); | 1569 | JSON::writeDictionaryItem(p, first, "version", JSON::makeInt(m->json_version), 1); |
| 1570 | JSON j_params = JSON::makeDictionary(); | 1570 | JSON j_params = JSON::makeDictionary(); |
| 1571 | std::string decode_level_str; | 1571 | std::string decode_level_str; |
| 1572 | - switch (m->decode_level) { | 1572 | + switch (m->w_cfg.decode_level()) { |
| 1573 | case qpdf_dl_none: | 1573 | case qpdf_dl_none: |
| 1574 | decode_level_str = "none"; | 1574 | decode_level_str = "none"; |
| 1575 | break; | 1575 | break; |
| @@ -1709,7 +1709,7 @@ QPDFJob::doProcessOnce( | @@ -1709,7 +1709,7 @@ QPDFJob::doProcessOnce( | ||
| 1709 | bool main_input) | 1709 | bool main_input) |
| 1710 | { | 1710 | { |
| 1711 | pdf = std::make_unique<QPDF>(); | 1711 | pdf = std::make_unique<QPDF>(); |
| 1712 | - pdf->doc().config(m->qcf.log(m->log)); | 1712 | + pdf->doc().config(m->d_cfg.log(m->log)); |
| 1713 | if (empty) { | 1713 | if (empty) { |
| 1714 | pdf->emptyPDF(); | 1714 | pdf->emptyPDF(); |
| 1715 | } else if (main_input && m->json_input) { | 1715 | } else if (main_input && m->json_input) { |
| @@ -1739,7 +1739,7 @@ QPDFJob::doProcess( | @@ -1739,7 +1739,7 @@ QPDFJob::doProcess( | ||
| 1739 | // was incorrectly encoded, there's a good chance we'd succeed here. | 1739 | // was incorrectly encoded, there's a good chance we'd succeed here. |
| 1740 | 1740 | ||
| 1741 | std::string ptemp; | 1741 | std::string ptemp; |
| 1742 | - if (password && !m->qcf.password_is_hex_key()) { | 1742 | + if (password && !m->d_cfg.password_is_hex_key()) { |
| 1743 | if (m->password_mode == QPDFJob::pm_hex_bytes) { | 1743 | if (m->password_mode == QPDFJob::pm_hex_bytes) { |
| 1744 | // Special case: handle --password-mode=hex-bytes for input password as well as output | 1744 | // Special case: handle --password-mode=hex-bytes for input password as well as output |
| 1745 | // password | 1745 | // password |
| @@ -1747,7 +1747,7 @@ QPDFJob::doProcess( | @@ -1747,7 +1747,7 @@ QPDFJob::doProcess( | ||
| 1747 | password = ptemp.c_str(); | 1747 | password = ptemp.c_str(); |
| 1748 | } | 1748 | } |
| 1749 | } | 1749 | } |
| 1750 | - if (!password || empty || m->qcf.password_is_hex_key() || m->suppress_password_recovery) { | 1750 | + if (!password || empty || m->d_cfg.password_is_hex_key() || m->suppress_password_recovery) { |
| 1751 | // There is no password, or we're not doing recovery, so just do the normal processing with | 1751 | // There is no password, or we're not doing recovery, so just do the normal processing with |
| 1752 | // the supplied password. | 1752 | // the supplied password. |
| 1753 | doProcessOnce(pdf, fn, password, empty, used_for_input, main_input); | 1753 | doProcessOnce(pdf, fn, password, empty, used_for_input, main_input); |
| @@ -2879,50 +2879,17 @@ parse_version(std::string const& full_version_string, std::string& version, int& | @@ -2879,50 +2879,17 @@ parse_version(std::string const& full_version_string, std::string& version, int& | ||
| 2879 | } | 2879 | } |
| 2880 | 2880 | ||
| 2881 | void | 2881 | void |
| 2882 | -QPDFJob::setWriterOptions(QPDFWriter& w) | 2882 | +QPDFJob::setWriterOptions(Writer& w) |
| 2883 | { | 2883 | { |
| 2884 | if (m->compression_level >= 0) { | 2884 | if (m->compression_level >= 0) { |
| 2885 | Pl_Flate::setCompressionLevel(m->compression_level); | 2885 | Pl_Flate::setCompressionLevel(m->compression_level); |
| 2886 | } | 2886 | } |
| 2887 | - if (m->qdf_mode) { | ||
| 2888 | - w.setQDFMode(true); | ||
| 2889 | - } | ||
| 2890 | - if (m->preserve_unreferenced_objects) { | ||
| 2891 | - w.setPreserveUnreferencedObjects(true); | ||
| 2892 | - } | ||
| 2893 | - if (m->newline_before_endstream) { | ||
| 2894 | - w.setNewlineBeforeEndstream(true); | ||
| 2895 | - } | ||
| 2896 | - if (m->normalize_set) { | ||
| 2897 | - w.setContentNormalization(m->normalize); | ||
| 2898 | - } | ||
| 2899 | - if (m->stream_data_set) { | ||
| 2900 | - w.setStreamDataMode(m->stream_data_mode); | ||
| 2901 | - } | ||
| 2902 | - if (m->compress_streams_set) { | ||
| 2903 | - w.setCompressStreams(m->compress_streams); | ||
| 2904 | - } | ||
| 2905 | - if (m->recompress_flate_set) { | ||
| 2906 | - w.setRecompressFlate(m->recompress_flate); | ||
| 2907 | - } | ||
| 2908 | - if (m->decode_level_set) { | ||
| 2909 | - w.setDecodeLevel(m->decode_level); | ||
| 2910 | - } | ||
| 2911 | if (m->decrypt) { | 2887 | if (m->decrypt) { |
| 2912 | w.setPreserveEncryption(false); | 2888 | w.setPreserveEncryption(false); |
| 2913 | } | 2889 | } |
| 2914 | - if (m->deterministic_id) { | ||
| 2915 | - w.setDeterministicID(true); | ||
| 2916 | - } | ||
| 2917 | - if (m->static_id) { | ||
| 2918 | - w.setStaticID(true); | ||
| 2919 | - } | ||
| 2920 | if (m->static_aes_iv) { | 2890 | if (m->static_aes_iv) { |
| 2921 | w.setStaticAesIV(true); | 2891 | w.setStaticAesIV(true); |
| 2922 | } | 2892 | } |
| 2923 | - if (m->suppress_original_object_id) { | ||
| 2924 | - w.setSuppressOriginalObjectIDs(true); | ||
| 2925 | - } | ||
| 2926 | if (m->copy_encryption) { | 2893 | if (m->copy_encryption) { |
| 2927 | std::unique_ptr<QPDF> encryption_pdf; | 2894 | std::unique_ptr<QPDF> encryption_pdf; |
| 2928 | processFile( | 2895 | processFile( |
| @@ -2936,15 +2903,6 @@ QPDFJob::setWriterOptions(QPDFWriter& w) | @@ -2936,15 +2903,6 @@ QPDFJob::setWriterOptions(QPDFWriter& w) | ||
| 2936 | if (m->encrypt) { | 2903 | if (m->encrypt) { |
| 2937 | setEncryptionOptions(w); | 2904 | setEncryptionOptions(w); |
| 2938 | } | 2905 | } |
| 2939 | - if (m->linearize) { | ||
| 2940 | - w.setLinearization(true); | ||
| 2941 | - } | ||
| 2942 | - if (!m->linearize_pass1.empty()) { | ||
| 2943 | - w.setLinearizationPass1Filename(m->linearize_pass1); | ||
| 2944 | - } | ||
| 2945 | - if (m->object_stream_set) { | ||
| 2946 | - w.setObjectStreamMode(m->object_stream_mode); | ||
| 2947 | - } | ||
| 2948 | w.setMinimumPDFVersion(m->max_input_version); | 2906 | w.setMinimumPDFVersion(m->max_input_version); |
| 2949 | if (!m->min_version.empty()) { | 2907 | if (!m->min_version.empty()) { |
| 2950 | std::string version; | 2908 | std::string version; |
| @@ -2961,15 +2919,13 @@ QPDFJob::setWriterOptions(QPDFWriter& w) | @@ -2961,15 +2919,13 @@ QPDFJob::setWriterOptions(QPDFWriter& w) | ||
| 2961 | if (m->progress) { | 2919 | if (m->progress) { |
| 2962 | if (m->progress_handler) { | 2920 | if (m->progress_handler) { |
| 2963 | w.registerProgressReporter( | 2921 | w.registerProgressReporter( |
| 2964 | - std::shared_ptr<QPDFWriter::ProgressReporter>( | ||
| 2965 | - new QPDFWriter::FunctionProgressReporter(m->progress_handler))); | 2922 | + std::make_shared<QPDFWriter::FunctionProgressReporter>(m->progress_handler)); |
| 2966 | } else { | 2923 | } else { |
| 2967 | char const* outfilename = | 2924 | char const* outfilename = |
| 2968 | !m->outfilename.empty() ? m->outfilename.data() : "standard output"; | 2925 | !m->outfilename.empty() ? m->outfilename.data() : "standard output"; |
| 2969 | w.registerProgressReporter( | 2926 | w.registerProgressReporter( |
| 2970 | - std::shared_ptr<QPDFWriter::ProgressReporter>( | ||
| 2971 | - // line-break | ||
| 2972 | - new ProgressReporter(*m->log->getInfo(), m->message_prefix, outfilename))); | 2927 | + std::make_shared<ProgressReporter>( |
| 2928 | + *m->log->getInfo(), m->message_prefix, outfilename)); | ||
| 2973 | } | 2929 | } |
| 2974 | } | 2930 | } |
| 2975 | } | 2931 | } |
| @@ -3014,7 +2970,7 @@ QPDFJob::doSplitPages(QPDF& pdf) | @@ -3014,7 +2970,7 @@ QPDFJob::doSplitPages(QPDF& pdf) | ||
| 3014 | last = num_pages; | 2970 | last = num_pages; |
| 3015 | } | 2971 | } |
| 3016 | QPDF outpdf; | 2972 | QPDF outpdf; |
| 3017 | - outpdf.doc().config(m->qcf); | 2973 | + outpdf.doc().config(m->d_cfg); |
| 3018 | outpdf.emptyPDF(); | 2974 | outpdf.emptyPDF(); |
| 3019 | QPDFAcroFormDocumentHelper* out_afdh = | 2975 | QPDFAcroFormDocumentHelper* out_afdh = |
| 3020 | afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr; | 2976 | afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr; |
| @@ -3052,7 +3008,8 @@ QPDFJob::doSplitPages(QPDF& pdf) | @@ -3052,7 +3008,8 @@ QPDFJob::doSplitPages(QPDF& pdf) | ||
| 3052 | if (QUtil::same_file(m->infile_nm(), outfile.data())) { | 3008 | if (QUtil::same_file(m->infile_nm(), outfile.data())) { |
| 3053 | throw std::runtime_error("split pages would overwrite input file with " + outfile); | 3009 | throw std::runtime_error("split pages would overwrite input file with " + outfile); |
| 3054 | } | 3010 | } |
| 3055 | - QPDFWriter w(outpdf, outfile.c_str()); | 3011 | + Writer w(outpdf, m->w_cfg); |
| 3012 | + w.setOutputFilename(outfile.data()); | ||
| 3056 | setWriterOptions(w); | 3013 | setWriterOptions(w); |
| 3057 | w.write(); | 3014 | w.write(); |
| 3058 | doIfVerbose([&](Pipeline& v, std::string const& prefix) { | 3015 | doIfVerbose([&](Pipeline& v, std::string const& prefix) { |
| @@ -3077,9 +3034,8 @@ QPDFJob::writeOutfile(QPDF& pdf) | @@ -3077,9 +3034,8 @@ QPDFJob::writeOutfile(QPDF& pdf) | ||
| 3077 | if (m->json_version) { | 3034 | if (m->json_version) { |
| 3078 | writeJSON(pdf); | 3035 | writeJSON(pdf); |
| 3079 | } else { | 3036 | } else { |
| 3080 | - // QPDFWriter must have block scope so the output file will be closed after write() | ||
| 3081 | - // finishes. | ||
| 3082 | - QPDFWriter w(pdf); | 3037 | + // Writer must have block scope so the output file will be closed after write() finishes. |
| 3038 | + Writer w(pdf, m->w_cfg); | ||
| 3083 | if (!m->outfilename.empty()) { | 3039 | if (!m->outfilename.empty()) { |
| 3084 | w.setOutputFilename(m->outfilename.data()); | 3040 | w.setOutputFilename(m->outfilename.data()); |
| 3085 | } else { | 3041 | } else { |
libqpdf/QPDFJob_config.cc
| @@ -68,7 +68,7 @@ QPDFJob::Config* | @@ -68,7 +68,7 @@ QPDFJob::Config* | ||
| 68 | QPDFJob::Config::check() | 68 | QPDFJob::Config::check() |
| 69 | { | 69 | { |
| 70 | o.m->check = true; | 70 | o.m->check = true; |
| 71 | - o.m->qcf.check_mode(true); | 71 | + o.m->d_cfg.check_mode(true); |
| 72 | o.m->require_outfile = false; | 72 | o.m->require_outfile = false; |
| 73 | return this; | 73 | return this; |
| 74 | } | 74 | } |
| @@ -124,8 +124,7 @@ QPDFJob::Config::collate(std::string const& parameter) | @@ -124,8 +124,7 @@ QPDFJob::Config::collate(std::string const& parameter) | ||
| 124 | QPDFJob::Config* | 124 | QPDFJob::Config* |
| 125 | QPDFJob::Config::compressStreams(std::string const& parameter) | 125 | QPDFJob::Config::compressStreams(std::string const& parameter) |
| 126 | { | 126 | { |
| 127 | - o.m->compress_streams_set = true; | ||
| 128 | - o.m->compress_streams = (parameter == "y"); | 127 | + o.m->w_cfg.compress_streams(parameter == "y"); |
| 129 | return this; | 128 | return this; |
| 130 | } | 129 | } |
| 131 | 130 | ||
| @@ -146,7 +145,7 @@ QPDFJob::Config::jpegQuality(std::string const& parameter) | @@ -146,7 +145,7 @@ QPDFJob::Config::jpegQuality(std::string const& parameter) | ||
| 146 | QPDFJob::Config* | 145 | QPDFJob::Config* |
| 147 | QPDFJob::Config::copyEncryption(std::string const& parameter) | 146 | QPDFJob::Config::copyEncryption(std::string const& parameter) |
| 148 | { | 147 | { |
| 149 | - if (o.m->deterministic_id) { | 148 | + if (o.m->w_cfg.deterministic_id()) { |
| 150 | usage("the deterministic-id option is incompatible with encrypted output files"); | 149 | usage("the deterministic-id option is incompatible with encrypted output files"); |
| 151 | } | 150 | } |
| 152 | o.m->inputs.encryption_file = parameter; | 151 | o.m->inputs.encryption_file = parameter; |
| @@ -171,7 +170,7 @@ QPDFJob::Config::deterministicId() | @@ -171,7 +170,7 @@ QPDFJob::Config::deterministicId() | ||
| 171 | if (o.m->encrypt || o.m->copy_encryption) { | 170 | if (o.m->encrypt || o.m->copy_encryption) { |
| 172 | usage("the deterministic-id option is incompatible with encrypted output files"); | 171 | usage("the deterministic-id option is incompatible with encrypted output files"); |
| 173 | } | 172 | } |
| 174 | - o.m->deterministic_id = true; | 173 | + o.m->w_cfg.deterministic_id(true); |
| 175 | return this; | 174 | return this; |
| 176 | } | 175 | } |
| 177 | 176 | ||
| @@ -234,7 +233,7 @@ QPDFJob::Config::generateAppearances() | @@ -234,7 +233,7 @@ QPDFJob::Config::generateAppearances() | ||
| 234 | QPDFJob::Config* | 233 | QPDFJob::Config* |
| 235 | QPDFJob::Config::ignoreXrefStreams() | 234 | QPDFJob::Config::ignoreXrefStreams() |
| 236 | { | 235 | { |
| 237 | - o.m->qcf.ignore_xref_streams(true); | 236 | + o.m->d_cfg.ignore_xref_streams(true); |
| 238 | return this; | 237 | return this; |
| 239 | } | 238 | } |
| 240 | 239 | ||
| @@ -327,9 +326,7 @@ QPDFJob::Config::jsonOutput(std::string const& parameter) | @@ -327,9 +326,7 @@ QPDFJob::Config::jsonOutput(std::string const& parameter) | ||
| 327 | // No need to set json_stream_data_set -- that indicates explicit use of --json-stream-data. | 326 | // No need to set json_stream_data_set -- that indicates explicit use of --json-stream-data. |
| 328 | o.m->json_stream_data = qpdf_sj_inline; | 327 | o.m->json_stream_data = qpdf_sj_inline; |
| 329 | } | 328 | } |
| 330 | - if (!o.m->decode_level_set) { | ||
| 331 | - o.m->decode_level = qpdf_dl_none; | ||
| 332 | - } | 329 | + o.m->w_cfg.default_decode_level(qpdf_dl_none); |
| 333 | o.m->json_keys.insert("qpdf"); | 330 | o.m->json_keys.insert("qpdf"); |
| 334 | return this; | 331 | return this; |
| 335 | } | 332 | } |
| @@ -373,14 +370,14 @@ QPDFJob::Config::keepInlineImages() | @@ -373,14 +370,14 @@ QPDFJob::Config::keepInlineImages() | ||
| 373 | QPDFJob::Config* | 370 | QPDFJob::Config* |
| 374 | QPDFJob::Config::linearize() | 371 | QPDFJob::Config::linearize() |
| 375 | { | 372 | { |
| 376 | - o.m->linearize = true; | 373 | + o.m->w_cfg.linearize(true); |
| 377 | return this; | 374 | return this; |
| 378 | } | 375 | } |
| 379 | 376 | ||
| 380 | QPDFJob::Config* | 377 | QPDFJob::Config* |
| 381 | QPDFJob::Config::linearizePass1(std::string const& parameter) | 378 | QPDFJob::Config::linearizePass1(std::string const& parameter) |
| 382 | { | 379 | { |
| 383 | - o.m->linearize_pass1 = parameter; | 380 | + o.m->w_cfg.linearize_pass1(parameter); |
| 384 | return this; | 381 | return this; |
| 385 | } | 382 | } |
| 386 | 383 | ||
| @@ -402,29 +399,28 @@ QPDFJob::Config::minVersion(std::string const& parameter) | @@ -402,29 +399,28 @@ QPDFJob::Config::minVersion(std::string const& parameter) | ||
| 402 | QPDFJob::Config* | 399 | QPDFJob::Config* |
| 403 | QPDFJob::Config::newlineBeforeEndstream() | 400 | QPDFJob::Config::newlineBeforeEndstream() |
| 404 | { | 401 | { |
| 405 | - o.m->newline_before_endstream = true; | 402 | + o.m->w_cfg.newline_before_endstream(true); |
| 406 | return this; | 403 | return this; |
| 407 | } | 404 | } |
| 408 | 405 | ||
| 409 | QPDFJob::Config* | 406 | QPDFJob::Config* |
| 410 | QPDFJob::Config::noOriginalObjectIds() | 407 | QPDFJob::Config::noOriginalObjectIds() |
| 411 | { | 408 | { |
| 412 | - o.m->suppress_original_object_id = true; | 409 | + o.m->w_cfg.no_original_object_ids(true); |
| 413 | return this; | 410 | return this; |
| 414 | } | 411 | } |
| 415 | 412 | ||
| 416 | QPDFJob::Config* | 413 | QPDFJob::Config* |
| 417 | QPDFJob::Config::noWarn() | 414 | QPDFJob::Config::noWarn() |
| 418 | { | 415 | { |
| 419 | - o.m->qcf.suppress_warnings(true); | 416 | + o.m->d_cfg.suppress_warnings(true); |
| 420 | return this; | 417 | return this; |
| 421 | } | 418 | } |
| 422 | 419 | ||
| 423 | QPDFJob::Config* | 420 | QPDFJob::Config* |
| 424 | QPDFJob::Config::normalizeContent(std::string const& parameter) | 421 | QPDFJob::Config::normalizeContent(std::string const& parameter) |
| 425 | { | 422 | { |
| 426 | - o.m->normalize_set = true; | ||
| 427 | - o.m->normalize = (parameter == "y"); | 423 | + o.m->w_cfg.normalize_content(parameter == "y"); |
| 428 | return this; | 424 | return this; |
| 429 | } | 425 | } |
| 430 | 426 | ||
| @@ -466,14 +462,14 @@ QPDFJob::Config::password(std::string const& parameter) | @@ -466,14 +462,14 @@ QPDFJob::Config::password(std::string const& parameter) | ||
| 466 | QPDFJob::Config* | 462 | QPDFJob::Config* |
| 467 | QPDFJob::Config::passwordIsHexKey() | 463 | QPDFJob::Config::passwordIsHexKey() |
| 468 | { | 464 | { |
| 469 | - o.m->qcf.password_is_hex_key(true); | 465 | + o.m->d_cfg.password_is_hex_key(true); |
| 470 | return this; | 466 | return this; |
| 471 | } | 467 | } |
| 472 | 468 | ||
| 473 | QPDFJob::Config* | 469 | QPDFJob::Config* |
| 474 | QPDFJob::Config::preserveUnreferenced() | 470 | QPDFJob::Config::preserveUnreferenced() |
| 475 | { | 471 | { |
| 476 | - o.m->preserve_unreferenced_objects = true; | 472 | + o.m->w_cfg.preserve_unreferenced(true); |
| 477 | return this; | 473 | return this; |
| 478 | } | 474 | } |
| 479 | 475 | ||
| @@ -494,7 +490,7 @@ QPDFJob::Config::progress() | @@ -494,7 +490,7 @@ QPDFJob::Config::progress() | ||
| 494 | QPDFJob::Config* | 490 | QPDFJob::Config* |
| 495 | QPDFJob::Config::qdf() | 491 | QPDFJob::Config::qdf() |
| 496 | { | 492 | { |
| 497 | - o.m->qdf_mode = true; | 493 | + o.m->w_cfg.qdf(true); |
| 498 | return this; | 494 | return this; |
| 499 | } | 495 | } |
| 500 | 496 | ||
| @@ -508,8 +504,7 @@ QPDFJob::Config::rawStreamData() | @@ -508,8 +504,7 @@ QPDFJob::Config::rawStreamData() | ||
| 508 | QPDFJob::Config* | 504 | QPDFJob::Config* |
| 509 | QPDFJob::Config::recompressFlate() | 505 | QPDFJob::Config::recompressFlate() |
| 510 | { | 506 | { |
| 511 | - o.m->recompress_flate_set = true; | ||
| 512 | - o.m->recompress_flate = true; | 507 | + o.m->w_cfg.recompress_flate(true); |
| 513 | return this; | 508 | return this; |
| 514 | } | 509 | } |
| 515 | 510 | ||
| @@ -649,7 +644,7 @@ QPDFJob::Config::staticAesIv() | @@ -649,7 +644,7 @@ QPDFJob::Config::staticAesIv() | ||
| 649 | QPDFJob::Config* | 644 | QPDFJob::Config* |
| 650 | QPDFJob::Config::staticId() | 645 | QPDFJob::Config::staticId() |
| 651 | { | 646 | { |
| 652 | - o.m->static_id = true; | 647 | + o.m->w_cfg.static_id(true); |
| 653 | return this; | 648 | return this; |
| 654 | } | 649 | } |
| 655 | 650 | ||
| @@ -663,7 +658,7 @@ QPDFJob::Config::suppressPasswordRecovery() | @@ -663,7 +658,7 @@ QPDFJob::Config::suppressPasswordRecovery() | ||
| 663 | QPDFJob::Config* | 658 | QPDFJob::Config* |
| 664 | QPDFJob::Config::suppressRecovery() | 659 | QPDFJob::Config::suppressRecovery() |
| 665 | { | 660 | { |
| 666 | - o.m->qcf.surpress_recovery(true); | 661 | + o.m->d_cfg.surpress_recovery(true); |
| 667 | return this; | 662 | return this; |
| 668 | } | 663 | } |
| 669 | 664 | ||
| @@ -731,13 +726,12 @@ QPDFJob::Config::passwordMode(std::string const& parameter) | @@ -731,13 +726,12 @@ QPDFJob::Config::passwordMode(std::string const& parameter) | ||
| 731 | QPDFJob::Config* | 726 | QPDFJob::Config* |
| 732 | QPDFJob::Config::streamData(std::string const& parameter) | 727 | QPDFJob::Config::streamData(std::string const& parameter) |
| 733 | { | 728 | { |
| 734 | - o.m->stream_data_set = true; | ||
| 735 | if (parameter == "compress") { | 729 | if (parameter == "compress") { |
| 736 | - o.m->stream_data_mode = qpdf_s_compress; | 730 | + o.m->w_cfg.stream_data(qpdf_s_compress); |
| 737 | } else if (parameter == "preserve") { | 731 | } else if (parameter == "preserve") { |
| 738 | - o.m->stream_data_mode = qpdf_s_preserve; | 732 | + o.m->w_cfg.stream_data(qpdf_s_preserve); |
| 739 | } else if (parameter == "uncompress") { | 733 | } else if (parameter == "uncompress") { |
| 740 | - o.m->stream_data_mode = qpdf_s_uncompress; | 734 | + o.m->w_cfg.stream_data(qpdf_s_uncompress); |
| 741 | } else { | 735 | } else { |
| 742 | usage("invalid stream-data option"); | 736 | usage("invalid stream-data option"); |
| 743 | } | 737 | } |
| @@ -747,15 +741,14 @@ QPDFJob::Config::streamData(std::string const& parameter) | @@ -747,15 +741,14 @@ QPDFJob::Config::streamData(std::string const& parameter) | ||
| 747 | QPDFJob::Config* | 741 | QPDFJob::Config* |
| 748 | QPDFJob::Config::decodeLevel(std::string const& parameter) | 742 | QPDFJob::Config::decodeLevel(std::string const& parameter) |
| 749 | { | 743 | { |
| 750 | - o.m->decode_level_set = true; | ||
| 751 | if (parameter == "none") { | 744 | if (parameter == "none") { |
| 752 | - o.m->decode_level = qpdf_dl_none; | 745 | + o.m->w_cfg.decode_level(qpdf_dl_none); |
| 753 | } else if (parameter == "generalized") { | 746 | } else if (parameter == "generalized") { |
| 754 | - o.m->decode_level = qpdf_dl_generalized; | 747 | + o.m->w_cfg.decode_level(qpdf_dl_generalized); |
| 755 | } else if (parameter == "specialized") { | 748 | } else if (parameter == "specialized") { |
| 756 | - o.m->decode_level = qpdf_dl_specialized; | 749 | + o.m->w_cfg.decode_level(qpdf_dl_specialized); |
| 757 | } else if (parameter == "all") { | 750 | } else if (parameter == "all") { |
| 758 | - o.m->decode_level = qpdf_dl_all; | 751 | + o.m->w_cfg.decode_level(qpdf_dl_all); |
| 759 | } else { | 752 | } else { |
| 760 | usage("invalid option"); | 753 | usage("invalid option"); |
| 761 | } | 754 | } |
| @@ -765,13 +758,12 @@ QPDFJob::Config::decodeLevel(std::string const& parameter) | @@ -765,13 +758,12 @@ QPDFJob::Config::decodeLevel(std::string const& parameter) | ||
| 765 | QPDFJob::Config* | 758 | QPDFJob::Config* |
| 766 | QPDFJob::Config::objectStreams(std::string const& parameter) | 759 | QPDFJob::Config::objectStreams(std::string const& parameter) |
| 767 | { | 760 | { |
| 768 | - o.m->object_stream_set = true; | ||
| 769 | if (parameter == "disable") { | 761 | if (parameter == "disable") { |
| 770 | - o.m->object_stream_mode = qpdf_o_disable; | 762 | + o.m->w_cfg.object_streams(qpdf_o_disable); |
| 771 | } else if (parameter == "preserve") { | 763 | } else if (parameter == "preserve") { |
| 772 | - o.m->object_stream_mode = qpdf_o_preserve; | 764 | + o.m->w_cfg.object_streams(qpdf_o_preserve); |
| 773 | } else if (parameter == "generate") { | 765 | } else if (parameter == "generate") { |
| 774 | - o.m->object_stream_mode = qpdf_o_generate; | 766 | + o.m->w_cfg.object_streams(qpdf_o_generate); |
| 775 | } else { | 767 | } else { |
| 776 | usage("invalid object stream mode"); | 768 | usage("invalid object stream mode"); |
| 777 | } | 769 | } |
| @@ -1111,7 +1103,7 @@ std::shared_ptr<QPDFJob::EncConfig> | @@ -1111,7 +1103,7 @@ std::shared_ptr<QPDFJob::EncConfig> | ||
| 1111 | QPDFJob::Config::encrypt( | 1103 | QPDFJob::Config::encrypt( |
| 1112 | int keylen, std::string const& user_password, std::string const& owner_password) | 1104 | int keylen, std::string const& user_password, std::string const& owner_password) |
| 1113 | { | 1105 | { |
| 1114 | - if (o.m->deterministic_id) { | 1106 | + if (o.m->w_cfg.deterministic_id()) { |
| 1115 | usage("the deterministic-id option is incompatible with encrypted output files"); | 1107 | usage("the deterministic-id option is incompatible with encrypted output files"); |
| 1116 | } | 1108 | } |
| 1117 | o.m->keylen = keylen; | 1109 | o.m->keylen = keylen; |
libqpdf/QPDFWriter.cc
| @@ -27,8 +27,8 @@ | @@ -27,8 +27,8 @@ | ||
| 27 | using namespace std::literals; | 27 | using namespace std::literals; |
| 28 | using namespace qpdf; | 28 | using namespace qpdf; |
| 29 | 29 | ||
| 30 | -using QDoc = QPDF::Doc; | ||
| 31 | -using Encryption = QDoc::Encryption; | 30 | +using Encryption = impl::Doc::Encryption; |
| 31 | +using Config = Writer::Config; | ||
| 32 | 32 | ||
| 33 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) | 33 | QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) |
| 34 | { | 34 | { |
| @@ -262,300 +262,231 @@ Pl_stack::Popper::pop() | @@ -262,300 +262,231 @@ Pl_stack::Popper::pop() | ||
| 262 | stack = nullptr; | 262 | stack = nullptr; |
| 263 | } | 263 | } |
| 264 | 264 | ||
| 265 | -// Writer class is restricted to QPDFWriter so that only it can call certain methods. | ||
| 266 | -class QPDF::Doc::Writer: QPDF::Doc::Common | 265 | +namespace qpdf::impl |
| 267 | { | 266 | { |
| 268 | - friend class QPDFWriter; | ||
| 269 | - Writer(QPDF& qpdf) : | ||
| 270 | - Common(qpdf, qpdf.doc().m), | ||
| 271 | - lin(m->lin), | ||
| 272 | - objects(m->objects) | ||
| 273 | - { | ||
| 274 | - } | ||
| 275 | - | ||
| 276 | - protected: | ||
| 277 | - void | ||
| 278 | - optimize( | ||
| 279 | - QPDFWriter::ObjTable const& obj, | ||
| 280 | - std::function<int(QPDFObjectHandle&)> skip_stream_parameters) | ||
| 281 | - { | ||
| 282 | - lin.optimize(obj, skip_stream_parameters); | ||
| 283 | - } | ||
| 284 | - | ||
| 285 | - void | ||
| 286 | - getLinearizedParts( | ||
| 287 | - QPDFWriter::ObjTable const& obj, | ||
| 288 | - std::vector<QPDFObjectHandle>& part4, | ||
| 289 | - std::vector<QPDFObjectHandle>& part6, | ||
| 290 | - std::vector<QPDFObjectHandle>& part7, | ||
| 291 | - std::vector<QPDFObjectHandle>& part8, | ||
| 292 | - std::vector<QPDFObjectHandle>& part9) | ||
| 293 | - { | ||
| 294 | - lin.getLinearizedParts(obj, part4, part6, part7, part8, part9); | ||
| 295 | - } | ||
| 296 | - | ||
| 297 | - void | ||
| 298 | - generateHintStream( | ||
| 299 | - QPDFWriter::NewObjTable const& new_obj, | ||
| 300 | - QPDFWriter::ObjTable const& obj, | ||
| 301 | - std::string& hint_stream, | ||
| 302 | - int& S, | ||
| 303 | - int& O, | ||
| 304 | - bool compressed) | ||
| 305 | - { | ||
| 306 | - lin.generateHintStream(new_obj, obj, hint_stream, S, O, compressed); | ||
| 307 | - } | ||
| 308 | - | ||
| 309 | - std::vector<QPDFObjGen> | ||
| 310 | - getCompressibleObjGens() | ||
| 311 | - { | ||
| 312 | - return objects.getCompressibleObjVector(); | ||
| 313 | - } | ||
| 314 | - | ||
| 315 | - std::vector<bool> | ||
| 316 | - getCompressibleObjSet() | ||
| 317 | - { | ||
| 318 | - return objects.getCompressibleObjSet(); | ||
| 319 | - } | ||
| 320 | - | ||
| 321 | - std::map<QPDFObjGen, QPDFXRefEntry> const& | ||
| 322 | - getXRefTable() | ||
| 323 | - { | ||
| 324 | - return objects.getXRefTableInternal(); | ||
| 325 | - } | ||
| 326 | - | ||
| 327 | - size_t | ||
| 328 | - tableSize() | 267 | + // Writer class is restricted to QPDFWriter so that only it can call certain methods. |
| 268 | + class Writer: protected Doc::Common | ||
| 329 | { | 269 | { |
| 330 | - return qpdf.m->objects.tableSize(); | ||
| 331 | - } | ||
| 332 | - | ||
| 333 | - QPDF::Doc::Linearization& lin; | ||
| 334 | - QPDF::Doc::Objects& objects; | ||
| 335 | -}; | 270 | + public: |
| 271 | + // flags used by unparseObject | ||
| 272 | + static int const f_stream = 1 << 0; | ||
| 273 | + static int const f_filtered = 1 << 1; | ||
| 274 | + static int const f_in_ostream = 1 << 2; | ||
| 275 | + static int const f_hex_string = 1 << 3; | ||
| 276 | + static int const f_no_encryption = 1 << 4; | ||
| 277 | + | ||
| 278 | + enum trailer_e { t_normal, t_lin_first, t_lin_second }; | ||
| 279 | + | ||
| 280 | + Writer() = delete; | ||
| 281 | + Writer(Writer const&) = delete; | ||
| 282 | + Writer(Writer&&) = delete; | ||
| 283 | + Writer& operator=(Writer const&) = delete; | ||
| 284 | + Writer& operator=(Writer&&) = delete; | ||
| 285 | + ~Writer() | ||
| 286 | + { | ||
| 287 | + if (file && close_file) { | ||
| 288 | + fclose(file); | ||
| 289 | + } | ||
| 290 | + delete output_buffer; | ||
| 291 | + } | ||
| 292 | + Writer(QPDF& qpdf, QPDFWriter& w) : | ||
| 293 | + Common(qpdf.doc()), | ||
| 294 | + lin(qpdf.doc().linearization()), | ||
| 295 | + cfg(true), | ||
| 296 | + root_og(qpdf.getRoot().indirect() ? qpdf.getRoot().id_gen() : QPDFObjGen(-1, 0)), | ||
| 297 | + pipeline_stack(pipeline) | ||
| 298 | + { | ||
| 299 | + } | ||
| 336 | 300 | ||
| 337 | -class QPDFWriter::Members: QPDF::Doc::Writer | 301 | + void write(); |
| 302 | + std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable(); | ||
| 303 | + void setMinimumPDFVersion(std::string const& version, int extension_level = 0); | ||
| 304 | + void copyEncryptionParameters(QPDF&); | ||
| 305 | + void doWriteSetup(); | ||
| 306 | + void prepareFileForWrite(); | ||
| 307 | + | ||
| 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(); | ||
| 334 | + | ||
| 335 | + // Returns tuple<filter, compress_stream, is_root_metadata> | ||
| 336 | + std::tuple<const bool, const bool, const bool> | ||
| 337 | + will_filter_stream(QPDFObjectHandle stream, std::string* stream_data); | ||
| 338 | + | ||
| 339 | + // Test whether stream would be filtered if it were written. | ||
| 340 | + bool will_filter_stream(QPDFObjectHandle stream); | ||
| 341 | + unsigned int bytesNeeded(long long n); | ||
| 342 | + void writeBinary(unsigned long long val, unsigned int bytes); | ||
| 343 | + Writer& write(std::string_view str); | ||
| 344 | + Writer& write(size_t count, char c); | ||
| 345 | + Writer& write(std::integral auto val); | ||
| 346 | + Writer& write_name(std::string const& str); | ||
| 347 | + Writer& write_string(std::string const& str, bool force_binary = false); | ||
| 348 | + Writer& write_encrypted(std::string_view str); | ||
| 349 | + | ||
| 350 | + template <typename... Args> | ||
| 351 | + Writer& write_qdf(Args&&... args); | ||
| 352 | + template <typename... Args> | ||
| 353 | + Writer& write_no_qdf(Args&&... args); | ||
| 354 | + void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj); | ||
| 355 | + void writeObjectStream(QPDFObjectHandle object); | ||
| 356 | + void writeObject(QPDFObjectHandle object, int object_stream_index = -1); | ||
| 357 | + void writeTrailer( | ||
| 358 | + trailer_e which, | ||
| 359 | + int size, | ||
| 360 | + bool xref_stream, | ||
| 361 | + qpdf_offset_t prev, | ||
| 362 | + int linearization_pass); | ||
| 363 | + void unparseObject( | ||
| 364 | + QPDFObjectHandle object, | ||
| 365 | + size_t level, | ||
| 366 | + int flags, | ||
| 367 | + // for stream dictionaries | ||
| 368 | + size_t stream_length = 0, | ||
| 369 | + bool compress = false); | ||
| 370 | + void unparseChild(QPDFObjectHandle const& child, size_t level, int flags); | ||
| 371 | + int openObject(int objid = 0); | ||
| 372 | + void closeObject(int objid); | ||
| 373 | + void writeStandard(); | ||
| 374 | + void writeLinearized(); | ||
| 375 | + void writeEncryptionDictionary(); | ||
| 376 | + void writeHeader(); | ||
| 377 | + void writeHintStream(int hint_id); | ||
| 378 | + qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size); | ||
| 379 | + qpdf_offset_t writeXRefTable( | ||
| 380 | + trailer_e which, | ||
| 381 | + int first, | ||
| 382 | + int last, | ||
| 383 | + int size, | ||
| 384 | + // for linearization | ||
| 385 | + qpdf_offset_t prev, | ||
| 386 | + bool suppress_offsets, | ||
| 387 | + int hint_id, | ||
| 388 | + qpdf_offset_t hint_offset, | ||
| 389 | + qpdf_offset_t hint_length, | ||
| 390 | + int linearization_pass); | ||
| 391 | + qpdf_offset_t writeXRefStream( | ||
| 392 | + int objid, | ||
| 393 | + int max_id, | ||
| 394 | + qpdf_offset_t max_offset, | ||
| 395 | + trailer_e which, | ||
| 396 | + int first, | ||
| 397 | + int last, | ||
| 398 | + int size); | ||
| 399 | + qpdf_offset_t writeXRefStream( | ||
| 400 | + int objid, | ||
| 401 | + int max_id, | ||
| 402 | + qpdf_offset_t max_offset, | ||
| 403 | + trailer_e which, | ||
| 404 | + int first, | ||
| 405 | + int last, | ||
| 406 | + int size, | ||
| 407 | + // for linearization | ||
| 408 | + qpdf_offset_t prev, | ||
| 409 | + int hint_id, | ||
| 410 | + qpdf_offset_t hint_offset, | ||
| 411 | + qpdf_offset_t hint_length, | ||
| 412 | + bool skip_compression, | ||
| 413 | + int linearization_pass); | ||
| 414 | + | ||
| 415 | + void setDataKey(int objid); | ||
| 416 | + void indicateProgress(bool decrement, bool finished); | ||
| 417 | + size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes); | ||
| 418 | + | ||
| 419 | + void adjustAESStreamLength(size_t& length); | ||
| 420 | + void computeDeterministicIDData(); | ||
| 421 | + | ||
| 422 | + protected: | ||
| 423 | + Doc::Linearization& lin; | ||
| 424 | + | ||
| 425 | + qpdf::Writer::Config cfg; | ||
| 426 | + | ||
| 427 | + QPDFObjGen root_og{-1, 0}; | ||
| 428 | + char const* filename{"unspecified"}; | ||
| 429 | + FILE* file{nullptr}; | ||
| 430 | + bool close_file{false}; | ||
| 431 | + std::unique_ptr<Pl_Buffer> buffer_pipeline{nullptr}; | ||
| 432 | + Buffer* output_buffer{nullptr}; | ||
| 433 | + | ||
| 434 | + std::unique_ptr<QPDF::Doc::Encryption> encryption; | ||
| 435 | + std::string encryption_key; | ||
| 436 | + | ||
| 437 | + std::string id1; // for /ID key of | ||
| 438 | + std::string id2; // trailer dictionary | ||
| 439 | + std::string final_pdf_version; | ||
| 440 | + int final_extension_level{0}; | ||
| 441 | + std::string min_pdf_version; | ||
| 442 | + int min_extension_level{0}; | ||
| 443 | + int encryption_dict_objid{0}; | ||
| 444 | + std::string cur_data_key; | ||
| 445 | + std::unique_ptr<Pipeline> file_pl; | ||
| 446 | + qpdf::pl::Count* pipeline{nullptr}; | ||
| 447 | + std::vector<QPDFObjectHandle> object_queue; | ||
| 448 | + size_t object_queue_front{0}; | ||
| 449 | + QPDFWriter::ObjTable obj; | ||
| 450 | + QPDFWriter::NewObjTable new_obj; | ||
| 451 | + int next_objid{1}; | ||
| 452 | + int cur_stream_length_id{0}; | ||
| 453 | + size_t cur_stream_length{0}; | ||
| 454 | + bool added_newline{false}; | ||
| 455 | + size_t max_ostream_index{0}; | ||
| 456 | + std::set<QPDFObjGen> normalized_streams; | ||
| 457 | + std::map<QPDFObjGen, int> page_object_to_seq; | ||
| 458 | + std::map<QPDFObjGen, int> contents_to_page_seq; | ||
| 459 | + std::map<int, std::vector<QPDFObjGen>> object_stream_to_objects; | ||
| 460 | + Pl_stack pipeline_stack; | ||
| 461 | + std::string deterministic_id_data; | ||
| 462 | + bool did_write_setup{false}; | ||
| 463 | + | ||
| 464 | + // For progress reporting | ||
| 465 | + std::shared_ptr<QPDFWriter::ProgressReporter> progress_reporter; | ||
| 466 | + int events_expected{0}; | ||
| 467 | + int events_seen{0}; | ||
| 468 | + int next_progress_report{0}; | ||
| 469 | + }; // class qpdf::impl::Writer | ||
| 470 | + | ||
| 471 | +} // namespace qpdf::impl | ||
| 472 | + | ||
| 473 | +class QPDFWriter::Members: impl::Writer | ||
| 338 | { | 474 | { |
| 339 | friend class QPDFWriter; | 475 | friend class QPDFWriter; |
| 476 | + friend class qpdf::Writer; | ||
| 340 | 477 | ||
| 341 | public: | 478 | public: |
| 342 | - // flags used by unparseObject | ||
| 343 | - static int const f_stream = 1 << 0; | ||
| 344 | - static int const f_filtered = 1 << 1; | ||
| 345 | - static int const f_in_ostream = 1 << 2; | ||
| 346 | - static int const f_hex_string = 1 << 3; | ||
| 347 | - static int const f_no_encryption = 1 << 4; | ||
| 348 | - | ||
| 349 | - enum trailer_e { t_normal, t_lin_first, t_lin_second }; | ||
| 350 | - | ||
| 351 | - Members(QPDFWriter& w, QPDF& pdf) : | ||
| 352 | - QPDF::Doc::Writer(pdf), | ||
| 353 | - w(w), | ||
| 354 | - root_og( | ||
| 355 | - qpdf.getRoot().getObjGen().isIndirect() ? qpdf.getRoot().getObjGen() | ||
| 356 | - : QPDFObjGen(-1, 0)), | ||
| 357 | - pipeline_stack(pipeline) | 479 | + Members(QPDFWriter& w, QPDF& qpdf) : |
| 480 | + impl::Writer(qpdf, w) | ||
| 358 | { | 481 | { |
| 359 | } | 482 | } |
| 360 | - | ||
| 361 | - Members(Members const&) = delete; | ||
| 362 | - | ||
| 363 | - ~Members() | ||
| 364 | - { | ||
| 365 | - if (file && close_file) { | ||
| 366 | - fclose(file); | ||
| 367 | - } | ||
| 368 | - delete output_buffer; | ||
| 369 | - } | ||
| 370 | - | ||
| 371 | - void write(); | ||
| 372 | - std::map<QPDFObjGen, QPDFXRefEntry> getWrittenXRefTable(); | ||
| 373 | - void setMinimumPDFVersion(std::string const& version, int extension_level); | ||
| 374 | - void copyEncryptionParameters(QPDF&); | ||
| 375 | - void doWriteSetup(); | ||
| 376 | - void prepareFileForWrite(); | ||
| 377 | - | ||
| 378 | - void disableIncompatibleEncryption(int major, int minor, int extension_level); | ||
| 379 | - void interpretR3EncryptionParameters( | ||
| 380 | - bool allow_accessibility, | ||
| 381 | - bool allow_extract, | ||
| 382 | - bool allow_assemble, | ||
| 383 | - bool allow_annotate_and_form, | ||
| 384 | - bool allow_form_filling, | ||
| 385 | - bool allow_modify_other, | ||
| 386 | - qpdf_r3_print_e print, | ||
| 387 | - qpdf_r3_modify_e modify); | ||
| 388 | - void setEncryptionParameters(char const* user_password, char const* owner_password); | ||
| 389 | - void setEncryptionMinimumVersion(); | ||
| 390 | - void parseVersion(std::string const& version, int& major, int& minor) const; | ||
| 391 | - int compareVersions(int major1, int minor1, int major2, int minor2) const; | ||
| 392 | - void generateID(bool encrypted); | ||
| 393 | - std::string getOriginalID1(); | ||
| 394 | - void initializeTables(size_t extra = 0); | ||
| 395 | - void preserveObjectStreams(); | ||
| 396 | - void generateObjectStreams(); | ||
| 397 | - void initializeSpecialStreams(); | ||
| 398 | - void enqueue(QPDFObjectHandle const& object); | ||
| 399 | - void enqueueObjectsStandard(); | ||
| 400 | - void enqueueObjectsPCLm(); | ||
| 401 | - void enqueuePart(std::vector<QPDFObjectHandle>& part); | ||
| 402 | - void assignCompressedObjectNumbers(QPDFObjGen og); | ||
| 403 | - Dictionary trimmed_trailer(); | ||
| 404 | - | ||
| 405 | - // Returns tuple<filter, compress_stream, is_root_metadata> | ||
| 406 | - std::tuple<const bool, const bool, const bool> | ||
| 407 | - will_filter_stream(QPDFObjectHandle stream, std::string* stream_data); | ||
| 408 | - | ||
| 409 | - // Test whether stream would be filtered if it were written. | ||
| 410 | - bool will_filter_stream(QPDFObjectHandle stream); | ||
| 411 | - unsigned int bytesNeeded(long long n); | ||
| 412 | - void writeBinary(unsigned long long val, unsigned int bytes); | ||
| 413 | - Members& write(std::string_view str); | ||
| 414 | - Members& write(size_t count, char c); | ||
| 415 | - Members& write(std::integral auto val); | ||
| 416 | - Members& write_name(std::string const& str); | ||
| 417 | - Members& write_string(std::string const& str, bool force_binary = false); | ||
| 418 | - Members& write_encrypted(std::string_view str); | ||
| 419 | - | ||
| 420 | - template <typename... Args> | ||
| 421 | - Members& write_qdf(Args&&... args); | ||
| 422 | - template <typename... Args> | ||
| 423 | - Members& write_no_qdf(Args&&... args); | ||
| 424 | - void writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj); | ||
| 425 | - void writeObjectStream(QPDFObjectHandle object); | ||
| 426 | - void writeObject(QPDFObjectHandle object, int object_stream_index = -1); | ||
| 427 | - void writeTrailer( | ||
| 428 | - trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass); | ||
| 429 | - void unparseObject( | ||
| 430 | - QPDFObjectHandle object, | ||
| 431 | - size_t level, | ||
| 432 | - int flags, | ||
| 433 | - // for stream dictionaries | ||
| 434 | - size_t stream_length = 0, | ||
| 435 | - bool compress = false); | ||
| 436 | - void unparseChild(QPDFObjectHandle const& child, size_t level, int flags); | ||
| 437 | - int openObject(int objid = 0); | ||
| 438 | - void closeObject(int objid); | ||
| 439 | - void writeStandard(); | ||
| 440 | - void writeLinearized(); | ||
| 441 | - void writeEncryptionDictionary(); | ||
| 442 | - void writeHeader(); | ||
| 443 | - void writeHintStream(int hint_id); | ||
| 444 | - qpdf_offset_t writeXRefTable(trailer_e which, int first, int last, int size); | ||
| 445 | - qpdf_offset_t writeXRefTable( | ||
| 446 | - trailer_e which, | ||
| 447 | - int first, | ||
| 448 | - int last, | ||
| 449 | - int size, | ||
| 450 | - // for linearization | ||
| 451 | - qpdf_offset_t prev, | ||
| 452 | - bool suppress_offsets, | ||
| 453 | - int hint_id, | ||
| 454 | - qpdf_offset_t hint_offset, | ||
| 455 | - qpdf_offset_t hint_length, | ||
| 456 | - int linearization_pass); | ||
| 457 | - qpdf_offset_t writeXRefStream( | ||
| 458 | - int objid, | ||
| 459 | - int max_id, | ||
| 460 | - qpdf_offset_t max_offset, | ||
| 461 | - trailer_e which, | ||
| 462 | - int first, | ||
| 463 | - int last, | ||
| 464 | - int size); | ||
| 465 | - qpdf_offset_t writeXRefStream( | ||
| 466 | - int objid, | ||
| 467 | - int max_id, | ||
| 468 | - qpdf_offset_t max_offset, | ||
| 469 | - trailer_e which, | ||
| 470 | - int first, | ||
| 471 | - int last, | ||
| 472 | - int size, | ||
| 473 | - // for linearization | ||
| 474 | - qpdf_offset_t prev, | ||
| 475 | - int hint_id, | ||
| 476 | - qpdf_offset_t hint_offset, | ||
| 477 | - qpdf_offset_t hint_length, | ||
| 478 | - bool skip_compression, | ||
| 479 | - int linearization_pass); | ||
| 480 | - | ||
| 481 | - void setDataKey(int objid); | ||
| 482 | - void indicateProgress(bool decrement, bool finished); | ||
| 483 | - size_t calculateXrefStreamPadding(qpdf_offset_t xref_bytes); | ||
| 484 | - | ||
| 485 | - void adjustAESStreamLength(size_t& length); | ||
| 486 | - void computeDeterministicIDData(); | ||
| 487 | - | ||
| 488 | - private: | ||
| 489 | - QPDFWriter& w; | ||
| 490 | - QPDFObjGen root_og{-1, 0}; | ||
| 491 | - char const* filename{"unspecified"}; | ||
| 492 | - FILE* file{nullptr}; | ||
| 493 | - bool close_file{false}; | ||
| 494 | - std::unique_ptr<Pl_Buffer> buffer_pipeline{nullptr}; | ||
| 495 | - Buffer* output_buffer{nullptr}; | ||
| 496 | - bool normalize_content_set{false}; | ||
| 497 | - bool normalize_content{false}; | ||
| 498 | - bool compress_streams{true}; | ||
| 499 | - bool compress_streams_set{false}; | ||
| 500 | - qpdf_stream_decode_level_e stream_decode_level{qpdf_dl_generalized}; | ||
| 501 | - bool stream_decode_level_set{false}; | ||
| 502 | - bool recompress_flate{false}; | ||
| 503 | - bool qdf_mode{false}; | ||
| 504 | - bool preserve_unreferenced_objects{false}; | ||
| 505 | - bool newline_before_endstream{false}; | ||
| 506 | - bool static_id{false}; | ||
| 507 | - bool suppress_original_object_ids{false}; | ||
| 508 | - bool direct_stream_lengths{true}; | ||
| 509 | - bool preserve_encryption{true}; | ||
| 510 | - bool linearized{false}; | ||
| 511 | - bool pclm{false}; | ||
| 512 | - qpdf_object_stream_e object_stream_mode{qpdf_o_preserve}; | ||
| 513 | - | ||
| 514 | - std::unique_ptr<QPDF::Doc::Encryption> encryption; | ||
| 515 | - std::string encryption_key; | ||
| 516 | - bool encrypt_use_aes{false}; | ||
| 517 | - | ||
| 518 | - std::string id1; // for /ID key of | ||
| 519 | - std::string id2; // trailer dictionary | ||
| 520 | - std::string final_pdf_version; | ||
| 521 | - int final_extension_level{0}; | ||
| 522 | - std::string min_pdf_version; | ||
| 523 | - int min_extension_level{0}; | ||
| 524 | - std::string forced_pdf_version; | ||
| 525 | - int forced_extension_level{0}; | ||
| 526 | - std::string extra_header_text; | ||
| 527 | - int encryption_dict_objid{0}; | ||
| 528 | - std::string cur_data_key; | ||
| 529 | - std::unique_ptr<Pipeline> file_pl; | ||
| 530 | - qpdf::pl::Count* pipeline{nullptr}; | ||
| 531 | - std::vector<QPDFObjectHandle> object_queue; | ||
| 532 | - size_t object_queue_front{0}; | ||
| 533 | - QPDFWriter::ObjTable obj; | ||
| 534 | - QPDFWriter::NewObjTable new_obj; | ||
| 535 | - int next_objid{1}; | ||
| 536 | - int cur_stream_length_id{0}; | ||
| 537 | - size_t cur_stream_length{0}; | ||
| 538 | - bool added_newline{false}; | ||
| 539 | - size_t max_ostream_index{0}; | ||
| 540 | - std::set<QPDFObjGen> normalized_streams; | ||
| 541 | - std::map<QPDFObjGen, int> page_object_to_seq; | ||
| 542 | - std::map<QPDFObjGen, int> contents_to_page_seq; | ||
| 543 | - std::map<int, std::vector<QPDFObjGen>> object_stream_to_objects; | ||
| 544 | - Pl_stack pipeline_stack; | ||
| 545 | - bool deterministic_id{false}; | ||
| 546 | - std::string deterministic_id_data; | ||
| 547 | - bool did_write_setup{false}; | ||
| 548 | - | ||
| 549 | - // For linearization only | ||
| 550 | - std::string lin_pass1_filename; | ||
| 551 | - | ||
| 552 | - // For progress reporting | ||
| 553 | - std::shared_ptr<QPDFWriter::ProgressReporter> progress_reporter; | ||
| 554 | - int events_expected{0}; | ||
| 555 | - int events_seen{0}; | ||
| 556 | - int next_progress_report{0}; | ||
| 557 | }; | 483 | }; |
| 558 | 484 | ||
| 485 | +qpdf::Writer::Writer(QPDF& qpdf, Config cfg) : | ||
| 486 | + QPDFWriter(qpdf) | ||
| 487 | +{ | ||
| 488 | + m->cfg = cfg; | ||
| 489 | +} | ||
| 559 | QPDFWriter::QPDFWriter(QPDF& pdf) : | 490 | QPDFWriter::QPDFWriter(QPDF& pdf) : |
| 560 | m(std::make_shared<Members>(*this, pdf)) | 491 | m(std::make_shared<Members>(*this, pdf)) |
| 561 | { | 492 | { |
| @@ -632,75 +563,129 @@ QPDFWriter::setOutputPipeline(Pipeline* p) | @@ -632,75 +563,129 @@ QPDFWriter::setOutputPipeline(Pipeline* p) | ||
| 632 | void | 563 | void |
| 633 | QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) | 564 | QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) |
| 634 | { | 565 | { |
| 635 | - m->object_stream_mode = mode; | 566 | + m->cfg.object_streams(mode); |
| 636 | } | 567 | } |
| 637 | 568 | ||
| 638 | void | 569 | void |
| 639 | QPDFWriter::setStreamDataMode(qpdf_stream_data_e mode) | 570 | QPDFWriter::setStreamDataMode(qpdf_stream_data_e mode) |
| 640 | { | 571 | { |
| 572 | + m->cfg.stream_data(mode); | ||
| 573 | +} | ||
| 574 | + | ||
| 575 | +Config& | ||
| 576 | +Config::stream_data(qpdf_stream_data_e mode) | ||
| 577 | +{ | ||
| 641 | switch (mode) { | 578 | switch (mode) { |
| 642 | case qpdf_s_uncompress: | 579 | case qpdf_s_uncompress: |
| 643 | - m->stream_decode_level = std::max(qpdf_dl_generalized, m->stream_decode_level); | ||
| 644 | - m->compress_streams = false; | ||
| 645 | - break; | 580 | + decode_level(std::max(qpdf_dl_generalized, decode_level_)); |
| 581 | + compress_streams(false); | ||
| 582 | + return *this; | ||
| 646 | 583 | ||
| 647 | case qpdf_s_preserve: | 584 | case qpdf_s_preserve: |
| 648 | - m->stream_decode_level = qpdf_dl_none; | ||
| 649 | - m->compress_streams = false; | ||
| 650 | - break; | 585 | + decode_level(qpdf_dl_none); |
| 586 | + compress_streams(false); | ||
| 587 | + return *this; | ||
| 651 | 588 | ||
| 652 | case qpdf_s_compress: | 589 | case qpdf_s_compress: |
| 653 | - m->stream_decode_level = std::max(qpdf_dl_generalized, m->stream_decode_level); | ||
| 654 | - m->compress_streams = true; | ||
| 655 | - break; | 590 | + decode_level(std::max(qpdf_dl_generalized, decode_level_)); |
| 591 | + compress_streams(true); | ||
| 656 | } | 592 | } |
| 657 | - m->stream_decode_level_set = true; | ||
| 658 | - m->compress_streams_set = true; | 593 | + return *this; |
| 659 | } | 594 | } |
| 660 | 595 | ||
| 661 | void | 596 | void |
| 662 | QPDFWriter::setCompressStreams(bool val) | 597 | QPDFWriter::setCompressStreams(bool val) |
| 663 | { | 598 | { |
| 664 | - m->compress_streams = val; | ||
| 665 | - m->compress_streams_set = true; | 599 | + m->cfg.compress_streams(val); |
| 600 | +} | ||
| 601 | + | ||
| 602 | +Config& | ||
| 603 | +Config::compress_streams(bool val) | ||
| 604 | +{ | ||
| 605 | + if (pclm_) { | ||
| 606 | + usage("compress_streams cannot be set when pclm is set"); | ||
| 607 | + return *this; | ||
| 608 | + } | ||
| 609 | + compress_streams_set_ = true; | ||
| 610 | + compress_streams_ = val; | ||
| 611 | + return *this; | ||
| 666 | } | 612 | } |
| 667 | 613 | ||
| 668 | void | 614 | void |
| 669 | QPDFWriter::setDecodeLevel(qpdf_stream_decode_level_e val) | 615 | QPDFWriter::setDecodeLevel(qpdf_stream_decode_level_e val) |
| 670 | { | 616 | { |
| 671 | - m->stream_decode_level = val; | ||
| 672 | - m->stream_decode_level_set = true; | 617 | + m->cfg.decode_level(val); |
| 618 | +} | ||
| 619 | + | ||
| 620 | +Config& | ||
| 621 | +Config::decode_level(qpdf_stream_decode_level_e val) | ||
| 622 | +{ | ||
| 623 | + if (pclm_) { | ||
| 624 | + usage("stream_decode_level cannot be set when pclm is set"); | ||
| 625 | + return *this; | ||
| 626 | + } | ||
| 627 | + decode_level_set_ = true; | ||
| 628 | + decode_level_ = val; | ||
| 629 | + return *this; | ||
| 673 | } | 630 | } |
| 674 | 631 | ||
| 675 | void | 632 | void |
| 676 | QPDFWriter::setRecompressFlate(bool val) | 633 | QPDFWriter::setRecompressFlate(bool val) |
| 677 | { | 634 | { |
| 678 | - m->recompress_flate = val; | 635 | + m->cfg.recompress_flate(val); |
| 679 | } | 636 | } |
| 680 | 637 | ||
| 681 | void | 638 | void |
| 682 | QPDFWriter::setContentNormalization(bool val) | 639 | QPDFWriter::setContentNormalization(bool val) |
| 683 | { | 640 | { |
| 684 | - m->normalize_content_set = true; | ||
| 685 | - m->normalize_content = val; | 641 | + m->cfg.normalize_content(val); |
| 686 | } | 642 | } |
| 687 | 643 | ||
| 688 | void | 644 | void |
| 689 | QPDFWriter::setQDFMode(bool val) | 645 | QPDFWriter::setQDFMode(bool val) |
| 690 | { | 646 | { |
| 691 | - m->qdf_mode = val; | 647 | + m->cfg.qdf(val); |
| 648 | +} | ||
| 649 | + | ||
| 650 | +Config& | ||
| 651 | +Config::qdf(bool val) | ||
| 652 | +{ | ||
| 653 | + if (pclm_ || linearize_) { | ||
| 654 | + usage("qdf cannot be set when linearize or pclm are set"); | ||
| 655 | + } | ||
| 656 | + if (preserve_encryption_) { | ||
| 657 | + usage("preserve_encryption cannot be set when qdf is set"); | ||
| 658 | + } | ||
| 659 | + qdf_ = val; | ||
| 660 | + if (val) { | ||
| 661 | + if (!normalize_content_set_) { | ||
| 662 | + normalize_content(true); | ||
| 663 | + } | ||
| 664 | + if (!compress_streams_set_) { | ||
| 665 | + compress_streams(false); | ||
| 666 | + } | ||
| 667 | + if (!decode_level_set_) { | ||
| 668 | + decode_level(qpdf_dl_generalized); | ||
| 669 | + } | ||
| 670 | + preserve_encryption_ = false; | ||
| 671 | + // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing | ||
| 672 | + // recomputed stream length data. Certain streams such as object streams, xref streams, and | ||
| 673 | + // hint streams always get direct stream lengths. | ||
| 674 | + direct_stream_lengths_ = false; | ||
| 675 | + } | ||
| 676 | + return *this; | ||
| 692 | } | 677 | } |
| 693 | 678 | ||
| 694 | void | 679 | void |
| 695 | QPDFWriter::setPreserveUnreferencedObjects(bool val) | 680 | QPDFWriter::setPreserveUnreferencedObjects(bool val) |
| 696 | { | 681 | { |
| 697 | - m->preserve_unreferenced_objects = val; | 682 | + m->cfg.preserve_unreferenced(val); |
| 698 | } | 683 | } |
| 699 | 684 | ||
| 700 | void | 685 | void |
| 701 | QPDFWriter::setNewlineBeforeEndstream(bool val) | 686 | QPDFWriter::setNewlineBeforeEndstream(bool val) |
| 702 | { | 687 | { |
| 703 | - m->newline_before_endstream = val; | 688 | + m->cfg.newline_before_endstream(val); |
| 704 | } | 689 | } |
| 705 | 690 | ||
| 706 | void | 691 | void |
| @@ -710,7 +695,7 @@ QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level | @@ -710,7 +695,7 @@ QPDFWriter::setMinimumPDFVersion(std::string const& version, int extension_level | ||
| 710 | } | 695 | } |
| 711 | 696 | ||
| 712 | void | 697 | void |
| 713 | -QPDFWriter::Members::setMinimumPDFVersion(std::string const& version, int extension_level) | 698 | +impl::Writer::setMinimumPDFVersion(std::string const& version, int extension_level) |
| 714 | { | 699 | { |
| 715 | bool set_version = false; | 700 | bool set_version = false; |
| 716 | bool set_extension_level = false; | 701 | bool set_extension_level = false; |
| @@ -756,31 +741,37 @@ QPDFWriter::setMinimumPDFVersion(PDFVersion const& v) | @@ -756,31 +741,37 @@ QPDFWriter::setMinimumPDFVersion(PDFVersion const& v) | ||
| 756 | void | 741 | void |
| 757 | QPDFWriter::forcePDFVersion(std::string const& version, int extension_level) | 742 | QPDFWriter::forcePDFVersion(std::string const& version, int extension_level) |
| 758 | { | 743 | { |
| 759 | - m->forced_pdf_version = version; | ||
| 760 | - m->forced_extension_level = extension_level; | 744 | + m->cfg.forced_pdf_version(version, extension_level); |
| 761 | } | 745 | } |
| 762 | 746 | ||
| 763 | void | 747 | void |
| 764 | QPDFWriter::setExtraHeaderText(std::string const& text) | 748 | QPDFWriter::setExtraHeaderText(std::string const& text) |
| 765 | { | 749 | { |
| 766 | - m->extra_header_text = text; | ||
| 767 | - if (!m->extra_header_text.empty() && *m->extra_header_text.rbegin() != '\n') { | ||
| 768 | - m->extra_header_text += "\n"; | 750 | + m->cfg.extra_header_text(text); |
| 751 | +} | ||
| 752 | + | ||
| 753 | +Config& | ||
| 754 | +Config::extra_header_text(std::string const& val) | ||
| 755 | +{ | ||
| 756 | + extra_header_text_ = val; | ||
| 757 | + if (!extra_header_text_.empty() && extra_header_text_.back() != '\n') { | ||
| 758 | + extra_header_text_ += "\n"; | ||
| 769 | } else { | 759 | } else { |
| 770 | QTC::TC("qpdf", "QPDFWriter extra header text no newline"); | 760 | QTC::TC("qpdf", "QPDFWriter extra header text no newline"); |
| 771 | } | 761 | } |
| 762 | + return *this; | ||
| 772 | } | 763 | } |
| 773 | 764 | ||
| 774 | void | 765 | void |
| 775 | QPDFWriter::setStaticID(bool val) | 766 | QPDFWriter::setStaticID(bool val) |
| 776 | { | 767 | { |
| 777 | - m->static_id = val; | 768 | + m->cfg.static_id(val); |
| 778 | } | 769 | } |
| 779 | 770 | ||
| 780 | void | 771 | void |
| 781 | QPDFWriter::setDeterministicID(bool val) | 772 | QPDFWriter::setDeterministicID(bool val) |
| 782 | { | 773 | { |
| 783 | - m->deterministic_id = val; | 774 | + m->cfg.deterministic_id(val); |
| 784 | } | 775 | } |
| 785 | 776 | ||
| 786 | void | 777 | void |
| @@ -794,37 +785,61 @@ QPDFWriter::setStaticAesIV(bool val) | @@ -794,37 +785,61 @@ QPDFWriter::setStaticAesIV(bool val) | ||
| 794 | void | 785 | void |
| 795 | QPDFWriter::setSuppressOriginalObjectIDs(bool val) | 786 | QPDFWriter::setSuppressOriginalObjectIDs(bool val) |
| 796 | { | 787 | { |
| 797 | - m->suppress_original_object_ids = val; | 788 | + m->cfg.no_original_object_ids(val); |
| 798 | } | 789 | } |
| 799 | 790 | ||
| 800 | void | 791 | void |
| 801 | QPDFWriter::setPreserveEncryption(bool val) | 792 | QPDFWriter::setPreserveEncryption(bool val) |
| 802 | { | 793 | { |
| 803 | - m->preserve_encryption = val; | 794 | + m->cfg.preserve_encryption(val); |
| 804 | } | 795 | } |
| 805 | 796 | ||
| 806 | void | 797 | void |
| 807 | QPDFWriter::setLinearization(bool val) | 798 | QPDFWriter::setLinearization(bool val) |
| 808 | { | 799 | { |
| 809 | - m->linearized = val; | ||
| 810 | - if (val) { | ||
| 811 | - m->pclm = false; | 800 | + m->cfg.linearize(val); |
| 801 | +} | ||
| 802 | + | ||
| 803 | +Config& | ||
| 804 | +Config::linearize(bool val) | ||
| 805 | +{ | ||
| 806 | + if (pclm_ || qdf_) { | ||
| 807 | + usage("linearize cannot be set when qdf or pclm are set"); | ||
| 808 | + return *this; | ||
| 812 | } | 809 | } |
| 810 | + linearize_ = val; | ||
| 811 | + return *this; | ||
| 813 | } | 812 | } |
| 814 | 813 | ||
| 815 | void | 814 | void |
| 816 | QPDFWriter::setLinearizationPass1Filename(std::string const& filename) | 815 | QPDFWriter::setLinearizationPass1Filename(std::string const& filename) |
| 817 | { | 816 | { |
| 818 | - m->lin_pass1_filename = filename; | 817 | + m->cfg.linearize_pass1(filename); |
| 819 | } | 818 | } |
| 820 | 819 | ||
| 821 | void | 820 | void |
| 822 | QPDFWriter::setPCLm(bool val) | 821 | QPDFWriter::setPCLm(bool val) |
| 823 | { | 822 | { |
| 824 | - m->pclm = val; | 823 | + m->cfg.pclm(val); |
| 824 | +} | ||
| 825 | + | ||
| 826 | +Config& | ||
| 827 | +Config::pclm(bool val) | ||
| 828 | +{ | ||
| 829 | + if (decode_level_set_ || compress_streams_set_ || linearize_) { | ||
| 830 | + usage( | ||
| 831 | + "pclm cannot be set when stream_decode_level, compress_streams, linearize or qdf are " | ||
| 832 | + "set"); | ||
| 833 | + return *this; | ||
| 834 | + } | ||
| 835 | + pclm_ = val; | ||
| 825 | if (val) { | 836 | if (val) { |
| 826 | - m->linearized = false; | 837 | + decode_level_ = qpdf_dl_none; |
| 838 | + compress_streams_ = false; | ||
| 839 | + linearize_ = false; | ||
| 827 | } | 840 | } |
| 841 | + | ||
| 842 | + return *this; | ||
| 828 | } | 843 | } |
| 829 | 844 | ||
| 830 | void | 845 | void |
| @@ -892,7 +907,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( | @@ -892,7 +907,7 @@ QPDFWriter::setR4EncryptionParametersInsecure( | ||
| 892 | bool use_aes) | 907 | bool use_aes) |
| 893 | { | 908 | { |
| 894 | m->encryption = std::make_unique<Encryption>(4, 4, 16, encrypt_metadata); | 909 | m->encryption = std::make_unique<Encryption>(4, 4, 16, encrypt_metadata); |
| 895 | - m->encrypt_use_aes = use_aes; | 910 | + m->cfg.encrypt_use_aes(use_aes); |
| 896 | m->interpretR3EncryptionParameters( | 911 | m->interpretR3EncryptionParameters( |
| 897 | allow_accessibility, | 912 | allow_accessibility, |
| 898 | allow_extract, | 913 | allow_extract, |
| @@ -919,7 +934,7 @@ QPDFWriter::setR5EncryptionParameters( | @@ -919,7 +934,7 @@ QPDFWriter::setR5EncryptionParameters( | ||
| 919 | bool encrypt_metadata) | 934 | bool encrypt_metadata) |
| 920 | { | 935 | { |
| 921 | m->encryption = std::make_unique<Encryption>(5, 5, 32, encrypt_metadata); | 936 | m->encryption = std::make_unique<Encryption>(5, 5, 32, encrypt_metadata); |
| 922 | - m->encrypt_use_aes = true; | 937 | + m->cfg.encrypt_use_aes(true); |
| 923 | m->interpretR3EncryptionParameters( | 938 | m->interpretR3EncryptionParameters( |
| 924 | allow_accessibility, | 939 | allow_accessibility, |
| 925 | allow_extract, | 940 | allow_extract, |
| @@ -955,12 +970,12 @@ QPDFWriter::setR6EncryptionParameters( | @@ -955,12 +970,12 @@ QPDFWriter::setR6EncryptionParameters( | ||
| 955 | allow_modify_other, | 970 | allow_modify_other, |
| 956 | print, | 971 | print, |
| 957 | qpdf_r3m_all); | 972 | qpdf_r3m_all); |
| 958 | - m->encrypt_use_aes = true; | 973 | + m->cfg.encrypt_use_aes(true); |
| 959 | m->setEncryptionParameters(user_password, owner_password); | 974 | m->setEncryptionParameters(user_password, owner_password); |
| 960 | } | 975 | } |
| 961 | 976 | ||
| 962 | void | 977 | void |
| 963 | -QPDFWriter::Members::interpretR3EncryptionParameters( | 978 | +impl::Writer::interpretR3EncryptionParameters( |
| 964 | bool allow_accessibility, | 979 | bool allow_accessibility, |
| 965 | bool allow_extract, | 980 | bool allow_extract, |
| 966 | bool allow_assemble, | 981 | bool allow_assemble, |
| @@ -1059,7 +1074,7 @@ QPDFWriter::Members::interpretR3EncryptionParameters( | @@ -1059,7 +1074,7 @@ QPDFWriter::Members::interpretR3EncryptionParameters( | ||
| 1059 | } | 1074 | } |
| 1060 | 1075 | ||
| 1061 | void | 1076 | void |
| 1062 | -QPDFWriter::Members::setEncryptionParameters(char const* user_password, char const* owner_password) | 1077 | +impl::Writer::setEncryptionParameters(char const* user_password, char const* owner_password) |
| 1063 | { | 1078 | { |
| 1064 | generateID(true); | 1079 | generateID(true); |
| 1065 | encryption->setId1(id1); | 1080 | encryption->setId1(id1); |
| @@ -1074,9 +1089,9 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | @@ -1074,9 +1089,9 @@ QPDFWriter::copyEncryptionParameters(QPDF& qpdf) | ||
| 1074 | } | 1089 | } |
| 1075 | 1090 | ||
| 1076 | void | 1091 | void |
| 1077 | -QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf) | 1092 | +impl::Writer::copyEncryptionParameters(QPDF& qpdf) |
| 1078 | { | 1093 | { |
| 1079 | - preserve_encryption = false; | 1094 | + cfg.preserve_encryption(false); |
| 1080 | QPDFObjectHandle trailer = qpdf.getTrailer(); | 1095 | QPDFObjectHandle trailer = qpdf.getTrailer(); |
| 1081 | if (trailer.hasKey("/Encrypt")) { | 1096 | if (trailer.hasKey("/Encrypt")) { |
| 1082 | generateID(true); | 1097 | generateID(true); |
| @@ -1096,10 +1111,10 @@ QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf) | @@ -1096,10 +1111,10 @@ QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf) | ||
| 1096 | // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of | 1111 | // Acrobat doesn't create files with V >= 4 that don't use AES, and the logic of |
| 1097 | // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF | 1112 | // figuring out whether AES is used or not is complicated with /StmF, /StrF, and /EFF |
| 1098 | // all potentially having different values. | 1113 | // all potentially having different values. |
| 1099 | - encrypt_use_aes = true; | 1114 | + cfg.encrypt_use_aes(true); |
| 1100 | } | 1115 | } |
| 1101 | QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); | 1116 | QTC::TC("qpdf", "QPDFWriter copy encrypt metadata", encrypt_metadata ? 0 : 1); |
| 1102 | - QTC::TC("qpdf", "QPDFWriter copy use_aes", encrypt_use_aes ? 0 : 1); | 1117 | + QTC::TC("qpdf", "QPDFWriter copy use_aes", cfg.encrypt_use_aes() ? 0 : 1); |
| 1103 | 1118 | ||
| 1104 | encryption = std::make_unique<Encryption>( | 1119 | encryption = std::make_unique<Encryption>( |
| 1105 | V, | 1120 | V, |
| @@ -1120,7 +1135,7 @@ QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf) | @@ -1120,7 +1135,7 @@ QPDFWriter::Members::copyEncryptionParameters(QPDF& qpdf) | ||
| 1120 | } | 1135 | } |
| 1121 | 1136 | ||
| 1122 | void | 1137 | void |
| 1123 | -QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int extension_level) | 1138 | +impl::Writer::disableIncompatibleEncryption(int major, int minor, int extension_level) |
| 1124 | { | 1139 | { |
| 1125 | if (!encryption) { | 1140 | if (!encryption) { |
| 1126 | return; | 1141 | return; |
| @@ -1140,7 +1155,7 @@ QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int ext | @@ -1140,7 +1155,7 @@ QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int ext | ||
| 1140 | encryption = nullptr; | 1155 | encryption = nullptr; |
| 1141 | } | 1156 | } |
| 1142 | } else if (compareVersions(major, minor, 1, 6) < 0) { | 1157 | } else if (compareVersions(major, minor, 1, 6) < 0) { |
| 1143 | - if (encrypt_use_aes) { | 1158 | + if (cfg.encrypt_use_aes()) { |
| 1144 | encryption = nullptr; | 1159 | encryption = nullptr; |
| 1145 | } | 1160 | } |
| 1146 | } else if ( | 1161 | } else if ( |
| @@ -1157,7 +1172,7 @@ QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int ext | @@ -1157,7 +1172,7 @@ QPDFWriter::Members::disableIncompatibleEncryption(int major, int minor, int ext | ||
| 1157 | } | 1172 | } |
| 1158 | 1173 | ||
| 1159 | void | 1174 | void |
| 1160 | -QPDFWriter::Members::parseVersion(std::string const& version, int& major, int& minor) const | 1175 | +impl::Writer::parseVersion(std::string const& version, int& major, int& minor) const |
| 1161 | { | 1176 | { |
| 1162 | major = QUtil::string_to_int(version.c_str()); | 1177 | major = QUtil::string_to_int(version.c_str()); |
| 1163 | minor = 0; | 1178 | minor = 0; |
| @@ -1174,7 +1189,7 @@ QPDFWriter::Members::parseVersion(std::string const& version, int& major, int& m | @@ -1174,7 +1189,7 @@ QPDFWriter::Members::parseVersion(std::string const& version, int& major, int& m | ||
| 1174 | } | 1189 | } |
| 1175 | 1190 | ||
| 1176 | int | 1191 | int |
| 1177 | -QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int minor2) const | 1192 | +impl::Writer::compareVersions(int major1, int minor1, int major2, int minor2) const |
| 1178 | { | 1193 | { |
| 1179 | if (major1 < major2) { | 1194 | if (major1 < major2) { |
| 1180 | return -1; | 1195 | return -1; |
| @@ -1189,33 +1204,38 @@ QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int min | @@ -1189,33 +1204,38 @@ QPDFWriter::Members::compareVersions(int major1, int minor1, int major2, int min | ||
| 1189 | } | 1204 | } |
| 1190 | 1205 | ||
| 1191 | void | 1206 | void |
| 1192 | -QPDFWriter::Members::setEncryptionMinimumVersion() | 1207 | +impl::Writer::setEncryptionMinimumVersion() |
| 1193 | { | 1208 | { |
| 1194 | auto const R = encryption->getR(); | 1209 | auto const R = encryption->getR(); |
| 1195 | if (R >= 6) { | 1210 | if (R >= 6) { |
| 1196 | - w.setMinimumPDFVersion("1.7", 8); | 1211 | + setMinimumPDFVersion("1.7", 8); |
| 1197 | } else if (R == 5) { | 1212 | } else if (R == 5) { |
| 1198 | - w.setMinimumPDFVersion("1.7", 3); | 1213 | + setMinimumPDFVersion("1.7", 3); |
| 1199 | } else if (R == 4) { | 1214 | } else if (R == 4) { |
| 1200 | - w.setMinimumPDFVersion(encrypt_use_aes ? "1.6" : "1.5"); | 1215 | + setMinimumPDFVersion(cfg.encrypt_use_aes() ? "1.6" : "1.5"); |
| 1201 | } else if (R == 3) { | 1216 | } else if (R == 3) { |
| 1202 | - w.setMinimumPDFVersion("1.4"); | 1217 | + setMinimumPDFVersion("1.4"); |
| 1203 | } else { | 1218 | } else { |
| 1204 | - w.setMinimumPDFVersion("1.3"); | 1219 | + setMinimumPDFVersion("1.3"); |
| 1205 | } | 1220 | } |
| 1206 | } | 1221 | } |
| 1207 | 1222 | ||
| 1208 | void | 1223 | void |
| 1209 | -QPDFWriter::Members::setDataKey(int objid) | 1224 | +impl::Writer::setDataKey(int objid) |
| 1210 | { | 1225 | { |
| 1211 | if (encryption) { | 1226 | if (encryption) { |
| 1212 | cur_data_key = QPDF::compute_data_key( | 1227 | cur_data_key = QPDF::compute_data_key( |
| 1213 | - encryption_key, objid, 0, encrypt_use_aes, encryption->getV(), encryption->getR()); | 1228 | + encryption_key, |
| 1229 | + objid, | ||
| 1230 | + 0, | ||
| 1231 | + cfg.encrypt_use_aes(), | ||
| 1232 | + encryption->getV(), | ||
| 1233 | + encryption->getR()); | ||
| 1214 | } | 1234 | } |
| 1215 | } | 1235 | } |
| 1216 | 1236 | ||
| 1217 | unsigned int | 1237 | unsigned int |
| 1218 | -QPDFWriter::Members::bytesNeeded(long long n) | 1238 | +impl::Writer::bytesNeeded(long long n) |
| 1219 | { | 1239 | { |
| 1220 | unsigned int bytes = 0; | 1240 | unsigned int bytes = 0; |
| 1221 | while (n) { | 1241 | while (n) { |
| @@ -1226,7 +1246,7 @@ QPDFWriter::Members::bytesNeeded(long long n) | @@ -1226,7 +1246,7 @@ QPDFWriter::Members::bytesNeeded(long long n) | ||
| 1226 | } | 1246 | } |
| 1227 | 1247 | ||
| 1228 | void | 1248 | void |
| 1229 | -QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes) | 1249 | +impl::Writer::writeBinary(unsigned long long val, unsigned int bytes) |
| 1230 | { | 1250 | { |
| 1231 | if (bytes > sizeof(unsigned long long)) { | 1251 | if (bytes > sizeof(unsigned long long)) { |
| 1232 | throw std::logic_error("QPDFWriter::writeBinary called with too many bytes"); | 1252 | throw std::logic_error("QPDFWriter::writeBinary called with too many bytes"); |
| @@ -1239,77 +1259,77 @@ QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes) | @@ -1239,77 +1259,77 @@ QPDFWriter::Members::writeBinary(unsigned long long val, unsigned int bytes) | ||
| 1239 | pipeline->write(data, bytes); | 1259 | pipeline->write(data, bytes); |
| 1240 | } | 1260 | } |
| 1241 | 1261 | ||
| 1242 | -QPDFWriter::Members& | ||
| 1243 | -QPDFWriter::Members::write(std::string_view str) | 1262 | +impl::Writer& |
| 1263 | +impl::Writer::write(std::string_view str) | ||
| 1244 | { | 1264 | { |
| 1245 | pipeline->write(str); | 1265 | pipeline->write(str); |
| 1246 | return *this; | 1266 | return *this; |
| 1247 | } | 1267 | } |
| 1248 | 1268 | ||
| 1249 | -QPDFWriter::Members& | ||
| 1250 | -QPDFWriter::Members::write(std::integral auto val) | 1269 | +impl::Writer& |
| 1270 | +impl::Writer::write(std::integral auto val) | ||
| 1251 | { | 1271 | { |
| 1252 | pipeline->write(std::to_string(val)); | 1272 | pipeline->write(std::to_string(val)); |
| 1253 | return *this; | 1273 | return *this; |
| 1254 | } | 1274 | } |
| 1255 | 1275 | ||
| 1256 | -QPDFWriter::Members& | ||
| 1257 | -QPDFWriter::Members::write(size_t count, char c) | 1276 | +impl::Writer& |
| 1277 | +impl::Writer::write(size_t count, char c) | ||
| 1258 | { | 1278 | { |
| 1259 | pipeline->write(count, c); | 1279 | pipeline->write(count, c); |
| 1260 | return *this; | 1280 | return *this; |
| 1261 | } | 1281 | } |
| 1262 | 1282 | ||
| 1263 | -QPDFWriter::Members& | ||
| 1264 | -QPDFWriter::Members::write_name(std::string const& str) | 1283 | +impl::Writer& |
| 1284 | +impl::Writer::write_name(std::string const& str) | ||
| 1265 | { | 1285 | { |
| 1266 | pipeline->write(Name::normalize(str)); | 1286 | pipeline->write(Name::normalize(str)); |
| 1267 | return *this; | 1287 | return *this; |
| 1268 | } | 1288 | } |
| 1269 | 1289 | ||
| 1270 | -QPDFWriter::Members& | ||
| 1271 | -QPDFWriter::Members::write_string(std::string const& str, bool force_binary) | 1290 | +impl::Writer& |
| 1291 | +impl::Writer::write_string(std::string const& str, bool force_binary) | ||
| 1272 | { | 1292 | { |
| 1273 | pipeline->write(QPDF_String(str).unparse(force_binary)); | 1293 | pipeline->write(QPDF_String(str).unparse(force_binary)); |
| 1274 | return *this; | 1294 | return *this; |
| 1275 | } | 1295 | } |
| 1276 | 1296 | ||
| 1277 | template <typename... Args> | 1297 | template <typename... Args> |
| 1278 | -QPDFWriter::Members& | ||
| 1279 | -QPDFWriter::Members::write_qdf(Args&&... args) | 1298 | +impl::Writer& |
| 1299 | +impl::Writer::write_qdf(Args&&... args) | ||
| 1280 | { | 1300 | { |
| 1281 | - if (qdf_mode) { | 1301 | + if (cfg.qdf()) { |
| 1282 | pipeline->write(std::forward<Args>(args)...); | 1302 | pipeline->write(std::forward<Args>(args)...); |
| 1283 | } | 1303 | } |
| 1284 | return *this; | 1304 | return *this; |
| 1285 | } | 1305 | } |
| 1286 | 1306 | ||
| 1287 | template <typename... Args> | 1307 | template <typename... Args> |
| 1288 | -QPDFWriter::Members& | ||
| 1289 | -QPDFWriter::Members::write_no_qdf(Args&&... args) | 1308 | +impl::Writer& |
| 1309 | +impl::Writer::write_no_qdf(Args&&... args) | ||
| 1290 | { | 1310 | { |
| 1291 | - if (!qdf_mode) { | 1311 | + if (!cfg.qdf()) { |
| 1292 | pipeline->write(std::forward<Args>(args)...); | 1312 | pipeline->write(std::forward<Args>(args)...); |
| 1293 | } | 1313 | } |
| 1294 | return *this; | 1314 | return *this; |
| 1295 | } | 1315 | } |
| 1296 | 1316 | ||
| 1297 | void | 1317 | void |
| 1298 | -QPDFWriter::Members::adjustAESStreamLength(size_t& length) | 1318 | +impl::Writer::adjustAESStreamLength(size_t& length) |
| 1299 | { | 1319 | { |
| 1300 | - if (encryption && !cur_data_key.empty() && encrypt_use_aes) { | 1320 | + if (encryption && !cur_data_key.empty() && cfg.encrypt_use_aes()) { |
| 1301 | // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will | 1321 | // Stream length will be padded with 1 to 16 bytes to end up as a multiple of 16. It will |
| 1302 | // also be prepended by 16 bits of random data. | 1322 | // also be prepended by 16 bits of random data. |
| 1303 | length += 32 - (length & 0xf); | 1323 | length += 32 - (length & 0xf); |
| 1304 | } | 1324 | } |
| 1305 | } | 1325 | } |
| 1306 | 1326 | ||
| 1307 | -QPDFWriter::Members& | ||
| 1308 | -QPDFWriter::Members::write_encrypted(std::string_view str) | 1327 | +impl::Writer& |
| 1328 | +impl::Writer::write_encrypted(std::string_view str) | ||
| 1309 | { | 1329 | { |
| 1310 | if (!(encryption && !cur_data_key.empty())) { | 1330 | if (!(encryption && !cur_data_key.empty())) { |
| 1311 | write(str); | 1331 | write(str); |
| 1312 | - } else if (encrypt_use_aes) { | 1332 | + } else if (cfg.encrypt_use_aes()) { |
| 1313 | write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key)); | 1333 | write(pl::pipe<Pl_AES_PDF>(str, true, cur_data_key)); |
| 1314 | } else { | 1334 | } else { |
| 1315 | write(pl::pipe<Pl_RC4>(str, cur_data_key)); | 1335 | write(pl::pipe<Pl_RC4>(str, cur_data_key)); |
| @@ -1319,7 +1339,7 @@ QPDFWriter::Members::write_encrypted(std::string_view str) | @@ -1319,7 +1339,7 @@ QPDFWriter::Members::write_encrypted(std::string_view str) | ||
| 1319 | } | 1339 | } |
| 1320 | 1340 | ||
| 1321 | void | 1341 | void |
| 1322 | -QPDFWriter::Members::computeDeterministicIDData() | 1342 | +impl::Writer::computeDeterministicIDData() |
| 1323 | { | 1343 | { |
| 1324 | if (!id2.empty()) { | 1344 | if (!id2.empty()) { |
| 1325 | // Can't happen in the code | 1345 | // Can't happen in the code |
| @@ -1331,7 +1351,7 @@ QPDFWriter::Members::computeDeterministicIDData() | @@ -1331,7 +1351,7 @@ QPDFWriter::Members::computeDeterministicIDData() | ||
| 1331 | } | 1351 | } |
| 1332 | 1352 | ||
| 1333 | int | 1353 | int |
| 1334 | -QPDFWriter::Members::openObject(int objid) | 1354 | +impl::Writer::openObject(int objid) |
| 1335 | { | 1355 | { |
| 1336 | if (objid == 0) { | 1356 | if (objid == 0) { |
| 1337 | objid = next_objid++; | 1357 | objid = next_objid++; |
| @@ -1342,7 +1362,7 @@ QPDFWriter::Members::openObject(int objid) | @@ -1342,7 +1362,7 @@ QPDFWriter::Members::openObject(int objid) | ||
| 1342 | } | 1362 | } |
| 1343 | 1363 | ||
| 1344 | void | 1364 | void |
| 1345 | -QPDFWriter::Members::closeObject(int objid) | 1365 | +impl::Writer::closeObject(int objid) |
| 1346 | { | 1366 | { |
| 1347 | // Write a newline before endobj as it makes the file easier to repair. | 1367 | // Write a newline before endobj as it makes the file easier to repair. |
| 1348 | write("\nendobj\n").write_qdf("\n"); | 1368 | write("\nendobj\n").write_qdf("\n"); |
| @@ -1351,7 +1371,7 @@ QPDFWriter::Members::closeObject(int objid) | @@ -1351,7 +1371,7 @@ QPDFWriter::Members::closeObject(int objid) | ||
| 1351 | } | 1371 | } |
| 1352 | 1372 | ||
| 1353 | void | 1373 | void |
| 1354 | -QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og) | 1374 | +impl::Writer::assignCompressedObjectNumbers(QPDFObjGen og) |
| 1355 | { | 1375 | { |
| 1356 | int objid = og.getObj(); | 1376 | int objid = og.getObj(); |
| 1357 | if (og.getGen() != 0 || !object_stream_to_objects.contains(objid)) { | 1377 | if (og.getGen() != 0 || !object_stream_to_objects.contains(objid)) { |
| @@ -1366,7 +1386,7 @@ QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og) | @@ -1366,7 +1386,7 @@ QPDFWriter::Members::assignCompressedObjectNumbers(QPDFObjGen og) | ||
| 1366 | } | 1386 | } |
| 1367 | 1387 | ||
| 1368 | void | 1388 | void |
| 1369 | -QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | 1389 | +impl::Writer::enqueue(QPDFObjectHandle const& object) |
| 1370 | { | 1390 | { |
| 1371 | if (object.indirect()) { | 1391 | if (object.indirect()) { |
| 1372 | util::assertion( | 1392 | util::assertion( |
| @@ -1380,7 +1400,7 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | @@ -1380,7 +1400,7 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | ||
| 1380 | "Use QPDF::copyForeignObject to add objects from another file." // | 1400 | "Use QPDF::copyForeignObject to add objects from another file." // |
| 1381 | ); | 1401 | ); |
| 1382 | 1402 | ||
| 1383 | - if (qdf_mode && object.isStreamOfType("/XRef")) { | 1403 | + if (cfg.qdf() && object.isStreamOfType("/XRef")) { |
| 1384 | // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so | 1404 | // As a special case, do not output any extraneous XRef streams in QDF mode. Doing so |
| 1385 | // will confuse fix-qdf, which expects to see only one XRef stream at the end of the | 1405 | // will confuse fix-qdf, which expects to see only one XRef stream at the end of the |
| 1386 | // file. This case can occur when creating a QDF from a file with object streams when | 1406 | // file. This case can occur when creating a QDF from a file with object streams when |
| @@ -1406,10 +1426,10 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | @@ -1406,10 +1426,10 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | ||
| 1406 | if (og.getGen() == 0 && object_stream_to_objects.contains(og.getObj())) { | 1426 | if (og.getGen() == 0 && object_stream_to_objects.contains(og.getObj())) { |
| 1407 | // For linearized files, uncompressed objects go at end, and we take care of | 1427 | // For linearized files, uncompressed objects go at end, and we take care of |
| 1408 | // assigning numbers to them elsewhere. | 1428 | // assigning numbers to them elsewhere. |
| 1409 | - if (!linearized) { | 1429 | + if (!cfg.linearize()) { |
| 1410 | assignCompressedObjectNumbers(og); | 1430 | assignCompressedObjectNumbers(og); |
| 1411 | } | 1431 | } |
| 1412 | - } else if (!direct_stream_lengths && object.isStream()) { | 1432 | + } else if (!cfg.direct_stream_lengths() && object.isStream()) { |
| 1413 | // reserve next object ID for length | 1433 | // reserve next object ID for length |
| 1414 | ++next_objid; | 1434 | ++next_objid; |
| 1415 | } | 1435 | } |
| @@ -1418,7 +1438,7 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | @@ -1418,7 +1438,7 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | ||
| 1418 | return; | 1438 | return; |
| 1419 | } | 1439 | } |
| 1420 | 1440 | ||
| 1421 | - if (linearized) { | 1441 | + if (cfg.linearize()) { |
| 1422 | return; | 1442 | return; |
| 1423 | } | 1443 | } |
| 1424 | 1444 | ||
| @@ -1437,9 +1457,9 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | @@ -1437,9 +1457,9 @@ QPDFWriter::Members::enqueue(QPDFObjectHandle const& object) | ||
| 1437 | } | 1457 | } |
| 1438 | 1458 | ||
| 1439 | void | 1459 | void |
| 1440 | -QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) | 1460 | +impl::Writer::unparseChild(QPDFObjectHandle const& child, size_t level, int flags) |
| 1441 | { | 1461 | { |
| 1442 | - if (!linearized) { | 1462 | + if (!cfg.linearize()) { |
| 1443 | enqueue(child); | 1463 | enqueue(child); |
| 1444 | } | 1464 | } |
| 1445 | if (child.indirect()) { | 1465 | if (child.indirect()) { |
| @@ -1450,7 +1470,7 @@ QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, i | @@ -1450,7 +1470,7 @@ QPDFWriter::Members::unparseChild(QPDFObjectHandle const& child, size_t level, i | ||
| 1450 | } | 1470 | } |
| 1451 | 1471 | ||
| 1452 | void | 1472 | void |
| 1453 | -QPDFWriter::Members::writeTrailer( | 1473 | +impl::Writer::writeTrailer( |
| 1454 | trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) | 1474 | trailer_e which, int size, bool xref_stream, qpdf_offset_t prev, int linearization_pass) |
| 1455 | { | 1475 | { |
| 1456 | auto trailer = trimmed_trailer(); | 1476 | auto trailer = trimmed_trailer(); |
| @@ -1498,7 +1518,7 @@ QPDFWriter::Members::writeTrailer( | @@ -1498,7 +1518,7 @@ QPDFWriter::Members::writeTrailer( | ||
| 1498 | } | 1518 | } |
| 1499 | write("<00000000000000000000000000000000>"); | 1519 | write("<00000000000000000000000000000000>"); |
| 1500 | } else { | 1520 | } else { |
| 1501 | - if (linearization_pass == 0 && deterministic_id) { | 1521 | + if (linearization_pass == 0 && cfg.deterministic_id()) { |
| 1502 | computeDeterministicIDData(); | 1522 | computeDeterministicIDData(); |
| 1503 | } | 1523 | } |
| 1504 | generateID(encryption.get()); | 1524 | generateID(encryption.get()); |
| @@ -1517,7 +1537,7 @@ QPDFWriter::Members::writeTrailer( | @@ -1517,7 +1537,7 @@ QPDFWriter::Members::writeTrailer( | ||
| 1517 | } | 1537 | } |
| 1518 | 1538 | ||
| 1519 | bool | 1539 | bool |
| 1520 | -QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream) | 1540 | +impl::Writer::will_filter_stream(QPDFObjectHandle stream) |
| 1521 | { | 1541 | { |
| 1522 | std::string s; | 1542 | std::string s; |
| 1523 | [[maybe_unused]] auto [filter, ignore1, ignore2] = will_filter_stream(stream, &s); | 1543 | [[maybe_unused]] auto [filter, ignore1, ignore2] = will_filter_stream(stream, &s); |
| @@ -1525,23 +1545,23 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream) | @@ -1525,23 +1545,23 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream) | ||
| 1525 | } | 1545 | } |
| 1526 | 1546 | ||
| 1527 | std::tuple<const bool, const bool, const bool> | 1547 | std::tuple<const bool, const bool, const bool> |
| 1528 | -QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* stream_data) | 1548 | +impl::Writer::will_filter_stream(QPDFObjectHandle stream, std::string* stream_data) |
| 1529 | { | 1549 | { |
| 1530 | const bool is_root_metadata = stream.isRootMetadata(); | 1550 | const bool is_root_metadata = stream.isRootMetadata(); |
| 1531 | bool filter = false; | 1551 | bool filter = false; |
| 1532 | - auto decode_level = stream_decode_level; | 1552 | + auto decode_level = cfg.decode_level(); |
| 1533 | int encode_flags = 0; | 1553 | int encode_flags = 0; |
| 1534 | Dictionary stream_dict = stream.getDict(); | 1554 | Dictionary stream_dict = stream.getDict(); |
| 1535 | 1555 | ||
| 1536 | if (stream.getFilterOnWrite()) { | 1556 | if (stream.getFilterOnWrite()) { |
| 1537 | - filter = stream.isDataModified() || compress_streams || decode_level != qpdf_dl_none; | ||
| 1538 | - if (compress_streams) { | 1557 | + filter = stream.isDataModified() || cfg.compress_streams() || decode_level != qpdf_dl_none; |
| 1558 | + if (cfg.compress_streams()) { | ||
| 1539 | // Don't filter if the stream is already compressed with FlateDecode. This way we don't | 1559 | // Don't filter if the stream is already compressed with FlateDecode. This way we don't |
| 1540 | // make it worse if the original file used a better Flate algorithm, and we don't spend | 1560 | // make it worse if the original file used a better Flate algorithm, and we don't spend |
| 1541 | // time and CPU cycles uncompressing and recompressing stuff. This can be overridden | 1561 | // time and CPU cycles uncompressing and recompressing stuff. This can be overridden |
| 1542 | // with setRecompressFlate(true). | 1562 | // with setRecompressFlate(true). |
| 1543 | Name Filter = stream_dict["/Filter"]; | 1563 | Name Filter = stream_dict["/Filter"]; |
| 1544 | - if (Filter && !recompress_flate && !stream.isDataModified() && | 1564 | + if (Filter && !cfg.recompress_flate() && !stream.isDataModified() && |
| 1545 | (Filter == "/FlateDecode" || Filter == "/Fl")) { | 1565 | (Filter == "/FlateDecode" || Filter == "/Fl")) { |
| 1546 | filter = false; | 1566 | filter = false; |
| 1547 | } | 1567 | } |
| @@ -1549,10 +1569,10 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* st | @@ -1549,10 +1569,10 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* st | ||
| 1549 | if (is_root_metadata && (!encryption || !encryption->getEncryptMetadata())) { | 1569 | if (is_root_metadata && (!encryption || !encryption->getEncryptMetadata())) { |
| 1550 | filter = true; | 1570 | filter = true; |
| 1551 | decode_level = qpdf_dl_all; | 1571 | decode_level = qpdf_dl_all; |
| 1552 | - } else if (normalize_content && normalized_streams.contains(stream)) { | 1572 | + } else if (cfg.normalize_content() && normalized_streams.contains(stream)) { |
| 1553 | encode_flags = qpdf_ef_normalize; | 1573 | encode_flags = qpdf_ef_normalize; |
| 1554 | filter = true; | 1574 | filter = true; |
| 1555 | - } else if (filter && compress_streams) { | 1575 | + } else if (filter && cfg.compress_streams()) { |
| 1556 | encode_flags = qpdf_ef_compress; | 1576 | encode_flags = qpdf_ef_compress; |
| 1557 | } | 1577 | } |
| 1558 | } | 1578 | } |
| @@ -1598,7 +1618,7 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* st | @@ -1598,7 +1618,7 @@ QPDFWriter::Members::will_filter_stream(QPDFObjectHandle stream, std::string* st | ||
| 1598 | } | 1618 | } |
| 1599 | 1619 | ||
| 1600 | void | 1620 | void |
| 1601 | -QPDFWriter::Members::unparseObject( | 1621 | +impl::Writer::unparseObject( |
| 1602 | QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) | 1622 | QPDFObjectHandle object, size_t level, int flags, size_t stream_length, bool compress) |
| 1603 | { | 1623 | { |
| 1604 | QPDFObjGen old_og = object.getObjGen(); | 1624 | QPDFObjGen old_og = object.getObjGen(); |
| @@ -1606,11 +1626,11 @@ QPDFWriter::Members::unparseObject( | @@ -1606,11 +1626,11 @@ QPDFWriter::Members::unparseObject( | ||
| 1606 | // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they | 1626 | // For non-qdf, "indent" and "indent_large" are a single space between tokens. For qdf, they |
| 1607 | // include the preceding newline. | 1627 | // include the preceding newline. |
| 1608 | std::string indent_large = " "; | 1628 | std::string indent_large = " "; |
| 1609 | - if (qdf_mode) { | 1629 | + if (cfg.qdf()) { |
| 1610 | indent_large.append(2 * (level + 1), ' '); | 1630 | indent_large.append(2 * (level + 1), ' '); |
| 1611 | indent_large[0] = '\n'; | 1631 | indent_large[0] = '\n'; |
| 1612 | } | 1632 | } |
| 1613 | - std::string_view indent{indent_large.data(), qdf_mode ? indent_large.size() - 2 : 1}; | 1633 | + std::string_view indent{indent_large.data(), cfg.qdf() ? indent_large.size() - 2 : 1}; |
| 1614 | 1634 | ||
| 1615 | if (auto const tc = object.getTypeCode(); tc == ::ot_array) { | 1635 | if (auto const tc = object.getTypeCode(); tc == ::ot_array) { |
| 1616 | // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the | 1636 | // Note: PDF spec 1.4 implementation note 121 states that Acrobat requires a space after the |
| @@ -1666,7 +1686,7 @@ QPDFWriter::Members::unparseObject( | @@ -1666,7 +1686,7 @@ QPDFWriter::Members::unparseObject( | ||
| 1666 | if (need_extensions_adbe) { | 1686 | if (need_extensions_adbe) { |
| 1667 | if (!(have_extensions_other || have_extensions_adbe)) { | 1687 | if (!(have_extensions_other || have_extensions_adbe)) { |
| 1668 | // We need Extensions and don't have it. Create it here. | 1688 | // We need Extensions and don't have it. Create it here. |
| 1669 | - QTC::TC("qpdf", "QPDFWriter create Extensions", qdf_mode ? 0 : 1); | 1689 | + QTC::TC("qpdf", "QPDFWriter create Extensions", cfg.qdf() ? 0 : 1); |
| 1670 | extensions = object.replaceKeyAndGetNew( | 1690 | extensions = object.replaceKeyAndGetNew( |
| 1671 | "/Extensions", QPDFObjectHandle::newDictionary()); | 1691 | "/Extensions", QPDFObjectHandle::newDictionary()); |
| 1672 | } | 1692 | } |
| @@ -1771,7 +1791,7 @@ QPDFWriter::Members::unparseObject( | @@ -1771,7 +1791,7 @@ QPDFWriter::Members::unparseObject( | ||
| 1771 | if (flags & f_stream) { | 1791 | if (flags & f_stream) { |
| 1772 | write(indent_large).write("/Length "); | 1792 | write(indent_large).write("/Length "); |
| 1773 | 1793 | ||
| 1774 | - if (direct_stream_lengths) { | 1794 | + if (cfg.direct_stream_lengths()) { |
| 1775 | write(stream_length); | 1795 | write(stream_length); |
| 1776 | } else { | 1796 | } else { |
| 1777 | write(cur_stream_length_id).write(" 0 R"); | 1797 | write(cur_stream_length_id).write(" 0 R"); |
| @@ -1784,7 +1804,7 @@ QPDFWriter::Members::unparseObject( | @@ -1784,7 +1804,7 @@ QPDFWriter::Members::unparseObject( | ||
| 1784 | write(indent).write(">>"); | 1804 | write(indent).write(">>"); |
| 1785 | } else if (tc == ::ot_stream) { | 1805 | } else if (tc == ::ot_stream) { |
| 1786 | // Write stream data to a buffer. | 1806 | // Write stream data to a buffer. |
| 1787 | - if (!direct_stream_lengths) { | 1807 | + if (!cfg.direct_stream_lengths()) { |
| 1788 | cur_stream_length_id = obj[old_og].renumber + 1; | 1808 | cur_stream_length_id = obj[old_og].renumber + 1; |
| 1789 | } | 1809 | } |
| 1790 | 1810 | ||
| @@ -1805,14 +1825,14 @@ QPDFWriter::Members::unparseObject( | @@ -1805,14 +1825,14 @@ QPDFWriter::Members::unparseObject( | ||
| 1805 | unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream); | 1825 | unparseObject(stream_dict, 0, flags, cur_stream_length, compress_stream); |
| 1806 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); | 1826 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); |
| 1807 | write("\nstream\n").write_encrypted(stream_data); | 1827 | write("\nstream\n").write_encrypted(stream_data); |
| 1808 | - added_newline = newline_before_endstream || (qdf_mode && last_char != '\n'); | 1828 | + added_newline = cfg.newline_before_endstream() || (cfg.qdf() && last_char != '\n'); |
| 1809 | write(added_newline ? "\nendstream" : "endstream"); | 1829 | write(added_newline ? "\nendstream" : "endstream"); |
| 1810 | } else if (tc == ::ot_string) { | 1830 | } else if (tc == ::ot_string) { |
| 1811 | std::string val; | 1831 | std::string val; |
| 1812 | if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && | 1832 | if (encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && |
| 1813 | !cur_data_key.empty()) { | 1833 | !cur_data_key.empty()) { |
| 1814 | val = object.getStringValue(); | 1834 | val = object.getStringValue(); |
| 1815 | - if (encrypt_use_aes) { | 1835 | + if (cfg.encrypt_use_aes()) { |
| 1816 | Pl_Buffer bufpl("encrypted string"); | 1836 | Pl_Buffer bufpl("encrypted string"); |
| 1817 | Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key); | 1837 | Pl_AES_PDF pl("aes encrypt string", &bufpl, true, cur_data_key); |
| 1818 | pl.writeString(val); | 1838 | pl.writeString(val); |
| @@ -1841,7 +1861,7 @@ QPDFWriter::Members::unparseObject( | @@ -1841,7 +1861,7 @@ QPDFWriter::Members::unparseObject( | ||
| 1841 | } | 1861 | } |
| 1842 | 1862 | ||
| 1843 | void | 1863 | void |
| 1844 | -QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj) | 1864 | +impl::Writer::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets, int first_obj) |
| 1845 | { | 1865 | { |
| 1846 | qpdf_assert_debug(first_obj > 0); | 1866 | qpdf_assert_debug(first_obj > 0); |
| 1847 | bool is_first = true; | 1867 | bool is_first = true; |
| @@ -1860,7 +1880,7 @@ QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offset | @@ -1860,7 +1880,7 @@ QPDFWriter::Members::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offset | ||
| 1860 | } | 1880 | } |
| 1861 | 1881 | ||
| 1862 | void | 1882 | void |
| 1863 | -QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | 1883 | +impl::Writer::writeObjectStream(QPDFObjectHandle object) |
| 1864 | { | 1884 | { |
| 1865 | // Note: object might be null if this is a place-holder for an object stream that we are | 1885 | // Note: object might be null if this is a place-holder for an object stream that we are |
| 1866 | // generating from scratch. | 1886 | // generating from scratch. |
| @@ -1878,7 +1898,7 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | @@ -1878,7 +1898,7 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | ||
| 1878 | std::string stream_buffer_pass1; | 1898 | std::string stream_buffer_pass1; |
| 1879 | std::string stream_buffer_pass2; | 1899 | std::string stream_buffer_pass2; |
| 1880 | int first_obj = -1; | 1900 | int first_obj = -1; |
| 1881 | - const bool compressed = compress_streams && !qdf_mode; | 1901 | + const bool compressed = cfg.compress_streams() && !cfg.qdf(); |
| 1882 | { | 1902 | { |
| 1883 | // Pass 1 | 1903 | // Pass 1 |
| 1884 | auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1); | 1904 | auto pp_ostream_pass1 = pipeline_stack.activate(stream_buffer_pass1); |
| @@ -1890,9 +1910,9 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | @@ -1890,9 +1910,9 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | ||
| 1890 | if (first_obj == -1) { | 1910 | if (first_obj == -1) { |
| 1891 | first_obj = new_o; | 1911 | first_obj = new_o; |
| 1892 | } | 1912 | } |
| 1893 | - if (qdf_mode) { | 1913 | + if (cfg.qdf()) { |
| 1894 | write("%% Object stream: object ").write(new_o).write(", index ").write(count); | 1914 | write("%% Object stream: object ").write(new_o).write(", index ").write(count); |
| 1895 | - if (!suppress_original_object_ids) { | 1915 | + if (!cfg.no_original_object_ids()) { |
| 1896 | write("; original object ID: ").write(og.getObj()); | 1916 | write("; original object ID: ").write(og.getObj()); |
| 1897 | // For compatibility, only write the generation if non-zero. While object | 1917 | // For compatibility, only write the generation if non-zero. While object |
| 1898 | // streams only allow objects with generation 0, if we are generating object | 1918 | // streams only allow objects with generation 0, if we are generating object |
| @@ -1968,16 +1988,15 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | @@ -1968,16 +1988,15 @@ QPDFWriter::Members::writeObjectStream(QPDFObjectHandle object) | ||
| 1968 | } | 1988 | } |
| 1969 | } | 1989 | } |
| 1970 | write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); | 1990 | write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); |
| 1991 | + write(cfg.newline_before_endstream() ? "\nendstream" : "endstream"); | ||
| 1971 | if (encryption) { | 1992 | if (encryption) { |
| 1972 | - QTC::TC("qpdf", "QPDFWriter encrypt object stream"); | 1993 | + cur_data_key.clear(); |
| 1973 | } | 1994 | } |
| 1974 | - write(newline_before_endstream ? "\nendstream" : "endstream"); | ||
| 1975 | - cur_data_key.clear(); | ||
| 1976 | closeObject(new_stream_id); | 1995 | closeObject(new_stream_id); |
| 1977 | } | 1996 | } |
| 1978 | 1997 | ||
| 1979 | void | 1998 | void |
| 1980 | -QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_index) | 1999 | +impl::Writer::writeObject(QPDFObjectHandle object, int object_stream_index) |
| 1981 | { | 2000 | { |
| 1982 | QPDFObjGen old_og = object.getObjGen(); | 2001 | QPDFObjGen old_og = object.getObjGen(); |
| 1983 | 2002 | ||
| @@ -1989,7 +2008,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | @@ -1989,7 +2008,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | ||
| 1989 | 2008 | ||
| 1990 | indicateProgress(false, false); | 2009 | indicateProgress(false, false); |
| 1991 | auto new_id = obj[old_og].renumber; | 2010 | auto new_id = obj[old_og].renumber; |
| 1992 | - if (qdf_mode) { | 2011 | + if (cfg.qdf()) { |
| 1993 | if (page_object_to_seq.contains(old_og)) { | 2012 | if (page_object_to_seq.contains(old_og)) { |
| 1994 | write("%% Page ").write(page_object_to_seq[old_og]).write("\n"); | 2013 | write("%% Page ").write(page_object_to_seq[old_og]).write("\n"); |
| 1995 | } | 2014 | } |
| @@ -1998,7 +2017,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | @@ -1998,7 +2017,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | ||
| 1998 | } | 2017 | } |
| 1999 | } | 2018 | } |
| 2000 | if (object_stream_index == -1) { | 2019 | if (object_stream_index == -1) { |
| 2001 | - if (qdf_mode && !suppress_original_object_ids) { | 2020 | + if (cfg.qdf() && !cfg.no_original_object_ids()) { |
| 2002 | write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); | 2021 | write("%% Original object ID: ").write(object.getObjGen().unparse(' ')).write("\n"); |
| 2003 | } | 2022 | } |
| 2004 | openObject(new_id); | 2023 | openObject(new_id); |
| @@ -2011,8 +2030,8 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | @@ -2011,8 +2030,8 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | ||
| 2011 | write("\n"); | 2030 | write("\n"); |
| 2012 | } | 2031 | } |
| 2013 | 2032 | ||
| 2014 | - if (!direct_stream_lengths && object.isStream()) { | ||
| 2015 | - if (qdf_mode) { | 2033 | + if (!cfg.direct_stream_lengths() && object.isStream()) { |
| 2034 | + if (cfg.qdf()) { | ||
| 2016 | if (added_newline) { | 2035 | if (added_newline) { |
| 2017 | write("%QDF: ignore_newline\n"); | 2036 | write("%QDF: ignore_newline\n"); |
| 2018 | } | 2037 | } |
| @@ -2024,7 +2043,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | @@ -2024,7 +2043,7 @@ QPDFWriter::Members::writeObject(QPDFObjectHandle object, int object_stream_inde | ||
| 2024 | } | 2043 | } |
| 2025 | 2044 | ||
| 2026 | std::string | 2045 | std::string |
| 2027 | -QPDFWriter::Members::getOriginalID1() | 2046 | +impl::Writer::getOriginalID1() |
| 2028 | { | 2047 | { |
| 2029 | QPDFObjectHandle trailer = qpdf.getTrailer(); | 2048 | QPDFObjectHandle trailer = qpdf.getTrailer(); |
| 2030 | if (trailer.hasKey("/ID")) { | 2049 | if (trailer.hasKey("/ID")) { |
| @@ -2035,7 +2054,7 @@ QPDFWriter::Members::getOriginalID1() | @@ -2035,7 +2054,7 @@ QPDFWriter::Members::getOriginalID1() | ||
| 2035 | } | 2054 | } |
| 2036 | 2055 | ||
| 2037 | void | 2056 | void |
| 2038 | -QPDFWriter::Members::generateID(bool encrypted) | 2057 | +impl::Writer::generateID(bool encrypted) |
| 2039 | { | 2058 | { |
| 2040 | // Generate the ID lazily so that we can handle the user's preference to use static or | 2059 | // Generate the ID lazily so that we can handle the user's preference to use static or |
| 2041 | // deterministic ID generation. | 2060 | // deterministic ID generation. |
| @@ -2048,7 +2067,7 @@ QPDFWriter::Members::generateID(bool encrypted) | @@ -2048,7 +2067,7 @@ QPDFWriter::Members::generateID(bool encrypted) | ||
| 2048 | 2067 | ||
| 2049 | std::string result; | 2068 | std::string result; |
| 2050 | 2069 | ||
| 2051 | - if (static_id) { | 2070 | + if (cfg.static_id()) { |
| 2052 | // For test suite use only... | 2071 | // For test suite use only... |
| 2053 | static unsigned char tmp[] = { | 2072 | static unsigned char tmp[] = { |
| 2054 | 0x31, | 2073 | 0x31, |
| @@ -2080,7 +2099,7 @@ QPDFWriter::Members::generateID(bool encrypted) | @@ -2080,7 +2099,7 @@ QPDFWriter::Members::generateID(bool encrypted) | ||
| 2080 | // that case, would have the same ID regardless of the output file's name. | 2099 | // that case, would have the same ID regardless of the output file's name. |
| 2081 | 2100 | ||
| 2082 | std::string seed; | 2101 | std::string seed; |
| 2083 | - if (deterministic_id) { | 2102 | + if (cfg.deterministic_id()) { |
| 2084 | if (encrypted) { | 2103 | if (encrypted) { |
| 2085 | throw std::runtime_error( | 2104 | throw std::runtime_error( |
| 2086 | "QPDFWriter: unable to generated a deterministic ID because the file to be " | 2105 | "QPDFWriter: unable to generated a deterministic ID because the file to be " |
| @@ -2125,7 +2144,7 @@ QPDFWriter::Members::generateID(bool encrypted) | @@ -2125,7 +2144,7 @@ QPDFWriter::Members::generateID(bool encrypted) | ||
| 2125 | } | 2144 | } |
| 2126 | 2145 | ||
| 2127 | void | 2146 | void |
| 2128 | -QPDFWriter::Members::initializeSpecialStreams() | 2147 | +impl::Writer::initializeSpecialStreams() |
| 2129 | { | 2148 | { |
| 2130 | // Mark all page content streams in case we are filtering or normalizing. | 2149 | // Mark all page content streams in case we are filtering or normalizing. |
| 2131 | int num = 0; | 2150 | int num = 0; |
| @@ -2150,9 +2169,9 @@ QPDFWriter::Members::initializeSpecialStreams() | @@ -2150,9 +2169,9 @@ QPDFWriter::Members::initializeSpecialStreams() | ||
| 2150 | } | 2169 | } |
| 2151 | 2170 | ||
| 2152 | void | 2171 | void |
| 2153 | -QPDFWriter::Members::preserveObjectStreams() | 2172 | +impl::Writer::preserveObjectStreams() |
| 2154 | { | 2173 | { |
| 2155 | - auto const& xref = getXRefTable(); | 2174 | + auto const& xref = objects.xref_table(); |
| 2156 | // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object | 2175 | // Our object_to_object_stream map has to map ObjGen -> ObjGen since we may be generating object |
| 2157 | // streams out of old objects that have generation numbers greater than zero. However in an | 2176 | // streams out of old objects that have generation numbers greater than zero. However in an |
| 2158 | // existing PDF, all object stream objects and all objects in them must have generation 0 | 2177 | // existing PDF, all object stream objects and all objects in them must have generation 0 |
| @@ -2162,7 +2181,7 @@ QPDFWriter::Members::preserveObjectStreams() | @@ -2162,7 +2181,7 @@ QPDFWriter::Members::preserveObjectStreams() | ||
| 2162 | // objects from being included. | 2181 | // objects from being included. |
| 2163 | auto end = xref.cend(); | 2182 | auto end = xref.cend(); |
| 2164 | obj.streams_empty = true; | 2183 | obj.streams_empty = true; |
| 2165 | - if (preserve_unreferenced_objects) { | 2184 | + if (cfg.preserve_unreferenced()) { |
| 2166 | for (auto iter = xref.cbegin(); iter != end; ++iter) { | 2185 | for (auto iter = xref.cbegin(); iter != end; ++iter) { |
| 2167 | if (iter->second.getType() == 2) { | 2186 | if (iter->second.getType() == 2) { |
| 2168 | // Pdf contains object streams. | 2187 | // Pdf contains object streams. |
| @@ -2177,9 +2196,9 @@ QPDFWriter::Members::preserveObjectStreams() | @@ -2177,9 +2196,9 @@ QPDFWriter::Members::preserveObjectStreams() | ||
| 2177 | if (iter->second.getType() == 2) { | 2196 | if (iter->second.getType() == 2) { |
| 2178 | // Pdf contains object streams. | 2197 | // Pdf contains object streams. |
| 2179 | obj.streams_empty = false; | 2198 | obj.streams_empty = false; |
| 2180 | - auto eligible = getCompressibleObjSet(); | 2199 | + auto eligible = objects.compressible_set(); |
| 2181 | // The object pointed to by iter may be a previous generation, in which case it is | 2200 | // The object pointed to by iter may be a previous generation, in which case it is |
| 2182 | - // removed by getCompressibleObjSet. We need to restart the loop (while the object | 2201 | + // removed by compressible_set. We need to restart the loop (while the object |
| 2183 | // table may contain multiple generations of an object). | 2202 | // table may contain multiple generations of an object). |
| 2184 | for (iter = xref.cbegin(); iter != end; ++iter) { | 2203 | for (iter = xref.cbegin(); iter != end; ++iter) { |
| 2185 | if (iter->second.getType() == 2) { | 2204 | if (iter->second.getType() == 2) { |
| @@ -2198,7 +2217,7 @@ QPDFWriter::Members::preserveObjectStreams() | @@ -2198,7 +2217,7 @@ QPDFWriter::Members::preserveObjectStreams() | ||
| 2198 | } | 2217 | } |
| 2199 | 2218 | ||
| 2200 | void | 2219 | void |
| 2201 | -QPDFWriter::Members::generateObjectStreams() | 2220 | +impl::Writer::generateObjectStreams() |
| 2202 | { | 2221 | { |
| 2203 | // Basic strategy: make a list of objects that can go into an object stream. Then figure out | 2222 | // Basic strategy: make a list of objects that can go into an object stream. Then figure out |
| 2204 | // how many object streams are needed so that we can distribute objects approximately evenly | 2223 | // how many object streams are needed so that we can distribute objects approximately evenly |
| @@ -2208,7 +2227,7 @@ QPDFWriter::Members::generateObjectStreams() | @@ -2208,7 +2227,7 @@ QPDFWriter::Members::generateObjectStreams() | ||
| 2208 | 2227 | ||
| 2209 | // This code doesn't do anything with /Extends. | 2228 | // This code doesn't do anything with /Extends. |
| 2210 | 2229 | ||
| 2211 | - std::vector<QPDFObjGen> eligible = getCompressibleObjGens(); | 2230 | + auto eligible = objects.compressible_vector(); |
| 2212 | size_t n_object_streams = (eligible.size() + 99U) / 100U; | 2231 | size_t n_object_streams = (eligible.size() + 99U) / 100U; |
| 2213 | 2232 | ||
| 2214 | initializeTables(2U * n_object_streams); | 2233 | initializeTables(2U * n_object_streams); |
| @@ -2237,7 +2256,7 @@ QPDFWriter::Members::generateObjectStreams() | @@ -2237,7 +2256,7 @@ QPDFWriter::Members::generateObjectStreams() | ||
| 2237 | } | 2256 | } |
| 2238 | 2257 | ||
| 2239 | Dictionary | 2258 | Dictionary |
| 2240 | -QPDFWriter::Members::trimmed_trailer() | 2259 | +impl::Writer::trimmed_trailer() |
| 2241 | { | 2260 | { |
| 2242 | // Remove keys from the trailer that necessarily have to be replaced when writing the file. | 2261 | // Remove keys from the trailer that necessarily have to be replaced when writing the file. |
| 2243 | 2262 | ||
| @@ -2264,7 +2283,7 @@ QPDFWriter::Members::trimmed_trailer() | @@ -2264,7 +2283,7 @@ QPDFWriter::Members::trimmed_trailer() | ||
| 2264 | 2283 | ||
| 2265 | // Make document extension level information direct as required by the spec. | 2284 | // Make document extension level information direct as required by the spec. |
| 2266 | void | 2285 | void |
| 2267 | -QPDFWriter::Members::prepareFileForWrite() | 2286 | +impl::Writer::prepareFileForWrite() |
| 2268 | { | 2287 | { |
| 2269 | qpdf.fixDanglingReferences(); | 2288 | qpdf.fixDanglingReferences(); |
| 2270 | auto root = qpdf.getRoot(); | 2289 | auto root = qpdf.getRoot(); |
| @@ -2287,15 +2306,15 @@ QPDFWriter::Members::prepareFileForWrite() | @@ -2287,15 +2306,15 @@ QPDFWriter::Members::prepareFileForWrite() | ||
| 2287 | } | 2306 | } |
| 2288 | 2307 | ||
| 2289 | void | 2308 | void |
| 2290 | -QPDFWriter::Members::initializeTables(size_t extra) | 2309 | +impl::Writer::initializeTables(size_t extra) |
| 2291 | { | 2310 | { |
| 2292 | - auto size = QIntC::to_size(tableSize() + 100) + extra; | 2311 | + auto size = objects.table_size() + 100u + extra; |
| 2293 | obj.resize(size); | 2312 | obj.resize(size); |
| 2294 | new_obj.resize(size); | 2313 | new_obj.resize(size); |
| 2295 | } | 2314 | } |
| 2296 | 2315 | ||
| 2297 | void | 2316 | void |
| 2298 | -QPDFWriter::Members::doWriteSetup() | 2317 | +impl::Writer::doWriteSetup() |
| 2299 | { | 2318 | { |
| 2300 | if (did_write_setup) { | 2319 | if (did_write_setup) { |
| 2301 | return; | 2320 | return; |
| @@ -2304,63 +2323,42 @@ QPDFWriter::Members::doWriteSetup() | @@ -2304,63 +2323,42 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2304 | 2323 | ||
| 2305 | // Do preliminary setup | 2324 | // Do preliminary setup |
| 2306 | 2325 | ||
| 2307 | - if (linearized) { | ||
| 2308 | - qdf_mode = false; | 2326 | + if (cfg.linearize()) { |
| 2327 | + cfg.qdf(false); | ||
| 2309 | } | 2328 | } |
| 2310 | 2329 | ||
| 2311 | - if (pclm) { | ||
| 2312 | - stream_decode_level = qpdf_dl_none; | ||
| 2313 | - compress_streams = false; | 2330 | + if (cfg.pclm()) { |
| 2314 | encryption = nullptr; | 2331 | encryption = nullptr; |
| 2315 | } | 2332 | } |
| 2316 | 2333 | ||
| 2317 | - if (qdf_mode) { | ||
| 2318 | - if (!normalize_content_set) { | ||
| 2319 | - normalize_content = true; | ||
| 2320 | - } | ||
| 2321 | - if (!compress_streams_set) { | ||
| 2322 | - compress_streams = false; | ||
| 2323 | - } | ||
| 2324 | - if (!stream_decode_level_set) { | ||
| 2325 | - stream_decode_level = qpdf_dl_generalized; | ||
| 2326 | - } | ||
| 2327 | - } | ||
| 2328 | - | ||
| 2329 | if (encryption) { | 2334 | if (encryption) { |
| 2330 | // Encryption has been explicitly set | 2335 | // Encryption has been explicitly set |
| 2331 | - preserve_encryption = false; | ||
| 2332 | - } else if (normalize_content || pclm || qdf_mode) { | 2336 | + cfg.preserve_encryption(false); |
| 2337 | + } else if (cfg.normalize_content() || cfg.pclm()) { | ||
| 2333 | // Encryption makes looking at contents pretty useless. If the user explicitly encrypted | 2338 | // Encryption makes looking at contents pretty useless. If the user explicitly encrypted |
| 2334 | // though, we still obey that. | 2339 | // though, we still obey that. |
| 2335 | - preserve_encryption = false; | 2340 | + cfg.preserve_encryption(false); |
| 2336 | } | 2341 | } |
| 2337 | 2342 | ||
| 2338 | - if (preserve_encryption) { | 2343 | + if (cfg.preserve_encryption()) { |
| 2339 | copyEncryptionParameters(qpdf); | 2344 | copyEncryptionParameters(qpdf); |
| 2340 | } | 2345 | } |
| 2341 | 2346 | ||
| 2342 | - if (!forced_pdf_version.empty()) { | 2347 | + if (!cfg.forced_pdf_version().empty()) { |
| 2343 | int major = 0; | 2348 | int major = 0; |
| 2344 | int minor = 0; | 2349 | int minor = 0; |
| 2345 | - parseVersion(forced_pdf_version, major, minor); | ||
| 2346 | - disableIncompatibleEncryption(major, minor, forced_extension_level); | 2350 | + parseVersion(cfg.forced_pdf_version(), major, minor); |
| 2351 | + disableIncompatibleEncryption(major, minor, cfg.forced_extension_level()); | ||
| 2347 | if (compareVersions(major, minor, 1, 5) < 0) { | 2352 | if (compareVersions(major, minor, 1, 5) < 0) { |
| 2348 | - object_stream_mode = qpdf_o_disable; | 2353 | + cfg.object_streams(qpdf_o_disable); |
| 2349 | } | 2354 | } |
| 2350 | } | 2355 | } |
| 2351 | 2356 | ||
| 2352 | - if (qdf_mode || normalize_content) { | 2357 | + if (cfg.qdf() || cfg.normalize_content()) { |
| 2353 | initializeSpecialStreams(); | 2358 | initializeSpecialStreams(); |
| 2354 | } | 2359 | } |
| 2355 | 2360 | ||
| 2356 | - if (qdf_mode) { | ||
| 2357 | - // Generate indirect stream lengths for qdf mode since fix-qdf uses them for storing | ||
| 2358 | - // recomputed stream length data. Certain streams such as object streams, xref streams, and | ||
| 2359 | - // hint streams always get direct stream lengths. | ||
| 2360 | - direct_stream_lengths = false; | ||
| 2361 | - } | ||
| 2362 | - | ||
| 2363 | - switch (object_stream_mode) { | 2361 | + switch (cfg.object_streams()) { |
| 2364 | case qpdf_o_disable: | 2362 | case qpdf_o_disable: |
| 2365 | initializeTables(); | 2363 | initializeTables(); |
| 2366 | obj.streams_empty = true; | 2364 | obj.streams_empty = true; |
| @@ -2374,12 +2372,10 @@ QPDFWriter::Members::doWriteSetup() | @@ -2374,12 +2372,10 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2374 | case qpdf_o_generate: | 2372 | case qpdf_o_generate: |
| 2375 | generateObjectStreams(); | 2373 | generateObjectStreams(); |
| 2376 | break; | 2374 | break; |
| 2377 | - | ||
| 2378 | - // no default so gcc will warn for missing case tag | ||
| 2379 | } | 2375 | } |
| 2380 | 2376 | ||
| 2381 | if (!obj.streams_empty) { | 2377 | if (!obj.streams_empty) { |
| 2382 | - if (linearized) { | 2378 | + if (cfg.linearize()) { |
| 2383 | // Page dictionaries are not allowed to be compressed objects. | 2379 | // Page dictionaries are not allowed to be compressed objects. |
| 2384 | for (auto& page: pages) { | 2380 | for (auto& page: pages) { |
| 2385 | if (obj[page].object_stream > 0) { | 2381 | if (obj[page].object_stream > 0) { |
| @@ -2388,9 +2384,9 @@ QPDFWriter::Members::doWriteSetup() | @@ -2388,9 +2384,9 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2388 | } | 2384 | } |
| 2389 | } | 2385 | } |
| 2390 | 2386 | ||
| 2391 | - if (linearized || encryption) { | ||
| 2392 | - // The document catalog is not allowed to be compressed in linearized files either. It | ||
| 2393 | - // also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to | 2387 | + if (cfg.linearize() || encryption) { |
| 2388 | + // The document catalog is not allowed to be compressed in cfg.linearized_ files either. | ||
| 2389 | + // It also appears that Adobe Reader 8.0.0 has a bug that prevents it from being able to | ||
| 2394 | // handle encrypted files with compressed document catalogs, so we disable them in that | 2390 | // handle encrypted files with compressed document catalogs, so we disable them in that |
| 2395 | // case as well. | 2391 | // case as well. |
| 2396 | if (obj[root_og].object_stream > 0) { | 2392 | if (obj[root_og].object_stream > 0) { |
| @@ -2413,16 +2409,16 @@ QPDFWriter::Members::doWriteSetup() | @@ -2413,16 +2409,16 @@ QPDFWriter::Members::doWriteSetup() | ||
| 2413 | if (object_stream_to_objects.empty()) { | 2409 | if (object_stream_to_objects.empty()) { |
| 2414 | obj.streams_empty = true; | 2410 | obj.streams_empty = true; |
| 2415 | } else { | 2411 | } else { |
| 2416 | - w.setMinimumPDFVersion("1.5"); | 2412 | + setMinimumPDFVersion("1.5"); |
| 2417 | } | 2413 | } |
| 2418 | } | 2414 | } |
| 2419 | 2415 | ||
| 2420 | setMinimumPDFVersion(qpdf.getPDFVersion(), qpdf.getExtensionLevel()); | 2416 | setMinimumPDFVersion(qpdf.getPDFVersion(), qpdf.getExtensionLevel()); |
| 2421 | final_pdf_version = min_pdf_version; | 2417 | final_pdf_version = min_pdf_version; |
| 2422 | final_extension_level = min_extension_level; | 2418 | final_extension_level = min_extension_level; |
| 2423 | - if (!forced_pdf_version.empty()) { | ||
| 2424 | - final_pdf_version = forced_pdf_version; | ||
| 2425 | - final_extension_level = forced_extension_level; | 2419 | + if (!cfg.forced_pdf_version().empty()) { |
| 2420 | + final_pdf_version = cfg.forced_pdf_version(); | ||
| 2421 | + final_extension_level = cfg.forced_extension_level(); | ||
| 2426 | } | 2422 | } |
| 2427 | } | 2423 | } |
| 2428 | 2424 | ||
| @@ -2433,17 +2429,17 @@ QPDFWriter::write() | @@ -2433,17 +2429,17 @@ QPDFWriter::write() | ||
| 2433 | } | 2429 | } |
| 2434 | 2430 | ||
| 2435 | void | 2431 | void |
| 2436 | -QPDFWriter::Members::write() | 2432 | +impl::Writer::write() |
| 2437 | { | 2433 | { |
| 2438 | doWriteSetup(); | 2434 | doWriteSetup(); |
| 2439 | 2435 | ||
| 2440 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an | 2436 | // Set up progress reporting. For linearized files, we write two passes. events_expected is an |
| 2441 | // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. | 2437 | // approximation, but it's good enough for progress reporting, which is mostly a guess anyway. |
| 2442 | - events_expected = QIntC::to_int(qpdf.getObjectCount() * (linearized ? 2 : 1)); | 2438 | + events_expected = QIntC::to_int(qpdf.getObjectCount() * (cfg.linearize() ? 2 : 1)); |
| 2443 | 2439 | ||
| 2444 | prepareFileForWrite(); | 2440 | prepareFileForWrite(); |
| 2445 | 2441 | ||
| 2446 | - if (linearized) { | 2442 | + if (cfg.linearize()) { |
| 2447 | writeLinearized(); | 2443 | writeLinearized(); |
| 2448 | } else { | 2444 | } else { |
| 2449 | writeStandard(); | 2445 | writeStandard(); |
| @@ -2474,7 +2470,7 @@ QPDFWriter::getWrittenXRefTable() | @@ -2474,7 +2470,7 @@ QPDFWriter::getWrittenXRefTable() | ||
| 2474 | } | 2470 | } |
| 2475 | 2471 | ||
| 2476 | std::map<QPDFObjGen, QPDFXRefEntry> | 2472 | std::map<QPDFObjGen, QPDFXRefEntry> |
| 2477 | -QPDFWriter::Members::getWrittenXRefTable() | 2473 | +impl::Writer::getWrittenXRefTable() |
| 2478 | { | 2474 | { |
| 2479 | std::map<QPDFObjGen, QPDFXRefEntry> result; | 2475 | std::map<QPDFObjGen, QPDFXRefEntry> result; |
| 2480 | 2476 | ||
| @@ -2488,7 +2484,7 @@ QPDFWriter::Members::getWrittenXRefTable() | @@ -2488,7 +2484,7 @@ QPDFWriter::Members::getWrittenXRefTable() | ||
| 2488 | } | 2484 | } |
| 2489 | 2485 | ||
| 2490 | void | 2486 | void |
| 2491 | -QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part) | 2487 | +impl::Writer::enqueuePart(std::vector<QPDFObjectHandle>& part) |
| 2492 | { | 2488 | { |
| 2493 | for (auto const& oh: part) { | 2489 | for (auto const& oh: part) { |
| 2494 | enqueue(oh); | 2490 | enqueue(oh); |
| @@ -2496,7 +2492,7 @@ QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part) | @@ -2496,7 +2492,7 @@ QPDFWriter::Members::enqueuePart(std::vector<QPDFObjectHandle>& part) | ||
| 2496 | } | 2492 | } |
| 2497 | 2493 | ||
| 2498 | void | 2494 | void |
| 2499 | -QPDFWriter::Members::writeEncryptionDictionary() | 2495 | +impl::Writer::writeEncryptionDictionary() |
| 2500 | { | 2496 | { |
| 2501 | encryption_dict_objid = openObject(encryption_dict_objid); | 2497 | encryption_dict_objid = openObject(encryption_dict_objid); |
| 2502 | auto& enc = *encryption; | 2498 | auto& enc = *encryption; |
| @@ -2505,10 +2501,10 @@ QPDFWriter::Members::writeEncryptionDictionary() | @@ -2505,10 +2501,10 @@ QPDFWriter::Members::writeEncryptionDictionary() | ||
| 2505 | write("<<"); | 2501 | write("<<"); |
| 2506 | if (V >= 4) { | 2502 | if (V >= 4) { |
| 2507 | write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); | 2503 | write(" /CF << /StdCF << /AuthEvent /DocOpen /CFM "); |
| 2508 | - write(encrypt_use_aes ? (V < 5 ? "/AESV2" : "/AESV3") : "/V2"); | 2504 | + write(cfg.encrypt_use_aes() ? (V < 5 ? "/AESV2" : "/AESV3") : "/V2"); |
| 2509 | // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of | 2505 | // The PDF spec says the /Length key is optional, but the PDF previewer on some versions of |
| 2510 | // MacOS won't open encrypted files without it. | 2506 | // MacOS won't open encrypted files without it. |
| 2511 | - write((V < 5) ? " /Length 16 >> >>" : " /Length 32 >> >>"); | 2507 | + write(V < 5 ? " /Length 16 >> >>" : " /Length 32 >> >>"); |
| 2512 | if (!encryption->getEncryptMetadata()) { | 2508 | if (!encryption->getEncryptMetadata()) { |
| 2513 | write(" /EncryptMetadata false"); | 2509 | write(" /EncryptMetadata false"); |
| 2514 | } | 2510 | } |
| @@ -2543,10 +2539,10 @@ QPDFWriter::getFinalVersion() | @@ -2543,10 +2539,10 @@ QPDFWriter::getFinalVersion() | ||
| 2543 | } | 2539 | } |
| 2544 | 2540 | ||
| 2545 | void | 2541 | void |
| 2546 | -QPDFWriter::Members::writeHeader() | 2542 | +impl::Writer::writeHeader() |
| 2547 | { | 2543 | { |
| 2548 | write("%PDF-").write(final_pdf_version); | 2544 | write("%PDF-").write(final_pdf_version); |
| 2549 | - if (pclm) { | 2545 | + if (cfg.pclm()) { |
| 2550 | // PCLm version | 2546 | // PCLm version |
| 2551 | write("\n%PCLm 1.0\n"); | 2547 | write("\n%PCLm 1.0\n"); |
| 2552 | } else { | 2548 | } else { |
| @@ -2563,13 +2559,13 @@ QPDFWriter::Members::writeHeader() | @@ -2563,13 +2559,13 @@ QPDFWriter::Members::writeHeader() | ||
| 2563 | } | 2559 | } |
| 2564 | 2560 | ||
| 2565 | void | 2561 | void |
| 2566 | -QPDFWriter::Members::writeHintStream(int hint_id) | 2562 | +impl::Writer::writeHintStream(int hint_id) |
| 2567 | { | 2563 | { |
| 2568 | std::string hint_buffer; | 2564 | std::string hint_buffer; |
| 2569 | int S = 0; | 2565 | int S = 0; |
| 2570 | int O = 0; | 2566 | int O = 0; |
| 2571 | - bool compressed = compress_streams; | ||
| 2572 | - generateHintStream(new_obj, obj, hint_buffer, S, O, compressed); | 2567 | + bool compressed = cfg.compress_streams(); |
| 2568 | + lin.generateHintStream(new_obj, obj, hint_buffer, S, O, compressed); | ||
| 2573 | 2569 | ||
| 2574 | openObject(hint_id); | 2570 | openObject(hint_id); |
| 2575 | setDataKey(hint_id); | 2571 | setDataKey(hint_id); |
| @@ -2597,7 +2593,7 @@ QPDFWriter::Members::writeHintStream(int hint_id) | @@ -2597,7 +2593,7 @@ QPDFWriter::Members::writeHintStream(int hint_id) | ||
| 2597 | } | 2593 | } |
| 2598 | 2594 | ||
| 2599 | qpdf_offset_t | 2595 | qpdf_offset_t |
| 2600 | -QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int size) | 2596 | +impl::Writer::writeXRefTable(trailer_e which, int first, int last, int size) |
| 2601 | { | 2597 | { |
| 2602 | // There are too many extra arguments to replace overloaded function with defaults in the header | 2598 | // There are too many extra arguments to replace overloaded function with defaults in the header |
| 2603 | // file...too much risk of leaving something off. | 2599 | // file...too much risk of leaving something off. |
| @@ -2605,7 +2601,7 @@ QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int si | @@ -2605,7 +2601,7 @@ QPDFWriter::Members::writeXRefTable(trailer_e which, int first, int last, int si | ||
| 2605 | } | 2601 | } |
| 2606 | 2602 | ||
| 2607 | qpdf_offset_t | 2603 | qpdf_offset_t |
| 2608 | -QPDFWriter::Members::writeXRefTable( | 2604 | +impl::Writer::writeXRefTable( |
| 2609 | trailer_e which, | 2605 | trailer_e which, |
| 2610 | int first, | 2606 | int first, |
| 2611 | int last, | 2607 | int last, |
| @@ -2640,7 +2636,7 @@ QPDFWriter::Members::writeXRefTable( | @@ -2640,7 +2636,7 @@ QPDFWriter::Members::writeXRefTable( | ||
| 2640 | } | 2636 | } |
| 2641 | 2637 | ||
| 2642 | qpdf_offset_t | 2638 | qpdf_offset_t |
| 2643 | -QPDFWriter::Members::writeXRefStream( | 2639 | +impl::Writer::writeXRefStream( |
| 2644 | int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) | 2640 | int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size) |
| 2645 | { | 2641 | { |
| 2646 | // There are too many extra arguments to replace overloaded function with defaults in the header | 2642 | // There are too many extra arguments to replace overloaded function with defaults in the header |
| @@ -2650,7 +2646,7 @@ QPDFWriter::Members::writeXRefStream( | @@ -2650,7 +2646,7 @@ QPDFWriter::Members::writeXRefStream( | ||
| 2650 | } | 2646 | } |
| 2651 | 2647 | ||
| 2652 | qpdf_offset_t | 2648 | qpdf_offset_t |
| 2653 | -QPDFWriter::Members::writeXRefStream( | 2649 | +impl::Writer::writeXRefStream( |
| 2654 | int xref_id, | 2650 | int xref_id, |
| 2655 | int max_id, | 2651 | int max_id, |
| 2656 | qpdf_offset_t max_offset, | 2652 | qpdf_offset_t max_offset, |
| @@ -2681,7 +2677,7 @@ QPDFWriter::Members::writeXRefStream( | @@ -2681,7 +2677,7 @@ QPDFWriter::Members::writeXRefStream( | ||
| 2681 | new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount()); | 2677 | new_obj[xref_id].xref = QPDFXRefEntry(pipeline->getCount()); |
| 2682 | 2678 | ||
| 2683 | std::string xref_data; | 2679 | std::string xref_data; |
| 2684 | - const bool compressed = compress_streams && !qdf_mode; | 2680 | + const bool compressed = cfg.compress_streams() && !cfg.qdf(); |
| 2685 | { | 2681 | { |
| 2686 | auto pp_xref = pipeline_stack.activate(xref_data); | 2682 | auto pp_xref = pipeline_stack.activate(xref_data); |
| 2687 | 2683 | ||
| @@ -2746,7 +2742,7 @@ QPDFWriter::Members::writeXRefStream( | @@ -2746,7 +2742,7 @@ QPDFWriter::Members::writeXRefStream( | ||
| 2746 | } | 2742 | } |
| 2747 | 2743 | ||
| 2748 | size_t | 2744 | size_t |
| 2749 | -QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | 2745 | +impl::Writer::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) |
| 2750 | { | 2746 | { |
| 2751 | // This routine is called right after a linearization first pass xref stream has been written | 2747 | // This routine is called right after a linearization first pass xref stream has been written |
| 2752 | // without compression. Calculate the amount of padding that would be required in the worst | 2748 | // without compression. Calculate the amount of padding that would be required in the worst |
| @@ -2758,7 +2754,7 @@ QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | @@ -2758,7 +2754,7 @@ QPDFWriter::Members::calculateXrefStreamPadding(qpdf_offset_t xref_bytes) | ||
| 2758 | } | 2754 | } |
| 2759 | 2755 | ||
| 2760 | void | 2756 | void |
| 2761 | -QPDFWriter::Members::writeLinearized() | 2757 | +impl::Writer::writeLinearized() |
| 2762 | { | 2758 | { |
| 2763 | // Optimize file and enqueue objects in order | 2759 | // Optimize file and enqueue objects in order |
| 2764 | 2760 | ||
| @@ -2772,14 +2768,14 @@ QPDFWriter::Members::writeLinearized() | @@ -2772,14 +2768,14 @@ QPDFWriter::Members::writeLinearized() | ||
| 2772 | } | 2768 | } |
| 2773 | }; | 2769 | }; |
| 2774 | 2770 | ||
| 2775 | - optimize(obj, skip_stream_parameters); | 2771 | + lin.optimize(obj, skip_stream_parameters); |
| 2776 | 2772 | ||
| 2777 | std::vector<QPDFObjectHandle> part4; | 2773 | std::vector<QPDFObjectHandle> part4; |
| 2778 | std::vector<QPDFObjectHandle> part6; | 2774 | std::vector<QPDFObjectHandle> part6; |
| 2779 | std::vector<QPDFObjectHandle> part7; | 2775 | std::vector<QPDFObjectHandle> part7; |
| 2780 | std::vector<QPDFObjectHandle> part8; | 2776 | std::vector<QPDFObjectHandle> part8; |
| 2781 | std::vector<QPDFObjectHandle> part9; | 2777 | std::vector<QPDFObjectHandle> part9; |
| 2782 | - getLinearizedParts(obj, part4, part6, part7, part8, part9); | 2778 | + lin.parts(obj, part4, part6, part7, part8, part9); |
| 2783 | 2779 | ||
| 2784 | // Object number sequence: | 2780 | // Object number sequence: |
| 2785 | // | 2781 | // |
| @@ -2871,7 +2867,7 @@ QPDFWriter::Members::writeLinearized() | @@ -2871,7 +2867,7 @@ QPDFWriter::Members::writeLinearized() | ||
| 2871 | enqueuePart(part8); | 2867 | enqueuePart(part8); |
| 2872 | enqueuePart(part9); | 2868 | enqueuePart(part9); |
| 2873 | if (next_objid != after_second_half) { | 2869 | if (next_objid != after_second_half) { |
| 2874 | - throw std::runtime_error("error encountered after writing part 9 of linearized data"); | 2870 | + throw std::runtime_error("error encountered after writing part 9 of cfg.linearized_ data"); |
| 2875 | } | 2871 | } |
| 2876 | 2872 | ||
| 2877 | qpdf_offset_t hint_length = 0; | 2873 | qpdf_offset_t hint_length = 0; |
| @@ -2884,15 +2880,15 @@ QPDFWriter::Members::writeLinearized() | @@ -2884,15 +2880,15 @@ QPDFWriter::Members::writeLinearized() | ||
| 2884 | auto pp_md5 = pipeline_stack.popper(); | 2880 | auto pp_md5 = pipeline_stack.popper(); |
| 2885 | for (int pass: {1, 2}) { | 2881 | for (int pass: {1, 2}) { |
| 2886 | if (pass == 1) { | 2882 | if (pass == 1) { |
| 2887 | - if (!lin_pass1_filename.empty()) { | ||
| 2888 | - lin_pass1_file = QUtil::safe_fopen(lin_pass1_filename.c_str(), "wb"); | 2883 | + if (!cfg.linearize_pass1().empty()) { |
| 2884 | + lin_pass1_file = QUtil::safe_fopen(cfg.linearize_pass1().data(), "wb"); | ||
| 2889 | pipeline_stack.activate( | 2885 | pipeline_stack.activate( |
| 2890 | pp_pass1, | 2886 | pp_pass1, |
| 2891 | std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); | 2887 | std::make_unique<Pl_StdioFile>("linearization pass1", lin_pass1_file)); |
| 2892 | } else { | 2888 | } else { |
| 2893 | pipeline_stack.activate(pp_pass1, true); | 2889 | pipeline_stack.activate(pp_pass1, true); |
| 2894 | } | 2890 | } |
| 2895 | - if (deterministic_id) { | 2891 | + if (cfg.deterministic_id()) { |
| 2896 | pipeline_stack.activate_md5(pp_md5); | 2892 | pipeline_stack.activate_md5(pp_md5); |
| 2897 | } | 2893 | } |
| 2898 | } | 2894 | } |
| @@ -2927,7 +2923,7 @@ QPDFWriter::Members::writeLinearized() | @@ -2927,7 +2923,7 @@ QPDFWriter::Members::writeLinearized() | ||
| 2927 | 2923 | ||
| 2928 | // If the user supplied any additional header text, write it here after the linearization | 2924 | // If the user supplied any additional header text, write it here after the linearization |
| 2929 | // parameter dictionary. | 2925 | // parameter dictionary. |
| 2930 | - write(extra_header_text); | 2926 | + write(cfg.extra_header_text()); |
| 2931 | 2927 | ||
| 2932 | // Part 3: first page cross reference table and trailer. | 2928 | // Part 3: first page cross reference table and trailer. |
| 2933 | 2929 | ||
| @@ -3062,7 +3058,7 @@ QPDFWriter::Members::writeLinearized() | @@ -3062,7 +3058,7 @@ QPDFWriter::Members::writeLinearized() | ||
| 3062 | write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); | 3058 | write("startxref\n").write(first_xref_offset).write("\n%%EOF\n"); |
| 3063 | 3059 | ||
| 3064 | if (pass == 1) { | 3060 | if (pass == 1) { |
| 3065 | - if (deterministic_id) { | 3061 | + if (cfg.deterministic_id()) { |
| 3066 | QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); | 3062 | QTC::TC("qpdf", "QPDFWriter linearized deterministic ID", need_xref_stream ? 0 : 1); |
| 3067 | computeDeterministicIDData(); | 3063 | computeDeterministicIDData(); |
| 3068 | pp_md5.pop(); | 3064 | pp_md5.pop(); |
| @@ -3105,9 +3101,9 @@ QPDFWriter::Members::writeLinearized() | @@ -3105,9 +3101,9 @@ QPDFWriter::Members::writeLinearized() | ||
| 3105 | } | 3101 | } |
| 3106 | 3102 | ||
| 3107 | void | 3103 | void |
| 3108 | -QPDFWriter::Members::enqueueObjectsStandard() | 3104 | +impl::Writer::enqueueObjectsStandard() |
| 3109 | { | 3105 | { |
| 3110 | - if (preserve_unreferenced_objects) { | 3106 | + if (cfg.preserve_unreferenced()) { |
| 3111 | for (auto const& oh: qpdf.getAllObjects()) { | 3107 | for (auto const& oh: qpdf.getAllObjects()) { |
| 3112 | enqueue(oh); | 3108 | enqueue(oh); |
| 3113 | } | 3109 | } |
| @@ -3127,7 +3123,7 @@ QPDFWriter::Members::enqueueObjectsStandard() | @@ -3127,7 +3123,7 @@ QPDFWriter::Members::enqueueObjectsStandard() | ||
| 3127 | } | 3123 | } |
| 3128 | 3124 | ||
| 3129 | void | 3125 | void |
| 3130 | -QPDFWriter::Members::enqueueObjectsPCLm() | 3126 | +impl::Writer::enqueueObjectsPCLm() |
| 3131 | { | 3127 | { |
| 3132 | // Image transform stream content for page strip images. Each of this new stream has to come | 3128 | // Image transform stream content for page strip images. Each of this new stream has to come |
| 3133 | // after every page image strip written in the pclm file. | 3129 | // after every page image strip written in the pclm file. |
| @@ -3151,7 +3147,7 @@ QPDFWriter::Members::enqueueObjectsPCLm() | @@ -3151,7 +3147,7 @@ QPDFWriter::Members::enqueueObjectsPCLm() | ||
| 3151 | } | 3147 | } |
| 3152 | 3148 | ||
| 3153 | void | 3149 | void |
| 3154 | -QPDFWriter::Members::indicateProgress(bool decrement, bool finished) | 3150 | +impl::Writer::indicateProgress(bool decrement, bool finished) |
| 3155 | { | 3151 | { |
| 3156 | if (decrement) { | 3152 | if (decrement) { |
| 3157 | --events_seen; | 3153 | --events_seen; |
| @@ -3185,19 +3181,19 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) | @@ -3185,19 +3181,19 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) | ||
| 3185 | } | 3181 | } |
| 3186 | 3182 | ||
| 3187 | void | 3183 | void |
| 3188 | -QPDFWriter::Members::writeStandard() | 3184 | +impl::Writer::writeStandard() |
| 3189 | { | 3185 | { |
| 3190 | auto pp_md5 = pipeline_stack.popper(); | 3186 | auto pp_md5 = pipeline_stack.popper(); |
| 3191 | - if (deterministic_id) { | 3187 | + if (cfg.deterministic_id()) { |
| 3192 | pipeline_stack.activate_md5(pp_md5); | 3188 | pipeline_stack.activate_md5(pp_md5); |
| 3193 | } | 3189 | } |
| 3194 | 3190 | ||
| 3195 | // Start writing | 3191 | // Start writing |
| 3196 | 3192 | ||
| 3197 | writeHeader(); | 3193 | writeHeader(); |
| 3198 | - write(extra_header_text); | 3194 | + write(cfg.extra_header_text()); |
| 3199 | 3195 | ||
| 3200 | - if (pclm) { | 3196 | + if (cfg.pclm()) { |
| 3201 | enqueueObjectsPCLm(); | 3197 | enqueueObjectsPCLm(); |
| 3202 | } else { | 3198 | } else { |
| 3203 | enqueueObjectsStandard(); | 3199 | enqueueObjectsStandard(); |
| @@ -3227,7 +3223,7 @@ QPDFWriter::Members::writeStandard() | @@ -3227,7 +3223,7 @@ QPDFWriter::Members::writeStandard() | ||
| 3227 | } | 3223 | } |
| 3228 | write("startxref\n").write(xref_offset).write("\n%%EOF\n"); | 3224 | write("startxref\n").write(xref_offset).write("\n%%EOF\n"); |
| 3229 | 3225 | ||
| 3230 | - if (deterministic_id) { | 3226 | + if (cfg.deterministic_id()) { |
| 3231 | QTC::TC( | 3227 | QTC::TC( |
| 3232 | "qpdf", | 3228 | "qpdf", |
| 3233 | "QPDFWriter standard deterministic ID", | 3229 | "QPDFWriter standard deterministic ID", |
libqpdf/QPDF_linearization.cc
| @@ -1681,7 +1681,7 @@ Lin::pushOutlinesToPart( | @@ -1681,7 +1681,7 @@ Lin::pushOutlinesToPart( | ||
| 1681 | } | 1681 | } |
| 1682 | 1682 | ||
| 1683 | void | 1683 | void |
| 1684 | -Lin::getLinearizedParts( | 1684 | +Lin::parts( |
| 1685 | QPDFWriter::ObjTable const& obj, | 1685 | QPDFWriter::ObjTable const& obj, |
| 1686 | std::vector<QPDFObjectHandle>& part4, | 1686 | std::vector<QPDFObjectHandle>& part4, |
| 1687 | std::vector<QPDFObjectHandle>& part6, | 1687 | std::vector<QPDFObjectHandle>& part6, |
libqpdf/QPDF_objects.cc
| @@ -1916,7 +1916,7 @@ QPDF::swapObjects(QPDFObjGen og1, QPDFObjGen og2) | @@ -1916,7 +1916,7 @@ QPDF::swapObjects(QPDFObjGen og1, QPDFObjGen og2) | ||
| 1916 | } | 1916 | } |
| 1917 | 1917 | ||
| 1918 | size_t | 1918 | size_t |
| 1919 | -Objects::tableSize() | 1919 | +Objects::table_size() |
| 1920 | { | 1920 | { |
| 1921 | // If obj_cache is dense, accommodate all object in tables,else accommodate only original | 1921 | // If obj_cache is dense, accommodate all object in tables,else accommodate only original |
| 1922 | // objects. | 1922 | // objects. |
| @@ -1936,20 +1936,20 @@ Objects::tableSize() | @@ -1936,20 +1936,20 @@ Objects::tableSize() | ||
| 1936 | } | 1936 | } |
| 1937 | 1937 | ||
| 1938 | std::vector<QPDFObjGen> | 1938 | std::vector<QPDFObjGen> |
| 1939 | -Objects::getCompressibleObjVector() | 1939 | +Objects::compressible_vector() |
| 1940 | { | 1940 | { |
| 1941 | - return getCompressibleObjGens<QPDFObjGen>(); | 1941 | + return compressible<QPDFObjGen>(); |
| 1942 | } | 1942 | } |
| 1943 | 1943 | ||
| 1944 | std::vector<bool> | 1944 | std::vector<bool> |
| 1945 | -Objects::getCompressibleObjSet() | 1945 | +Objects::compressible_set() |
| 1946 | { | 1946 | { |
| 1947 | - return getCompressibleObjGens<bool>(); | 1947 | + return compressible<bool>(); |
| 1948 | } | 1948 | } |
| 1949 | 1949 | ||
| 1950 | template <typename T> | 1950 | template <typename T> |
| 1951 | std::vector<T> | 1951 | std::vector<T> |
| 1952 | -Objects::getCompressibleObjGens() | 1952 | +Objects::compressible() |
| 1953 | { | 1953 | { |
| 1954 | // Return a list of objects that are allowed to be in object streams. Walk through the objects | 1954 | // Return a list of objects that are allowed to be in object streams. Walk through the objects |
| 1955 | // by traversing the document from the root, including a traversal of the pages tree. This | 1955 | // by traversing the document from the root, including a traversal of the pages tree. This |
| @@ -1969,10 +1969,9 @@ Objects::getCompressibleObjGens() | @@ -1969,10 +1969,9 @@ Objects::getCompressibleObjGens() | ||
| 1969 | std::vector<T> result; | 1969 | std::vector<T> result; |
| 1970 | if constexpr (std::is_same_v<T, QPDFObjGen>) { | 1970 | if constexpr (std::is_same_v<T, QPDFObjGen>) { |
| 1971 | result.reserve(m->obj_cache.size()); | 1971 | result.reserve(m->obj_cache.size()); |
| 1972 | - } else if constexpr (std::is_same_v<T, bool>) { | ||
| 1973 | - result.resize(max_obj + 1U, false); | ||
| 1974 | } else { | 1972 | } else { |
| 1975 | - throw std::logic_error("Unsupported type in QPDF::getCompressibleObjGens"); | 1973 | + qpdf_static_expect(std::is_same_v<T, bool>); |
| 1974 | + result.resize(max_obj + 1U, false); | ||
| 1976 | } | 1975 | } |
| 1977 | while (!queue.empty()) { | 1976 | while (!queue.empty()) { |
| 1978 | auto obj = queue.back(); | 1977 | auto obj = queue.back(); |
libqpdf/qpdf/ObjTable.hh
| @@ -75,7 +75,6 @@ class ObjTable: public std::vector<T> | @@ -75,7 +75,6 @@ class ObjTable: public std::vector<T> | ||
| 75 | return contains(static_cast<size_t>(oh.getObjectID())); | 75 | return contains(static_cast<size_t>(oh.getObjectID())); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | - protected: | ||
| 79 | inline T& | 78 | inline T& |
| 80 | operator[](int id) | 79 | operator[](int id) |
| 81 | { | 80 | { |
libqpdf/qpdf/QPDFJob_private.hh
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | 5 | ||
| 6 | #include <qpdf/ClosedFileInputSource.hh> | 6 | #include <qpdf/ClosedFileInputSource.hh> |
| 7 | #include <qpdf/QPDFLogger.hh> | 7 | #include <qpdf/QPDFLogger.hh> |
| 8 | +#include <qpdf/QPDFWriter_private.hh> | ||
| 8 | #include <qpdf/QPDF_private.hh> | 9 | #include <qpdf/QPDF_private.hh> |
| 9 | 10 | ||
| 10 | // A selection of pages from a single input PDF to be included in the output. This corresponds to a | 11 | // A selection of pages from a single input PDF to be included in the output. This corresponds to a |
| @@ -150,7 +151,7 @@ class QPDFJob::Members | @@ -150,7 +151,7 @@ class QPDFJob::Members | ||
| 150 | 151 | ||
| 151 | public: | 152 | public: |
| 152 | Members(QPDFJob& job) : | 153 | Members(QPDFJob& job) : |
| 153 | - log(qcf.log()), | 154 | + log(d_cfg.log()), |
| 154 | inputs(job) | 155 | inputs(job) |
| 155 | { | 156 | { |
| 156 | } | 157 | } |
| @@ -168,14 +169,14 @@ class QPDFJob::Members | @@ -168,14 +169,14 @@ class QPDFJob::Members | ||
| 168 | static int constexpr DEFAULT_OI_MIN_AREA = 16384; | 169 | static int constexpr DEFAULT_OI_MIN_AREA = 16384; |
| 169 | static int constexpr DEFAULT_II_MIN_BYTES = 1024; | 170 | static int constexpr DEFAULT_II_MIN_BYTES = 1024; |
| 170 | 171 | ||
| 171 | - qpdf::Doc::Config qcf; | 172 | + qpdf::Doc::Config d_cfg; |
| 173 | + qpdf::Writer::Config w_cfg; | ||
| 172 | std::shared_ptr<QPDFLogger> log; | 174 | std::shared_ptr<QPDFLogger> log; |
| 173 | std::string message_prefix{"qpdf"}; | 175 | std::string message_prefix{"qpdf"}; |
| 174 | bool warnings{false}; | 176 | bool warnings{false}; |
| 175 | unsigned long encryption_status{0}; | 177 | unsigned long encryption_status{0}; |
| 176 | bool verbose{false}; | 178 | bool verbose{false}; |
| 177 | std::string password; | 179 | std::string password; |
| 178 | - bool linearize{false}; | ||
| 179 | bool decrypt{false}; | 180 | bool decrypt{false}; |
| 180 | bool remove_restrictions{false}; | 181 | bool remove_restrictions{false}; |
| 181 | int split_pages{0}; | 182 | int split_pages{0}; |
| @@ -206,25 +207,9 @@ class QPDFJob::Members | @@ -206,25 +207,9 @@ class QPDFJob::Members | ||
| 206 | bool force_R5{false}; | 207 | bool force_R5{false}; |
| 207 | bool cleartext_metadata{false}; | 208 | bool cleartext_metadata{false}; |
| 208 | bool use_aes{false}; | 209 | bool use_aes{false}; |
| 209 | - bool stream_data_set{false}; | ||
| 210 | - qpdf_stream_data_e stream_data_mode{qpdf_s_compress}; | ||
| 211 | - bool compress_streams{true}; | ||
| 212 | - bool compress_streams_set{false}; | ||
| 213 | - bool recompress_flate{false}; | ||
| 214 | - bool recompress_flate_set{false}; | ||
| 215 | int compression_level{-1}; | 210 | int compression_level{-1}; |
| 216 | int jpeg_quality{-1}; | 211 | int jpeg_quality{-1}; |
| 217 | - qpdf_stream_decode_level_e decode_level{qpdf_dl_generalized}; | ||
| 218 | - bool decode_level_set{false}; | ||
| 219 | - bool normalize_set{false}; | ||
| 220 | - bool normalize{false}; | ||
| 221 | - bool object_stream_set{false}; | ||
| 222 | - qpdf_object_stream_e object_stream_mode{qpdf_o_preserve}; | ||
| 223 | - bool qdf_mode{false}; | ||
| 224 | - bool preserve_unreferenced_objects{false}; | ||
| 225 | remove_unref_e remove_unreferenced_page_resources{re_auto}; | 212 | remove_unref_e remove_unreferenced_page_resources{re_auto}; |
| 226 | - bool newline_before_endstream{false}; | ||
| 227 | - std::string linearize_pass1; | ||
| 228 | bool coalesce_contents{false}; | 213 | bool coalesce_contents{false}; |
| 229 | bool flatten_annotations{false}; | 214 | bool flatten_annotations{false}; |
| 230 | int flatten_annotations_required{0}; | 215 | int flatten_annotations_required{0}; |
| @@ -234,10 +219,7 @@ class QPDFJob::Members | @@ -234,10 +219,7 @@ class QPDFJob::Members | ||
| 234 | std::string min_version; | 219 | std::string min_version; |
| 235 | std::string force_version; | 220 | std::string force_version; |
| 236 | bool show_npages{false}; | 221 | bool show_npages{false}; |
| 237 | - bool deterministic_id{false}; | ||
| 238 | - bool static_id{false}; | ||
| 239 | bool static_aes_iv{false}; | 222 | bool static_aes_iv{false}; |
| 240 | - bool suppress_original_object_id{false}; | ||
| 241 | bool show_encryption{false}; | 223 | bool show_encryption{false}; |
| 242 | bool show_encryption_key{false}; | 224 | bool show_encryption_key{false}; |
| 243 | bool check_linearization{false}; | 225 | bool check_linearization{false}; |
libqpdf/qpdf/QPDFObject_private.hh
| @@ -30,6 +30,11 @@ namespace qpdf | @@ -30,6 +30,11 @@ namespace qpdf | ||
| 30 | class Integer; | 30 | class Integer; |
| 31 | class Name; | 31 | class Name; |
| 32 | class Stream; | 32 | class Stream; |
| 33 | + | ||
| 34 | + namespace impl | ||
| 35 | + { | ||
| 36 | + class Writer; | ||
| 37 | + } | ||
| 33 | } // namespace qpdf | 38 | } // namespace qpdf |
| 34 | 39 | ||
| 35 | class QPDF_Array final | 40 | class QPDF_Array final |
| @@ -256,7 +261,7 @@ class QPDF_String final | @@ -256,7 +261,7 @@ class QPDF_String final | ||
| 256 | { | 261 | { |
| 257 | friend class QPDFObject; | 262 | friend class QPDFObject; |
| 258 | friend class qpdf::BaseHandle; | 263 | friend class qpdf::BaseHandle; |
| 259 | - friend class QPDFWriter; | 264 | + friend class qpdf::impl::Writer; |
| 260 | 265 | ||
| 261 | public: | 266 | public: |
| 262 | static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val); | 267 | static std::shared_ptr<QPDFObject> create_utf16(std::string const& utf8_val); |
libqpdf/qpdf/QPDFWriter_private.hh
| @@ -5,10 +5,332 @@ | @@ -5,10 +5,332 @@ | ||
| 5 | 5 | ||
| 6 | #include <qpdf/ObjTable.hh> | 6 | #include <qpdf/ObjTable.hh> |
| 7 | #include <qpdf/Pipeline_private.hh> | 7 | #include <qpdf/Pipeline_private.hh> |
| 8 | +#include <qpdf/QPDF.hh> | ||
| 9 | +#include <qpdf/QPDFUsage.hh> | ||
| 8 | 10 | ||
| 9 | // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization | 11 | // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization |
| 10 | // only. | 12 | // only. |
| 11 | 13 | ||
| 14 | +namespace qpdf | ||
| 15 | +{ | ||
| 16 | + namespace impl | ||
| 17 | + { | ||
| 18 | + class Writer; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + class Writer: public QPDFWriter | ||
| 22 | + { | ||
| 23 | + public: | ||
| 24 | + class Config | ||
| 25 | + { | ||
| 26 | + public: | ||
| 27 | + Config() = default; | ||
| 28 | + Config(Config const&) = default; | ||
| 29 | + Config(Config&&) = delete; | ||
| 30 | + Config& operator=(Config const&) = default; | ||
| 31 | + Config& operator=(Config&&) = delete; | ||
| 32 | + ~Config() = default; | ||
| 33 | + | ||
| 34 | + Config(bool permissive) : | ||
| 35 | + permissive_(permissive) | ||
| 36 | + { | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + bool | ||
| 40 | + linearize() const | ||
| 41 | + { | ||
| 42 | + return linearize_; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + Config& linearize(bool val); | ||
| 46 | + | ||
| 47 | + std::string const& | ||
| 48 | + linearize_pass1() const | ||
| 49 | + { | ||
| 50 | + return linearize_pass1_; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + Config& | ||
| 54 | + linearize_pass1(std::string const& val) | ||
| 55 | + { | ||
| 56 | + linearize_pass1_ = val; | ||
| 57 | + return *this; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + bool | ||
| 61 | + preserve_encryption() const | ||
| 62 | + { | ||
| 63 | + return preserve_encryption_; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + Config& | ||
| 67 | + preserve_encryption(bool val) | ||
| 68 | + { | ||
| 69 | + preserve_encryption_ = val; | ||
| 70 | + return *this; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + bool | ||
| 74 | + encrypt_use_aes() const | ||
| 75 | + { | ||
| 76 | + return encrypt_use_aes_; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + Config& | ||
| 80 | + encrypt_use_aes(bool val) | ||
| 81 | + { | ||
| 82 | + encrypt_use_aes_ = val; | ||
| 83 | + return *this; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + Config& | ||
| 87 | + default_decode_level(qpdf_stream_decode_level_e val) | ||
| 88 | + { | ||
| 89 | + if (!decode_level_set_) { | ||
| 90 | + decode_level_ = val; | ||
| 91 | + } | ||
| 92 | + return *this; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + qpdf_stream_decode_level_e | ||
| 96 | + decode_level() const | ||
| 97 | + { | ||
| 98 | + return decode_level_; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + Config& decode_level(qpdf_stream_decode_level_e val); | ||
| 102 | + | ||
| 103 | + qpdf_object_stream_e | ||
| 104 | + object_streams() const | ||
| 105 | + { | ||
| 106 | + return object_streams_; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + Config& | ||
| 110 | + object_streams(qpdf_object_stream_e val) | ||
| 111 | + { | ||
| 112 | + object_streams_ = val; | ||
| 113 | + return *this; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + bool | ||
| 117 | + compress_streams() const | ||
| 118 | + { | ||
| 119 | + return compress_streams_; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + Config& compress_streams(bool val); | ||
| 123 | + | ||
| 124 | + bool | ||
| 125 | + direct_stream_lengths() const | ||
| 126 | + { | ||
| 127 | + return direct_stream_lengths_; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + bool | ||
| 131 | + newline_before_endstream() const | ||
| 132 | + { | ||
| 133 | + return newline_before_endstream_; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + Config& | ||
| 137 | + newline_before_endstream(bool val) | ||
| 138 | + { | ||
| 139 | + newline_before_endstream_ = val; | ||
| 140 | + return *this; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + bool | ||
| 144 | + recompress_flate() const | ||
| 145 | + { | ||
| 146 | + return recompress_flate_; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + Config& | ||
| 150 | + recompress_flate(bool val) | ||
| 151 | + { | ||
| 152 | + recompress_flate_ = val; | ||
| 153 | + return *this; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + Config& stream_data(qpdf_stream_data_e val); | ||
| 157 | + | ||
| 158 | + std::string const& | ||
| 159 | + forced_pdf_version() const | ||
| 160 | + { | ||
| 161 | + return forced_pdf_version_; | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + Config& | ||
| 165 | + forced_pdf_version(std::string const& val) | ||
| 166 | + { | ||
| 167 | + forced_pdf_version_ = val; | ||
| 168 | + return *this; | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + Config& | ||
| 172 | + forced_pdf_version(std::string const& val, int ext) | ||
| 173 | + { | ||
| 174 | + forced_pdf_version_ = val; | ||
| 175 | + forced_extension_level_ = ext; | ||
| 176 | + return *this; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + int | ||
| 180 | + forced_extension_level() const | ||
| 181 | + { | ||
| 182 | + return forced_extension_level_; | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + Config& | ||
| 186 | + forced_extension_level(int val) | ||
| 187 | + { | ||
| 188 | + forced_extension_level_ = val; | ||
| 189 | + return *this; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + std::string const& | ||
| 193 | + extra_header_text() | ||
| 194 | + { | ||
| 195 | + return extra_header_text_; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + Config& extra_header_text(std::string const& val); | ||
| 199 | + | ||
| 200 | + bool | ||
| 201 | + preserve_unreferenced() const | ||
| 202 | + { | ||
| 203 | + return preserve_unreferenced_; | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + Config& | ||
| 207 | + preserve_unreferenced(bool val) | ||
| 208 | + { | ||
| 209 | + preserve_unreferenced_ = val; | ||
| 210 | + return *this; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + bool | ||
| 214 | + no_original_object_ids() const | ||
| 215 | + { | ||
| 216 | + return no_original_object_ids_; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + Config& | ||
| 220 | + no_original_object_ids(bool val) | ||
| 221 | + { | ||
| 222 | + no_original_object_ids_ = val; | ||
| 223 | + return *this; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + bool | ||
| 227 | + qdf() const | ||
| 228 | + { | ||
| 229 | + return qdf_; | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + Config& qdf(bool val); | ||
| 233 | + | ||
| 234 | + bool | ||
| 235 | + normalize_content() const | ||
| 236 | + { | ||
| 237 | + return normalize_content_; | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + Config& | ||
| 241 | + normalize_content(bool val) | ||
| 242 | + { | ||
| 243 | + normalize_content_ = val; | ||
| 244 | + normalize_content_set_ = true; | ||
| 245 | + return *this; | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + bool | ||
| 249 | + deterministic_id() const | ||
| 250 | + { | ||
| 251 | + return deterministic_id_; | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + Config& | ||
| 255 | + deterministic_id(bool val) | ||
| 256 | + { | ||
| 257 | + deterministic_id_ = val; | ||
| 258 | + return *this; | ||
| 259 | + } | ||
| 260 | + | ||
| 261 | + bool | ||
| 262 | + static_id() const | ||
| 263 | + { | ||
| 264 | + return static_id_; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + Config& | ||
| 268 | + static_id(bool val) | ||
| 269 | + { | ||
| 270 | + static_id_ = val; | ||
| 271 | + return *this; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + bool | ||
| 275 | + pclm() const | ||
| 276 | + { | ||
| 277 | + return pclm_; | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + Config& pclm(bool val); | ||
| 281 | + | ||
| 282 | + private: | ||
| 283 | + void | ||
| 284 | + usage(std::string const& msg) const | ||
| 285 | + { | ||
| 286 | + if (!permissive_) { | ||
| 287 | + throw QPDFUsage(msg); | ||
| 288 | + } | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + std::string forced_pdf_version_; | ||
| 292 | + std::string extra_header_text_; | ||
| 293 | + // For linearization only | ||
| 294 | + std::string linearize_pass1_; | ||
| 295 | + | ||
| 296 | + qpdf_object_stream_e object_streams_{qpdf_o_preserve}; | ||
| 297 | + qpdf_stream_decode_level_e decode_level_{qpdf_dl_generalized}; | ||
| 298 | + | ||
| 299 | + int forced_extension_level_{0}; | ||
| 300 | + | ||
| 301 | + bool normalize_content_set_{false}; | ||
| 302 | + bool normalize_content_{false}; | ||
| 303 | + bool compress_streams_{true}; | ||
| 304 | + bool compress_streams_set_{false}; | ||
| 305 | + bool decode_level_set_{false}; | ||
| 306 | + bool recompress_flate_{false}; | ||
| 307 | + bool qdf_{false}; | ||
| 308 | + bool preserve_unreferenced_{false}; | ||
| 309 | + bool newline_before_endstream_{false}; | ||
| 310 | + bool deterministic_id_{false}; | ||
| 311 | + bool static_id_{false}; | ||
| 312 | + bool no_original_object_ids_{false}; | ||
| 313 | + bool direct_stream_lengths_{true}; | ||
| 314 | + bool preserve_encryption_{true}; | ||
| 315 | + bool linearize_{false}; | ||
| 316 | + bool pclm_{false}; | ||
| 317 | + bool encrypt_use_aes_{false}; | ||
| 318 | + | ||
| 319 | + bool permissive_{true}; | ||
| 320 | + }; // class Writer::Config | ||
| 321 | + | ||
| 322 | + Writer() = delete; | ||
| 323 | + Writer(Writer const&) = delete; | ||
| 324 | + Writer(Writer&&) = delete; | ||
| 325 | + Writer& operator=(Writer const&) = delete; | ||
| 326 | + Writer& operator=(Writer&&) = delete; | ||
| 327 | + ~Writer() = default; | ||
| 328 | + | ||
| 329 | + Writer(QPDF& qpdf, Config cfg); | ||
| 330 | + | ||
| 331 | + }; // class Writer | ||
| 332 | +} // namespace qpdf | ||
| 333 | + | ||
| 12 | struct QPDFWriter::Object | 334 | struct QPDFWriter::Object |
| 13 | { | 335 | { |
| 14 | int renumber{0}; | 336 | int renumber{0}; |
| @@ -24,7 +346,7 @@ struct QPDFWriter::NewObject | @@ -24,7 +346,7 @@ struct QPDFWriter::NewObject | ||
| 24 | 346 | ||
| 25 | class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object> | 347 | class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object> |
| 26 | { | 348 | { |
| 27 | - friend class QPDFWriter; | 349 | + friend class qpdf::impl::Writer; |
| 28 | 350 | ||
| 29 | public: | 351 | public: |
| 30 | bool | 352 | bool |
libqpdf/qpdf/QPDF_private.hh
| @@ -22,6 +22,11 @@ namespace qpdf | @@ -22,6 +22,11 @@ namespace qpdf | ||
| 22 | class OffsetBuffer; | 22 | class OffsetBuffer; |
| 23 | } // namespace is | 23 | } // namespace is |
| 24 | 24 | ||
| 25 | + namespace impl | ||
| 26 | + { | ||
| 27 | + using Doc = QPDF::Doc; | ||
| 28 | + } | ||
| 29 | + | ||
| 25 | class Doc: public QPDF | 30 | class Doc: public QPDF |
| 26 | { | 31 | { |
| 27 | public: | 32 | public: |
| @@ -271,7 +276,6 @@ class QPDF::Doc | @@ -271,7 +276,6 @@ class QPDF::Doc | ||
| 271 | class Pages; | 276 | class Pages; |
| 272 | class ParseGuard; | 277 | class ParseGuard; |
| 273 | class Resolver; | 278 | class Resolver; |
| 274 | - class Writer; | ||
| 275 | 279 | ||
| 276 | // This is the common base-class for all document components. It is used by the other document | 280 | // This is the common base-class for all document components. It is used by the other document |
| 277 | // components to access common functionality. It is not meant to be used directly by the user. | 281 | // components to access common functionality. It is not meant to be used directly by the user. |
| @@ -286,6 +290,7 @@ class QPDF::Doc | @@ -286,6 +290,7 @@ class QPDF::Doc | ||
| 286 | ~Common() = default; | 290 | ~Common() = default; |
| 287 | 291 | ||
| 288 | inline Common(QPDF& qpdf, QPDF::Members* m); | 292 | inline Common(QPDF& qpdf, QPDF::Members* m); |
| 293 | + inline Common(Doc& doc); | ||
| 289 | 294 | ||
| 290 | void stopOnError(std::string const& message); | 295 | void stopOnError(std::string const& message); |
| 291 | void warn(QPDFExc const& e); | 296 | void warn(QPDFExc const& e); |
| @@ -546,7 +551,7 @@ class QPDF::Doc::Linearization: Common | @@ -546,7 +551,7 @@ class QPDF::Doc::Linearization: Common | ||
| 546 | ~Linearization() = default; | 551 | ~Linearization() = default; |
| 547 | 552 | ||
| 548 | Linearization(Doc& doc) : | 553 | Linearization(Doc& doc) : |
| 549 | - Common(doc.qpdf, doc.m) | 554 | + Common(doc) |
| 550 | { | 555 | { |
| 551 | } | 556 | } |
| 552 | 557 | ||
| @@ -567,7 +572,7 @@ class QPDF::Doc::Linearization: Common | @@ -567,7 +572,7 @@ class QPDF::Doc::Linearization: Common | ||
| 567 | 572 | ||
| 568 | // Get lists of all objects in order according to the part of a linearized file that they | 573 | // Get lists of all objects in order according to the part of a linearized file that they |
| 569 | // belong to. | 574 | // belong to. |
| 570 | - void getLinearizedParts( | 575 | + void parts( |
| 571 | QPDFWriter::ObjTable const& obj, | 576 | QPDFWriter::ObjTable const& obj, |
| 572 | std::vector<QPDFObjectHandle>& part4, | 577 | std::vector<QPDFObjectHandle>& part4, |
| 573 | std::vector<QPDFObjectHandle>& part6, | 578 | std::vector<QPDFObjectHandle>& part6, |
| @@ -940,7 +945,7 @@ class QPDF::Doc::Objects: Common | @@ -940,7 +945,7 @@ class QPDF::Doc::Objects: Common | ||
| 940 | ~Objects() = default; | 945 | ~Objects() = default; |
| 941 | 946 | ||
| 942 | Objects(Doc& doc) : | 947 | Objects(Doc& doc) : |
| 943 | - Common(doc.qpdf, doc.m), | 948 | + Common(doc), |
| 944 | foreign_(*this), | 949 | foreign_(*this), |
| 945 | streams_(*this) | 950 | streams_(*this) |
| 946 | { | 951 | { |
| @@ -987,18 +992,19 @@ class QPDF::Doc::Objects: Common | @@ -987,18 +992,19 @@ class QPDF::Doc::Objects: Common | ||
| 987 | QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj); | 992 | QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj); |
| 988 | std::shared_ptr<QPDFObject> getObjectForParser(int id, int gen, bool parse_pdf); | 993 | std::shared_ptr<QPDFObject> getObjectForParser(int id, int gen, bool parse_pdf); |
| 989 | std::shared_ptr<QPDFObject> getObjectForJSON(int id, int gen); | 994 | std::shared_ptr<QPDFObject> getObjectForJSON(int id, int gen); |
| 990 | - size_t tableSize(); | 995 | + size_t table_size(); |
| 991 | 996 | ||
| 992 | // For QPDFWriter: | 997 | // For QPDFWriter: |
| 993 | 998 | ||
| 994 | - std::map<QPDFObjGen, QPDFXRefEntry> const& getXRefTableInternal(); | 999 | + std::map<QPDFObjGen, QPDFXRefEntry> const& xref_table(); |
| 1000 | + std::vector<QPDFObjGen> compressible_vector(); | ||
| 1001 | + std::vector<bool> compressible_set(); | ||
| 1002 | + | ||
| 1003 | + private: | ||
| 995 | // Get a list of objects that would be permitted in an object stream. | 1004 | // Get a list of objects that would be permitted in an object stream. |
| 996 | template <typename T> | 1005 | template <typename T> |
| 997 | - std::vector<T> getCompressibleObjGens(); | ||
| 998 | - std::vector<QPDFObjGen> getCompressibleObjVector(); | ||
| 999 | - std::vector<bool> getCompressibleObjSet(); | 1006 | + std::vector<T> compressible(); |
| 1000 | 1007 | ||
| 1001 | - private: | ||
| 1002 | void setTrailer(QPDFObjectHandle obj); | 1008 | void setTrailer(QPDFObjectHandle obj); |
| 1003 | void reconstruct_xref(QPDFExc& e, bool found_startxref = true); | 1009 | void reconstruct_xref(QPDFExc& e, bool found_startxref = true); |
| 1004 | void read_xref(qpdf_offset_t offset, bool in_stream_recovery = false); | 1010 | void read_xref(qpdf_offset_t offset, bool in_stream_recovery = false); |
| @@ -1060,7 +1066,7 @@ class QPDF::Doc::Pages: Common | @@ -1060,7 +1066,7 @@ class QPDF::Doc::Pages: Common | ||
| 1060 | ~Pages() = default; | 1066 | ~Pages() = default; |
| 1061 | 1067 | ||
| 1062 | Pages(Doc& doc) : | 1068 | Pages(Doc& doc) : |
| 1063 | - Common(doc.qpdf, doc.m) | 1069 | + Common(doc) |
| 1064 | { | 1070 | { |
| 1065 | } | 1071 | } |
| 1066 | 1072 | ||
| @@ -1214,6 +1220,11 @@ inline QPDF::Doc::Common::Common(QPDF& qpdf, QPDF::Members* m) : | @@ -1214,6 +1220,11 @@ inline QPDF::Doc::Common::Common(QPDF& qpdf, QPDF::Members* m) : | ||
| 1214 | { | 1220 | { |
| 1215 | } | 1221 | } |
| 1216 | 1222 | ||
| 1223 | +inline QPDF::Doc::Common::Common(Doc& doc) : | ||
| 1224 | + Common(doc.qpdf, doc.m) | ||
| 1225 | +{ | ||
| 1226 | +} | ||
| 1227 | + | ||
| 1217 | inline QPDF::Doc::Linearization& | 1228 | inline QPDF::Doc::Linearization& |
| 1218 | QPDF::Doc::linearization() | 1229 | QPDF::Doc::linearization() |
| 1219 | { | 1230 | { |
| @@ -1245,7 +1256,7 @@ QPDF::doc() | @@ -1245,7 +1256,7 @@ QPDF::doc() | ||
| 1245 | } | 1256 | } |
| 1246 | 1257 | ||
| 1247 | inline QPDF::Doc::Objects::Foreign::Copier::Copier(QPDF& qpdf) : | 1258 | inline QPDF::Doc::Objects::Foreign::Copier::Copier(QPDF& qpdf) : |
| 1248 | - Common(qpdf, qpdf.doc().m) | 1259 | + Common(qpdf.doc()) |
| 1249 | { | 1260 | { |
| 1250 | } | 1261 | } |
| 1251 | 1262 |
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 |