aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/qpdf/QPDFWriter.hh1
-rw-r--r--libqpdf/QPDFWriter.cc122
-rw-r--r--qpdf/qpdf.testcov3
-rw-r--r--qpdf/qtest/qpdf.test2
-rw-r--r--qpdf/qtest/qpdf/extensions-adbe-force-1.8.5.qdf19
-rw-r--r--qpdf/qtest/qpdf/extensions-adbe-other-force-1.8.5.qdf19
-rw-r--r--qpdf/qtest/qpdf/extensions-none-force-1.8.5.qdf21
-rw-r--r--qpdf/qtest/qpdf/extensions-other-force-1.8.5.qdf19
8 files changed, 97 insertions, 109 deletions
diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh
index a8cf5054..7861203c 100644
--- a/include/qpdf/QPDFWriter.hh
+++ b/include/qpdf/QPDFWriter.hh
@@ -271,7 +271,6 @@ class QPDFWriter
static int const f_stream = 1 << 0;
static int const f_filtered = 1 << 1;
static int const f_in_ostream = 1 << 2;
- static int const f_in_extensions = 1 << 3;
enum trailer_e { t_normal, t_lin_first, t_lin_second };
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc
index a02239c4..d7ab0c8b 100644
--- a/libqpdf/QPDFWriter.cc
+++ b/libqpdf/QPDFWriter.cc
@@ -1135,7 +1135,8 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
unsigned int flags, size_t stream_length,
bool compress)
{
- unsigned int child_flags = flags & ~f_stream & ~f_in_extensions;
+ int old_id = object.getObjectID();
+ unsigned int child_flags = flags & ~f_stream;
std::string indent;
for (int i = 0; i < level; ++i)
@@ -1167,10 +1168,19 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
}
else if (object.isDictionary())
{
+ // Make a shallow copy of this object so we can modify it
+ // safely without affecting the original. This code makes
+ // assumptions about things that are made true in
+ // prepareFileForWrite, such as that certain things are direct
+ // objects so that replacing them doesn't leave unreferenced
+ // objects in the output.
+ object = object.shallowCopy();
+
// Handle special cases for specific dictionaries.
- // Extensions dictionaries are complicated. We have one of
- // several cases:
+ // Extensions dictionaries.
+
+ // We have one of several cases:
//
// * We need ADBE
// - We already have Extensions
@@ -1183,16 +1193,16 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
// - If it has other things, keep those and remove ADBE
// - We have no extensions: no action required
//
- // We may be in the root dictionary, or we may be inside the
- // extensions dictionary itself. The latter is determined by
- // the presence of the f_in_extensions flag.
+ // Before writing, we guarantee that /Extensions, if present,
+ // is direct through the ADBE dictionary, so we can modify in
+ // place.
bool is_root = false;
bool have_extensions_other = false;
bool have_extensions_adbe = false;
QPDFObjectHandle extensions;
- if (object.getObjectID() == pdf.getRoot().getObjectID())
+ if (old_id == pdf.getRoot().getObjectID())
{
is_root = true;
if (object.hasKey("/Extensions") &&
@@ -1201,10 +1211,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
extensions = object.getKey("/Extensions");
}
}
- else if (flags & f_in_extensions)
- {
- extensions = object;
- }
+
if (extensions.isInitialized())
{
std::set<std::string> keys = extensions.getKeys();
@@ -1221,10 +1228,6 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
bool need_extensions_adbe = (this->final_extension_level > 0);
- bool write_new_extensions = false;
- bool write_new_adbe = false;
- bool suppress_existing_extensions = false;
- bool suppress_existing_adbe = false;
if (is_root)
{
if (need_extensions_adbe)
@@ -1235,26 +1238,23 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
// it here.
QTC::TC("qpdf", "QPDFWriter create Extensions",
this->qdf_mode ? 0 : 1);
- write_new_extensions = true;
- suppress_existing_extensions = true;
- }
- else
- {
- // Preserve existing Extensions and do the work
- // in the extensions dictionary.
+ extensions = QPDFObjectHandle::newDictionary();
+ object.replaceKey("/Extensions", extensions);
}
}
else if (! have_extensions_other)
{
// We have Extensions dictionary and don't want one.
- suppress_existing_extensions = true;
if (have_extensions_adbe)
{
QTC::TC("qpdf", "QPDFWriter remove existing Extensions");
+ object.removeKey("/Extensions");
+ extensions = QPDFObjectHandle(); // uninitialized
}
}
}
- else if (flags & f_in_extensions)
+
+ if (extensions.isInitialized())
{
QTC::TC("qpdf", "QPDFWriter preserve Extensions");
QPDFObjectHandle adbe = extensions.getKey("/ADBE");
@@ -1272,77 +1272,54 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
}
else
{
- suppress_existing_adbe = true;
if (need_extensions_adbe)
{
- write_new_adbe = true;
+ extensions.replaceKey(
+ "/ADBE",
+ QPDFObjectHandle::parse(
+ "<< /BaseVersion /" + this->final_pdf_version +
+ " /ExtensionLevel " +
+ QUtil::int_to_string(this->final_extension_level) +
+ " >>"));
+ }
+ else
+ {
+ QTC::TC("qpdf", "QPDFWriter remove ADBE");
+ extensions.removeKey("/ADBE");
}
}
}
- writeString("<<");
- writeStringQDF("\n");
+ // Stream dictionaries.
- if (write_new_extensions || write_new_adbe)
+ if (flags & f_stream)
{
- writeStringQDF(indent);
- writeStringQDF(" ");
- writeStringNoQDF(" ");
- if (write_new_extensions)
- {
- writeString("/Extensions << ");
- }
- writeString("/ADBE << /BaseVersion /");
- writeString(this->final_pdf_version);
- writeString(" /ExtensionLevel ");
- writeString(QUtil::int_to_string(this->final_extension_level));
- writeString(" >>");
- if (write_new_extensions)
+ // Suppress /Length since we will write it manually
+ object.removeKey("/Length");
+
+ // XXX BUG: /Crypt filters should always be removed.
+ if (flags & f_filtered)
{
- writeString(" >>");
+ object.removeKey("/Filter");
+ object.removeKey("/DecodeParms");
}
- writeStringQDF("\n");
}
+ writeString("<<");
+ writeStringQDF("\n");
+
std::set<std::string> keys = object.getKeys();
for (std::set<std::string>::iterator iter = keys.begin();
iter != keys.end(); ++iter)
{
- // I'm not fully clear on /Crypt keys in /DecodeParms. If
- // one is found, we refuse to filter, so we should be
- // safe.
std::string const& key = *iter;
- if ((flags & f_filtered) &&
- ((key == "/Filter") ||
- (key == "/DecodeParms")))
- {
- continue;
- }
- if ((flags & f_stream) && (key == "/Length"))
- {
- continue;
- }
-
- bool is_extensions = (is_root && (key == "/Extensions"));
- if (suppress_existing_extensions && is_extensions)
- {
- QTC::TC("qpdf", "QPDFWriter skip Extensions");
- continue;
- }
- if (suppress_existing_adbe && (key == "/ADBE"))
- {
- QTC::TC("qpdf", "QPDFWriter skip ADBE");
- continue;
- }
-
writeStringQDF(indent);
writeStringQDF(" ");
writeStringNoQDF(" ");
writeString(QPDF_Name::normalizeName(key));
writeString(" ");
- unparseChild(object.getKey(key), level + 1,
- child_flags | (is_extensions ? f_in_extensions : 0));
+ unparseChild(object.getKey(key), level + 1, child_flags);
writeStringQDF("\n");
}
@@ -1379,7 +1356,6 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
else if (object.isStream())
{
// Write stream data to a buffer.
- int old_id = object.getObjectID();
int new_id = obj_renumber[old_id];
if (! this->direct_stream_lengths)
{
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index fd80bfb2..4ade4e7e 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -249,9 +249,8 @@ QPDFWriter make Extensions direct 0
QPDFWriter make ADBE direct 1
QPDFWriter preserve Extensions 0
QPDFWriter create Extensions 1
-QPDFWriter skip ADBE 0
+QPDFWriter remove ADBE 0
QPDFWriter remove existing Extensions 0
-QPDFWriter skip Extensions 0
QPDFWriter preserve ADBE 0
QPDF_encryption skip 0x28 0
QPDF_encrypt crypt array 0
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 58bc764f..47afbcf2 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -134,7 +134,7 @@ foreach my $input (@ext_inputs)
"qpdf --static-id" .
" --$op-version=$version $input a.pdf"},
{$td->STRING => "", $td->EXIT_STATUS => 0});
- $td->runtest("check version information",
+ $td->runtest("check version information ($op $version)",
{$td->COMMAND => "test_driver 34 a.pdf"},
{$td->FILE => "$base-$op-$version.out",
$td->EXIT_STATUS => 0},
diff --git a/qpdf/qtest/qpdf/extensions-adbe-force-1.8.5.qdf b/qpdf/qtest/qpdf/extensions-adbe-force-1.8.5.qdf
index 111ed12a..efd08ba9 100644
--- a/qpdf/qtest/qpdf/extensions-adbe-force-1.8.5.qdf
+++ b/qpdf/qtest/qpdf/extensions-adbe-force-1.8.5.qdf
@@ -6,7 +6,10 @@
1 0 obj
<<
/Extensions <<
- /ADBE << /BaseVersion /1.8 /ExtensionLevel 5 >>
+ /ADBE <<
+ /BaseVersion /1.8
+ /ExtensionLevel 5
+ >>
>>
/Pages 2 0 R
/Type /Catalog
@@ -88,17 +91,17 @@ xref
0 8
0000000000 65535 f
0000000052 00000 n
-0000000207 00000 n
-0000000316 00000 n
-0000000558 00000 n
-0000000657 00000 n
-0000000703 00000 n
-0000000848 00000 n
+0000000223 00000 n
+0000000332 00000 n
+0000000574 00000 n
+0000000673 00000 n
+0000000719 00000 n
+0000000864 00000 n
trailer <<
/Root 1 0 R
/Size 8
/ID [<e42c124696c09bd2cacaf7196e9c88a0><31415926535897932384626433832795>]
>>
startxref
-883
+899
%%EOF
diff --git a/qpdf/qtest/qpdf/extensions-adbe-other-force-1.8.5.qdf b/qpdf/qtest/qpdf/extensions-adbe-other-force-1.8.5.qdf
index 5993af1f..e391af0c 100644
--- a/qpdf/qtest/qpdf/extensions-adbe-other-force-1.8.5.qdf
+++ b/qpdf/qtest/qpdf/extensions-adbe-other-force-1.8.5.qdf
@@ -6,7 +6,10 @@
1 0 obj
<<
/Extensions <<
- /ADBE << /BaseVersion /1.8 /ExtensionLevel 5 >>
+ /ADBE <<
+ /BaseVersion /1.8
+ /ExtensionLevel 5
+ >>
/Potato <<
/BaseVersion /3.14159
/ExtensionLevel 16059
@@ -92,17 +95,17 @@ xref
0 8
0000000000 65535 f
0000000052 00000 n
-0000000285 00000 n
-0000000394 00000 n
-0000000636 00000 n
-0000000735 00000 n
-0000000781 00000 n
-0000000926 00000 n
+0000000301 00000 n
+0000000410 00000 n
+0000000652 00000 n
+0000000751 00000 n
+0000000797 00000 n
+0000000942 00000 n
trailer <<
/Root 1 0 R
/Size 8
/ID [<484577389048fa45fc00a1f5b434efa5><31415926535897932384626433832795>]
>>
startxref
-961
+977
%%EOF
diff --git a/qpdf/qtest/qpdf/extensions-none-force-1.8.5.qdf b/qpdf/qtest/qpdf/extensions-none-force-1.8.5.qdf
index c6f9a1f6..230c1c07 100644
--- a/qpdf/qtest/qpdf/extensions-none-force-1.8.5.qdf
+++ b/qpdf/qtest/qpdf/extensions-none-force-1.8.5.qdf
@@ -5,7 +5,12 @@
%% Original object ID: 1 0
1 0 obj
<<
- /Extensions << /ADBE << /BaseVersion /1.8 /ExtensionLevel 5 >> >>
+ /Extensions <<
+ /ADBE <<
+ /BaseVersion /1.8
+ /ExtensionLevel 5
+ >>
+ >>
/Pages 2 0 R
/Type /Catalog
>>
@@ -86,17 +91,17 @@ xref
0 8
0000000000 65535 f
0000000052 00000 n
-0000000201 00000 n
-0000000310 00000 n
-0000000552 00000 n
-0000000651 00000 n
-0000000697 00000 n
-0000000842 00000 n
+0000000223 00000 n
+0000000332 00000 n
+0000000574 00000 n
+0000000673 00000 n
+0000000719 00000 n
+0000000864 00000 n
trailer <<
/Root 1 0 R
/Size 8
/ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
>>
startxref
-877
+899
%%EOF
diff --git a/qpdf/qtest/qpdf/extensions-other-force-1.8.5.qdf b/qpdf/qtest/qpdf/extensions-other-force-1.8.5.qdf
index 3c596f7d..a4ffae3a 100644
--- a/qpdf/qtest/qpdf/extensions-other-force-1.8.5.qdf
+++ b/qpdf/qtest/qpdf/extensions-other-force-1.8.5.qdf
@@ -6,7 +6,10 @@
1 0 obj
<<
/Extensions <<
- /ADBE << /BaseVersion /1.8 /ExtensionLevel 5 >>
+ /ADBE <<
+ /BaseVersion /1.8
+ /ExtensionLevel 5
+ >>
/Potato <<
/BaseVersion /3.14159
/ExtensionLevel 16059
@@ -92,17 +95,17 @@ xref
0 8
0000000000 65535 f
0000000052 00000 n
-0000000285 00000 n
-0000000394 00000 n
-0000000636 00000 n
-0000000735 00000 n
-0000000781 00000 n
-0000000926 00000 n
+0000000301 00000 n
+0000000410 00000 n
+0000000652 00000 n
+0000000751 00000 n
+0000000797 00000 n
+0000000942 00000 n
trailer <<
/Root 1 0 R
/Size 8
/ID [<369e89600ee1a6c4c7e73533610180c2><31415926535897932384626433832795>]
>>
startxref
-961
+977
%%EOF