diff options
Diffstat (limited to 'libqpdf/QPDFWriter.cc')
-rw-r--r-- | libqpdf/QPDFWriter.cc | 194 |
1 files changed, 171 insertions, 23 deletions
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 447b6627..fee287bc 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -63,6 +63,7 @@ QPDFWriter::Members::Members(QPDF& pdf) : max_ostream_index(0), deterministic_id(false), md5_pipeline(0), + did_write_setup(false), events_expected(0), events_seen(0), next_progress_report(0) @@ -75,10 +76,7 @@ QPDFWriter::Members::~Members() { fclose(file); } - if (output_buffer) - { - delete output_buffer; - } + delete output_buffer; } QPDFWriter::QPDFWriter(QPDF& pdf) : @@ -411,7 +409,26 @@ QPDFWriter::setR3EncryptionParameters( std::set<int> clear; interpretR3EncryptionParameters( clear, user_password, owner_password, - allow_accessibility, allow_extract, print, modify); + allow_accessibility, allow_extract, + true, true, true, true, print, modify); + setEncryptionParameters(user_password, owner_password, 2, 3, 16, clear); +} + +void +QPDFWriter::setR3EncryptionParameters( + char const* user_password, char const* owner_password, + bool allow_accessibility, bool allow_extract, + bool allow_assemble, bool allow_annotate_and_form, + bool allow_form_filling, bool allow_modify_other, + qpdf_r3_print_e print) +{ + std::set<int> clear; + interpretR3EncryptionParameters( + clear, user_password, owner_password, + allow_accessibility, allow_extract, + allow_assemble, allow_annotate_and_form, + allow_form_filling, allow_modify_other, + print, qpdf_r3m_all); setEncryptionParameters(user_password, owner_password, 2, 3, 16, clear); } @@ -425,7 +442,29 @@ QPDFWriter::setR4EncryptionParameters( std::set<int> clear; interpretR3EncryptionParameters( clear, user_password, owner_password, - allow_accessibility, allow_extract, print, modify); + allow_accessibility, allow_extract, + true, true, true, true, print, modify); + this->m->encrypt_use_aes = use_aes; + this->m->encrypt_metadata = encrypt_metadata; + setEncryptionParameters(user_password, owner_password, 4, 4, 16, clear); +} + +void +QPDFWriter::setR4EncryptionParameters( + char const* user_password, char const* owner_password, + bool allow_accessibility, bool allow_extract, + bool allow_assemble, bool allow_annotate_and_form, + bool allow_form_filling, bool allow_modify_other, + qpdf_r3_print_e print, + bool encrypt_metadata, bool use_aes) +{ + std::set<int> clear; + interpretR3EncryptionParameters( + clear, user_password, owner_password, + allow_accessibility, allow_extract, + allow_assemble, allow_annotate_and_form, + allow_form_filling, allow_modify_other, + print, qpdf_r3m_all); this->m->encrypt_use_aes = use_aes; this->m->encrypt_metadata = encrypt_metadata; setEncryptionParameters(user_password, owner_password, 4, 4, 16, clear); @@ -441,7 +480,29 @@ QPDFWriter::setR5EncryptionParameters( std::set<int> clear; interpretR3EncryptionParameters( clear, user_password, owner_password, - allow_accessibility, allow_extract, print, modify); + allow_accessibility, allow_extract, + true, true, true, true, print, modify); + this->m->encrypt_use_aes = true; + this->m->encrypt_metadata = encrypt_metadata; + setEncryptionParameters(user_password, owner_password, 5, 5, 32, clear); +} + +void +QPDFWriter::setR5EncryptionParameters( + char const* user_password, char const* owner_password, + bool allow_accessibility, bool allow_extract, + bool allow_assemble, bool allow_annotate_and_form, + bool allow_form_filling, bool allow_modify_other, + qpdf_r3_print_e print, + bool encrypt_metadata) +{ + std::set<int> clear; + interpretR3EncryptionParameters( + clear, user_password, owner_password, + allow_accessibility, allow_extract, + allow_assemble, allow_annotate_and_form, + allow_form_filling, allow_modify_other, + print, qpdf_r3m_all); this->m->encrypt_use_aes = true; this->m->encrypt_metadata = encrypt_metadata; setEncryptionParameters(user_password, owner_password, 5, 5, 32, clear); @@ -457,7 +518,29 @@ QPDFWriter::setR6EncryptionParameters( std::set<int> clear; interpretR3EncryptionParameters( clear, user_password, owner_password, - allow_accessibility, allow_extract, print, modify); + allow_accessibility, allow_extract, + true, true, true, true, print, modify); + this->m->encrypt_use_aes = true; + this->m->encrypt_metadata = encrypt_metadata; + setEncryptionParameters(user_password, owner_password, 5, 6, 32, clear); +} + +void +QPDFWriter::setR6EncryptionParameters( + char const* user_password, char const* owner_password, + bool allow_accessibility, bool allow_extract, + bool allow_assemble, bool allow_annotate_and_form, + bool allow_form_filling, bool allow_modify_other, + qpdf_r3_print_e print, + bool encrypt_metadata) +{ + std::set<int> clear; + interpretR3EncryptionParameters( + clear, user_password, owner_password, + allow_accessibility, allow_extract, + allow_assemble, allow_annotate_and_form, + allow_form_filling, allow_modify_other, + print, qpdf_r3m_all); this->m->encrypt_use_aes = true; this->m->encrypt_metadata = encrypt_metadata; setEncryptionParameters(user_password, owner_password, 5, 6, 32, clear); @@ -468,6 +551,8 @@ QPDFWriter::interpretR3EncryptionParameters( std::set<int>& clear, char const* user_password, char const* owner_password, bool allow_accessibility, bool allow_extract, + bool allow_assemble, bool allow_annotate_and_form, + bool allow_form_filling, bool allow_modify_other, qpdf_r3_print_e print, qpdf_r3_modify_e modify) { // Acrobat 5 security options: @@ -488,8 +573,21 @@ QPDFWriter::interpretR3EncryptionParameters( // Low Resolution // Full printing + // Meanings of bits in P when R >= 3 + // + // 3: low-resolution printing + // 4: document modification except as controlled by 6, 9, and 11 + // 5: extraction + // 6: add/modify annotations (comment), fill in forms + // if 4+6 are set, also allows modification of form fields + // 9: fill in forms even if 6 is clear + // 10: accessibility; ignored by readers, should always be set + // 11: document assembly even if 4 is clear + // 12: high-resolution printing + if (! allow_accessibility) { + // setEncryptionParameters sets this if R > 3 clear.insert(10); } if (! allow_extract) @@ -513,6 +611,13 @@ QPDFWriter::interpretR3EncryptionParameters( // no default so gcc warns for missing cases } + // Modify options. The qpdf_r3_modify_e options control groups of + // bits and lack the full flexibility of the spec. This is + // unfortunate, but it's been in the API for ages, and we're stuck + // with it. See also allow checks below to control the bits + // individually. + + // NOT EXERCISED IN TEST SUITE switch (modify) { case qpdf_r3m_none: @@ -532,6 +637,24 @@ QPDFWriter::interpretR3EncryptionParameters( // no default so gcc warns for missing cases } + // END NOT EXERCISED IN TEST SUITE + + if (! allow_assemble) + { + clear.insert(11); + } + if (! allow_annotate_and_form) + { + clear.insert(6); + } + if (! allow_form_filling) + { + clear.insert(9); + } + if (! allow_modify_other) + { + clear.insert(4); + } } void @@ -1811,7 +1934,9 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) // Set up a stream to write the stream data into a buffer. Pipeline* next = pushPipeline(new Pl_Buffer("object stream")); - if (! (this->m->stream_decode_level || this->m->qdf_mode)) + if ((this->m->compress_streams || + (this->m->stream_decode_level == qpdf_dl_none)) && + (! this->m->qdf_mode)) { compressed = true; next = pushPipeline( @@ -2247,6 +2372,7 @@ QPDFWriter::prepareFileForWrite() // includes stream lengths, stream filtering parameters, and // document extension level information. + this->m->pdf.fixDanglingReferences(true); std::list<QPDFObjectHandle> queue; queue.push_back(getTrimmedTrailer()); std::set<int> visited; @@ -2360,8 +2486,14 @@ QPDFWriter::prepareFileForWrite() } void -QPDFWriter::write() +QPDFWriter::doWriteSetup() { + if (this->m->did_write_setup) + { + return; + } + this->m->did_write_setup = true; + // Do preliminary setup if (this->m->linearized) @@ -2509,6 +2641,23 @@ QPDFWriter::write() setMinimumPDFVersion("1.5"); } + setMinimumPDFVersion(this->m->pdf.getPDFVersion(), + this->m->pdf.getExtensionLevel()); + this->m->final_pdf_version = this->m->min_pdf_version; + this->m->final_extension_level = this->m->min_extension_level; + if (! this->m->forced_pdf_version.empty()) + { + QTC::TC("qpdf", "QPDFWriter using forced PDF version"); + this->m->final_pdf_version = this->m->forced_pdf_version; + this->m->final_extension_level = this->m->forced_extension_level; + } +} + +void +QPDFWriter::write() +{ + doWriteSetup(); + // Set up progress reporting. We spent about equal amounts of time // preparing and writing one pass. To get a rough estimate of // progress, we track handling of indirect objects. For linearized @@ -2571,20 +2720,16 @@ QPDFWriter::writeEncryptionDictionary() closeObject(this->m->encryption_dict_objid); } +std::string +QPDFWriter::getFinalVersion() +{ + doWriteSetup(); + return this->m->final_pdf_version; +} + void QPDFWriter::writeHeader() { - setMinimumPDFVersion(this->m->pdf.getPDFVersion(), - this->m->pdf.getExtensionLevel()); - this->m->final_pdf_version = this->m->min_pdf_version; - this->m->final_extension_level = this->m->min_extension_level; - if (! this->m->forced_pdf_version.empty()) - { - QTC::TC("qpdf", "QPDFWriter using forced PDF version"); - this->m->final_pdf_version = this->m->forced_pdf_version; - this->m->final_extension_level = this->m->forced_extension_level; - } - writeString("%PDF-"); writeString(this->m->final_pdf_version); if (this->m->pclm) @@ -2733,7 +2878,9 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, qpdf_offset_t max_offset, Pipeline* p = pushPipeline(new Pl_Buffer("xref stream")); bool compressed = false; - if (! (this->m->stream_decode_level || this->m->qdf_mode)) + if ((this->m->compress_streams || + (this->m->stream_decode_level == qpdf_dl_none)) && + (! this->m->qdf_mode)) { compressed = true; if (! skip_compression) @@ -3357,9 +3504,10 @@ QPDFWriter::indicateProgress(bool decrement, bool finished) this->m->events_expected))); this->m->progress_reporter->reportProgress(percentage); } + int increment = std::max(1, (this->m->events_expected / 100)); while (this->m->events_seen >= this->m->next_progress_report) { - this->m->next_progress_report += (this->m->events_expected / 100); + this->m->next_progress_report += increment; } } |