2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 19:08:59 +00:00

Limited inheritance to the attributes explicitly listed in the PDF spec

Previous versions of qpdf incorrectly passed arbitrary objects from
/Pages objects down to individual pages in direct contradition with
the PDF specification.  These are now left in /Pages.  When
intermediate /Pages nodes are being discarded as when the /Pages tree
is being flattened, a warning is issued when unknown keys are
encountered.
This commit is contained in:
Tobias Hoffmann 2012-06-22 18:52:13 +02:00 committed by Jay Berkenbilt
parent 7770a1b036
commit abb53ac369
4 changed files with 34 additions and 12 deletions

View File

@ -908,11 +908,12 @@ class QPDF
// Methods to support optimization // Methods to support optimization
void pushInheritedAttributesToPage(bool allow_changes); void pushInheritedAttributesToPage(bool allow_changes,
bool warn_skipped_keys);
void pushInheritedAttributesToPageInternal( void pushInheritedAttributesToPageInternal(
QPDFObjectHandle, QPDFObjectHandle,
std::map<std::string, std::vector<QPDFObjectHandle> >&, std::map<std::string, std::vector<QPDFObjectHandle> >&,
bool allow_changes); bool allow_changes, bool warn_skipped_keys);
void updateObjectMaps(ObjUser const& ou, QPDFObjectHandle oh); void updateObjectMaps(ObjUser const& ou, QPDFObjectHandle oh);
void updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh, void updateObjectMapsInternal(ObjUser const& ou, QPDFObjectHandle oh,
std::set<ObjGen>& visited, bool top); std::set<ObjGen>& visited, bool top);

View File

@ -167,7 +167,7 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
// Traverse pages tree pushing all inherited resources down to the // Traverse pages tree pushing all inherited resources down to the
// page level. // page level.
pushInheritedAttributesToPage(allow_changes); pushInheritedAttributesToPage(allow_changes, false);
getAllPages(); getAllPages();
// Traverse pages // Traverse pages
@ -224,11 +224,11 @@ void
QPDF::pushInheritedAttributesToPage() QPDF::pushInheritedAttributesToPage()
{ {
// Public API should not have access to allow_changes. // Public API should not have access to allow_changes.
pushInheritedAttributesToPage(true); pushInheritedAttributesToPage(true, false);
} }
void void
QPDF::pushInheritedAttributesToPage(bool allow_changes) QPDF::pushInheritedAttributesToPage(bool allow_changes, bool warn_skipped_keys)
{ {
// Traverse pages tree pushing all inherited resources down to the // Traverse pages tree pushing all inherited resources down to the
// page level. // page level.
@ -238,7 +238,7 @@ QPDF::pushInheritedAttributesToPage(bool allow_changes)
std::map<std::string, std::vector<QPDFObjectHandle> > key_ancestors; std::map<std::string, std::vector<QPDFObjectHandle> > key_ancestors;
pushInheritedAttributesToPageInternal( pushInheritedAttributesToPageInternal(
this->trailer.getKey("/Root").getKey("/Pages"), this->trailer.getKey("/Root").getKey("/Pages"),
key_ancestors, allow_changes); key_ancestors, allow_changes, warn_skipped_keys);
assert(key_ancestors.empty()); assert(key_ancestors.empty());
} }
@ -246,7 +246,7 @@ void
QPDF::pushInheritedAttributesToPageInternal( QPDF::pushInheritedAttributesToPageInternal(
QPDFObjectHandle cur_pages, QPDFObjectHandle cur_pages,
std::map<std::string, std::vector<QPDFObjectHandle> >& key_ancestors, std::map<std::string, std::vector<QPDFObjectHandle> >& key_ancestors,
bool allow_changes) bool allow_changes, bool warn_skipped_keys)
{ {
// Extract the underlying dictionary object // Extract the underlying dictionary object
std::string type = cur_pages.getKey("/Type").getName(); std::string type = cur_pages.getKey("/Type").getName();
@ -264,8 +264,8 @@ QPDF::pushInheritedAttributesToPageInternal(
iter != keys.end(); ++iter) iter != keys.end(); ++iter)
{ {
std::string const& key = *iter; std::string const& key = *iter;
if (! ((key == "/Type") || (key == "/Parent") || if ( (key == "/MediaBox") || (key == "/CropBox") ||
(key == "/Kids") || (key == "/Count"))) (key == "/Resources") || (key == "/Rotate") )
{ {
if (! allow_changes) if (! allow_changes)
{ {
@ -273,7 +273,7 @@ QPDF::pushInheritedAttributesToPageInternal(
this->last_object_description, this->last_object_description,
this->file->getLastOffset(), this->file->getLastOffset(),
"optimize detected an " "optimize detected an "
"inheritable resource when called " "inheritable attribute when called "
"in no-change mode"); "in no-change mode");
} }
@ -309,6 +309,25 @@ QPDF::pushInheritedAttributesToPageInternal(
// reattached at the page level. // reattached at the page level.
cur_pages.removeKey(key); cur_pages.removeKey(key);
} }
else if (! ((key == "/Type") || (key == "/Parent") ||
(key == "/Kids") || (key == "/Count")))
{
// Warn when flattening, but not if the key is at the top
// level (i.e. "/Parent" not set), as we don't change these;
// but flattening removes intermediate /Pages nodes.
if ( (warn_skipped_keys) && (cur_pages.hasKey("/Parent")) )
{
QTC::TC("qpdf", "QPDF unknown key not inherited");
setLastObjectDescription("Pages object",
cur_pages.getObjectID(),
cur_pages.getGeneration());
warn(QPDFExc(qpdf_e_pages, this->file->getName(),
this->last_object_description, 0,
"Unknown key " + key + " in /Pages object"
" is being discarded as a result of"
" flattening the /Pages tree"));
}
}
} }
// Visit descendant nodes. // Visit descendant nodes.
@ -317,7 +336,8 @@ QPDF::pushInheritedAttributesToPageInternal(
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
{ {
pushInheritedAttributesToPageInternal( pushInheritedAttributesToPageInternal(
kids.getArrayItem(i), key_ancestors, allow_changes); kids.getArrayItem(i), key_ancestors,
allow_changes, warn_skipped_keys);
} }
// For each inheritable key, pop the stack. If the stack // For each inheritable key, pop the stack. If the stack

View File

@ -102,7 +102,7 @@ QPDF::flattenPagesTree()
} }
// Push inherited objects down to the /Page level // Push inherited objects down to the /Page level
pushInheritedAttributesToPage(); pushInheritedAttributesToPage(true, true);
getAllPages(); getAllPages();
QPDFObjectHandle pages = getRoot().getKey("/Pages"); QPDFObjectHandle pages = getRoot().getKey("/Pages");

View File

@ -214,3 +214,4 @@ QPDFObjectHandle shallow copy array 0
QPDFObjectHandle shallow copy dictionary 0 QPDFObjectHandle shallow copy dictionary 0
QPDFObjectHandle shallow copy scalar 0 QPDFObjectHandle shallow copy scalar 0
QPDFObjectHandle newStream with string 0 QPDFObjectHandle newStream with string 0
QPDF unknown key not inherited 0