aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/QPDFWriter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/QPDFWriter.cc')
-rw-r--r--libqpdf/QPDFWriter.cc122
1 files changed, 49 insertions, 73 deletions
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)
{