Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/fpdfapi/parser/cpdf_base_document.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class CPDF_BaseDocument final : public CPDF_Document, public Retainable {
// full pass over the file — unless the embedder supplied it through
// SetKnownRawBaseSha256(). Reads all-zero when the file cannot be read.
const std::array<uint8_t, 32>& GetRawBaseSha256() const;
// The same hash when it is known already (supplied, or worked out once),
// else null: never hashes the file.
const std::array<uint8_t, 32>* GetKnownRawBaseSha256() const {
return raw_base_sha256_ ? &*raw_base_sha256_ : nullptr;
}
// A host that already hashed the exact bytes it handed us (a storage layer
// verifying a download) need not pay for a second pass. Only an identity
// claim: a wrong value makes this host's own artifacts fail to open on the
Expand Down
44 changes: 40 additions & 4 deletions core/fpdfdoc/cpdf_bookmarktree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,44 @@ CPDF_BookmarkTree::CPDF_BookmarkTree(const CPDF_Document* doc)

CPDF_BookmarkTree::~CPDF_BookmarkTree() = default;

// EmbedPDF(bug-fix): see the declaration. An item has no /Type, and the
// outline's dictionary may say /Outlines; the other keys belong to pages and
// the page tree (/Kids /Contents /MediaBox /Resources), annotations and
// fields (/Subtype /FT) and actions (/S, whose /Next chains actions).
// static
bool CPDF_BookmarkTree::IsOutlineNode(const CPDF_Dictionary* dict) {
if (!dict) {
return false;
}
if (dict->KeyExist("Type") && dict->GetNameFor("Type") != "Outlines") {
return false;
}
for (const char* key :
{"Subtype", "FT", "S", "Kids", "Contents", "MediaBox", "Resources"}) {
if (dict->KeyExist(key)) {
return false;
}
}
return true;
}

namespace {

// EmbedPDF(bug-fix): |dict| as a bookmark when IsOutlineNode() takes it.
CPDF_Bookmark OutlineItem(RetainPtr<const CPDF_Dictionary> dict) {
return CPDF_BookmarkTree::IsOutlineNode(dict.Get())
? CPDF_Bookmark(std::move(dict))
: CPDF_Bookmark();
}

} // namespace

CPDF_Bookmark CPDF_BookmarkTree::GetFirstChild(
const CPDF_Bookmark& parent) const {
const CPDF_Dictionary* parent_dict = parent.GetDict();
if (parent_dict) {
return CPDF_Bookmark(parent_dict->GetDictFor("First"));
// EmbedPDF(bug-fix): only an item IsOutlineNode() takes.
return OutlineItem(parent_dict->GetDictFor("First"));
}

const CPDF_Dictionary* root = document_->GetRoot();
Expand All @@ -31,8 +64,10 @@ CPDF_Bookmark CPDF_BookmarkTree::GetFirstChild(

RetainPtr<const CPDF_Dictionary> outlines =
root->GetDictFor(pdfium::catalog::kOutlines);
return outlines ? CPDF_Bookmark(outlines->GetDictFor("First"))
: CPDF_Bookmark();
// EmbedPDF(bug-fix): only an outline and item IsOutlineNode() takes.
return IsOutlineNode(outlines.Get())
? OutlineItem(outlines->GetDictFor("First"))
: CPDF_Bookmark();
}

CPDF_Bookmark CPDF_BookmarkTree::GetNextSibling(
Expand All @@ -43,5 +78,6 @@ CPDF_Bookmark CPDF_BookmarkTree::GetNextSibling(
}

RetainPtr<const CPDF_Dictionary> next = dict->GetDictFor("Next");
return next != dict ? CPDF_Bookmark(std::move(next)) : CPDF_Bookmark();
// EmbedPDF(bug-fix): only an item IsOutlineNode() takes.
return next != dict ? OutlineItem(std::move(next)) : CPDF_Bookmark();
}
9 changes: 9 additions & 0 deletions core/fpdfdoc/cpdf_bookmarktree.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,22 @@
#include "core/fpdfdoc/cpdf_bookmark.h"
#include "core/fxcrt/unowned_ptr.h"

// EmbedPDF(bug-fix): IsOutlineNode() below reads one.
class CPDF_Dictionary;
class CPDF_Document;

class CPDF_BookmarkTree {
public:
explicit CPDF_BookmarkTree(const CPDF_Document* doc);
~CPDF_BookmarkTree();

// EmbedPDF(bug-fix): upstream took any dictionary that /Outlines, /First or
// /Next reaches as part of the outline, so a broken file that links a page,
// a field or an action there showed it as a bookmark, and an outline
// writer rewrote its links. Whether |dict| can be the outline's dictionary
// or one of its items: it has no key that gives a dictionary another role.
static bool IsOutlineNode(const CPDF_Dictionary* dict);

CPDF_Bookmark GetFirstChild(const CPDF_Bookmark& parent) const;
CPDF_Bookmark GetNextSibling(const CPDF_Bookmark& bookmark) const;

Expand Down
4 changes: 4 additions & 0 deletions fpdfsdk/epdf_c_api_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ int CheckEmbedPDFCApi(void) {
CHK(EPDFDoc_GetAttachmentKey);

// epdf_capture.h
CHK(EPDFAttachment_ExportCanonicalToOwnedBuffer);
CHK(EPDFAttachment_ExportRawToOwnedBuffer);
CHK(EPDFAttachment_ImportRaw);
CHK(EPDFDoc_ExportDictCanonicalToOwnedBuffer);
CHK(EPDFDoc_ExportDictRawToOwnedBuffer);
CHK(EPDFDoc_ImportDictRaw);
CHK(EPDFForm_ExportFieldRawToOwnedBuffer);
Expand Down
Loading