aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/QPDFWriter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/QPDFWriter.cc')
-rw-r--r--libqpdf/QPDFWriter.cc194
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;
}
}