Handle /Outlines dictionary being a direct object

Even though this case is not valid according to the spec, it has been
seen, and caused an internal error.
This commit is contained in:
Jay Berkenbilt 2013-06-14 21:35:10 -04:00
parent eae8370cd9
commit 16051788ed
6 changed files with 1534 additions and 1 deletions

View File

@ -1,5 +1,11 @@
2013-06-14 Jay Berkenbilt <ejb@ql.org>
* Detect and correct /Outlines dictionary being a direct object
when linearizing files. This is not allowed by the spec but has
been seen in the wild. Prior to this change, such a file would
cause an internal error in the linearization code, which assumed
/Outlines was indirect.
* Add /Length key to crypt filter dictionary for encrypted files.
This key is optional, but some version of MacOS reportedly fail to
open encrypted PDF files without this key.

View File

@ -958,6 +958,15 @@ QPDF::checkHOutlines(std::list<std::string>& warnings)
{
// Check length and offset. Acrobat gets these wrong.
QPDFObjectHandle outlines = getRoot().getKey("/Outlines");
if (! outlines.isIndirect())
{
// This case is not exercised in test suite since not
// permitted by the spec, but if this does occur, the
// code below would fail.
warnings.push_back(
"/Outlines key of root dictionary is not indirect");
return;
}
QPDFObjGen og(outlines.getObjGen());
assert(this->xref_table.count(og) > 0);
int offset = getLinearizationOffset(og);

View File

@ -68,6 +68,20 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
return;
}
// The PDF specification indicates that /Outlines is supposed to
// be an indirect reference. Force it to be so if it exists and
// is direct. (This has been seen in the wild.)
QPDFObjectHandle root = getRoot();
if (root.getKey("/Outlines").isDictionary())
{
QPDFObjectHandle outlines = root.getKey("/Outlines");
if (! outlines.isIndirect())
{
QTC::TC("qpdf", "QPDF_optimization indirect outlines");
root.replaceKey("/Outlines", makeIndirectObject(outlines));
}
}
// Traverse pages tree pushing all inherited resources down to the
// page level. This also initializes this->all_pages.
pushInheritedAttributesToPage(allow_changes, false);
@ -97,7 +111,6 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
}
}
QPDFObjectHandle root = getRoot();
keys = root.getKeys();
for (std::set<std::string>::iterator iter = keys.begin();
iter != keys.end(); ++iter)

View File

@ -263,3 +263,4 @@ QPDFObjectHandle EOF in inline image 0
QPDFObjectHandle inline image token 0
QPDF not caching overridden objstm object 0
QPDFWriter original obj non-zero gen 0
QPDF_optimization indirect outlines 0

View File

@ -1192,6 +1192,7 @@ my @to_linearize =
'object-stream', # contains object streams
'hybrid-xref', # contains both xref tables and streams
'gen1', # has objects with generation > 0
'direct-outlines', # /Outlines is a direct object
@linearized_files, # we should be able to relinearize
);

File diff suppressed because it is too large Load Diff