diff options
Diffstat (limited to 'fpdfsdk/fpdf_doc.cpp')
-rw-r--r-- | fpdfsdk/fpdf_doc.cpp | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/fpdfsdk/fpdf_doc.cpp b/fpdfsdk/fpdf_doc.cpp new file mode 100644 index 0000000000..d8be12066a --- /dev/null +++ b/fpdfsdk/fpdf_doc.cpp @@ -0,0 +1,429 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "public/fpdf_doc.h" + +#include <memory> +#include <set> + +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_array.h" +#include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfdoc/cpdf_bookmark.h" +#include "core/fpdfdoc/cpdf_bookmarktree.h" +#include "core/fpdfdoc/cpdf_dest.h" +#include "core/fpdfdoc/cpdf_pagelabel.h" +#include "fpdfsdk/cpdfsdk_helpers.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" + +namespace { + +CPDF_Bookmark FindBookmark(const CPDF_BookmarkTree& tree, + CPDF_Bookmark bookmark, + const WideString& title, + std::set<CPDF_Dictionary*>* visited) { + // Return if already checked to avoid circular calling. + if (pdfium::ContainsKey(*visited, bookmark.GetDict())) + return CPDF_Bookmark(); + visited->insert(bookmark.GetDict()); + + if (bookmark.GetDict() && + bookmark.GetTitle().CompareNoCase(title.c_str()) == 0) { + // First check this item. + return bookmark; + } + + // Go into children items. + CPDF_Bookmark child = tree.GetFirstChild(bookmark); + while (child.GetDict() && !pdfium::ContainsKey(*visited, child.GetDict())) { + // Check this item and its children. + CPDF_Bookmark found = FindBookmark(tree, child, title, visited); + if (found.GetDict()) + return found; + child = tree.GetNextSibling(child); + } + return CPDF_Bookmark(); +} + +CPDF_LinkList* GetLinkList(CPDF_Page* page) { + if (!page) + return nullptr; + + CPDF_Document* pDoc = page->m_pDocument.Get(); + std::unique_ptr<CPDF_LinkList>* pHolder = pDoc->LinksContext(); + if (!pHolder->get()) + *pHolder = pdfium::MakeUnique<CPDF_LinkList>(); + return pHolder->get(); +} + +CPDF_Array* CPDFArrayFromDest(FPDF_DEST dest) { + return static_cast<CPDF_Array*>(dest); +} + +CPDF_Dictionary* CPDFDictionaryFromFPDFAction(FPDF_ACTION action) { + return ToDictionary(static_cast<CPDF_Object*>(action)); +} + +CPDF_Dictionary* CPDFDictionaryFromFPDFBookmark(FPDF_BOOKMARK bookmark) { + return ToDictionary(static_cast<CPDF_Object*>(bookmark)); +} + +CPDF_Dictionary* CPDFDictionaryFromFPDFLink(FPDF_LINK link) { + return ToDictionary(static_cast<CPDF_Object*>(link)); +} + +} // namespace + +FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV +FPDFBookmark_GetFirstChild(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) { + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return nullptr; + CPDF_BookmarkTree tree(pDoc); + CPDF_Bookmark bookmark(CPDFDictionaryFromFPDFBookmark(pDict)); + return tree.GetFirstChild(bookmark).GetDict(); +} + +FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV +FPDFBookmark_GetNextSibling(FPDF_DOCUMENT document, FPDF_BOOKMARK pDict) { + if (!pDict) + return nullptr; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return nullptr; + CPDF_BookmarkTree tree(pDoc); + CPDF_Bookmark bookmark(CPDFDictionaryFromFPDFBookmark(pDict)); + return tree.GetNextSibling(bookmark).GetDict(); +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFBookmark_GetTitle(FPDF_BOOKMARK pDict, void* buffer, unsigned long buflen) { + if (!pDict) + return 0; + CPDF_Bookmark bookmark(CPDFDictionaryFromFPDFBookmark(pDict)); + WideString title = bookmark.GetTitle(); + return Utf16EncodeMaybeCopyAndReturnLength(title, buffer, buflen); +} + +FPDF_EXPORT FPDF_BOOKMARK FPDF_CALLCONV +FPDFBookmark_Find(FPDF_DOCUMENT document, FPDF_WIDESTRING title) { + if (!title || title[0] == 0) + return nullptr; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return nullptr; + CPDF_BookmarkTree tree(pDoc); + size_t len = WideString::WStringLength(title); + WideString encodedTitle = WideString::FromUTF16LE(title, len); + std::set<CPDF_Dictionary*> visited; + return FindBookmark(tree, CPDF_Bookmark(), encodedTitle, &visited).GetDict(); +} + +FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFBookmark_GetDest(FPDF_DOCUMENT document, + FPDF_BOOKMARK pDict) { + if (!pDict) + return nullptr; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return nullptr; + CPDF_Bookmark bookmark(CPDFDictionaryFromFPDFBookmark(pDict)); + CPDF_Dest dest = bookmark.GetDest(pDoc); + if (dest.GetObject()) + return dest.GetObject(); + // If this bookmark is not directly associated with a dest, we try to get + // action + CPDF_Action action = bookmark.GetAction(); + if (!action.GetDict()) + return nullptr; + return action.GetDest(pDoc).GetObject(); +} + +FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV +FPDFBookmark_GetAction(FPDF_BOOKMARK pDict) { + if (!pDict) + return nullptr; + CPDF_Bookmark bookmark(CPDFDictionaryFromFPDFBookmark(pDict)); + return bookmark.GetAction().GetDict(); +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV FPDFAction_GetType(FPDF_ACTION pDict) { + if (!pDict) + return PDFACTION_UNSUPPORTED; + + CPDF_Action action(CPDFDictionaryFromFPDFAction(pDict)); + CPDF_Action::ActionType type = action.GetType(); + switch (type) { + case CPDF_Action::GoTo: + return PDFACTION_GOTO; + case CPDF_Action::GoToR: + return PDFACTION_REMOTEGOTO; + case CPDF_Action::URI: + return PDFACTION_URI; + case CPDF_Action::Launch: + return PDFACTION_LAUNCH; + default: + return PDFACTION_UNSUPPORTED; + } +} + +FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFAction_GetDest(FPDF_DOCUMENT document, + FPDF_ACTION pDict) { + if (!pDict) + return nullptr; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return nullptr; + CPDF_Action action(CPDFDictionaryFromFPDFAction(pDict)); + return action.GetDest(pDoc).GetObject(); +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFAction_GetFilePath(FPDF_ACTION pDict, void* buffer, unsigned long buflen) { + unsigned long type = FPDFAction_GetType(pDict); + if (type != PDFACTION_REMOTEGOTO && type != PDFACTION_LAUNCH) + return 0; + + CPDF_Action action(CPDFDictionaryFromFPDFAction(pDict)); + ByteString path = action.GetFilePath().UTF8Encode(); + unsigned long len = path.GetLength() + 1; + if (buffer && len <= buflen) + memcpy(buffer, path.c_str(), len); + return len; +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFAction_GetURIPath(FPDF_DOCUMENT document, + FPDF_ACTION pDict, + void* buffer, + unsigned long buflen) { + if (!pDict) + return 0; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return 0; + CPDF_Action action(CPDFDictionaryFromFPDFAction(pDict)); + ByteString path = action.GetURI(pDoc); + unsigned long len = path.GetLength() + 1; + if (buffer && len <= buflen) + memcpy(buffer, path.c_str(), len); + return len; +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFDest_GetPageIndex(FPDF_DOCUMENT document, FPDF_DEST dest) { + if (!dest) + return 0; + + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return 0; + + CPDF_Dest destination(CPDFArrayFromDest(dest)); + return destination.GetPageIndexDeprecated(pDoc); +} + +FPDF_EXPORT int FPDF_CALLCONV FPDFDest_GetDestPageIndex(FPDF_DOCUMENT document, + FPDF_DEST dest) { + if (!dest) + return -1; + + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return -1; + + CPDF_Dest destination(CPDFArrayFromDest(dest)); + return destination.GetDestPageIndex(pDoc); +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDFDest_GetView(FPDF_DEST pDict, + unsigned long* pNumParams, + FS_FLOAT* pParams) { + if (!pDict) { + *pNumParams = 0; + return 0; + } + + CPDF_Dest destination(CPDFArrayFromDest(pDict)); + unsigned long nParams = destination.GetNumParams(); + ASSERT(nParams <= 4); + *pNumParams = nParams; + for (unsigned long i = 0; i < nParams; ++i) + pParams[i] = destination.GetParam(i); + return destination.GetZoomMode(); +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFDest_GetLocationInPage(FPDF_DEST pDict, + FPDF_BOOL* hasXVal, + FPDF_BOOL* hasYVal, + FPDF_BOOL* hasZoomVal, + FS_FLOAT* x, + FS_FLOAT* y, + FS_FLOAT* zoom) { + if (!pDict) + return false; + + auto dest = pdfium::MakeUnique<CPDF_Dest>(CPDFArrayFromDest(pDict)); + + // FPDF_BOOL is an int, GetXYZ expects bools. + bool bHasX; + bool bHasY; + bool bHasZoom; + if (!dest->GetXYZ(&bHasX, &bHasY, &bHasZoom, x, y, zoom)) + return false; + + *hasXVal = bHasX; + *hasYVal = bHasY; + *hasZoomVal = bHasZoom; + return true; +} + +FPDF_EXPORT FPDF_LINK FPDF_CALLCONV FPDFLink_GetLinkAtPoint(FPDF_PAGE page, + double x, + double y) { + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage) + return nullptr; + + CPDF_LinkList* pLinkList = GetLinkList(pPage); + if (!pLinkList) + return nullptr; + + return pLinkList + ->GetLinkAtPoint(pPage, + CFX_PointF(static_cast<float>(x), static_cast<float>(y)), + nullptr) + .GetDict(); +} + +FPDF_EXPORT int FPDF_CALLCONV FPDFLink_GetLinkZOrderAtPoint(FPDF_PAGE page, + double x, + double y) { + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage) + return -1; + + CPDF_LinkList* pLinkList = GetLinkList(pPage); + if (!pLinkList) + return -1; + + int z_order = -1; + pLinkList->GetLinkAtPoint( + pPage, CFX_PointF(static_cast<float>(x), static_cast<float>(y)), + &z_order); + return z_order; +} + +FPDF_EXPORT FPDF_DEST FPDF_CALLCONV FPDFLink_GetDest(FPDF_DOCUMENT document, + FPDF_LINK pDict) { + if (!pDict) + return nullptr; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return nullptr; + CPDF_Link link(CPDFDictionaryFromFPDFLink(pDict)); + FPDF_DEST dest = link.GetDest(pDoc).GetObject(); + if (dest) + return dest; + // If this link is not directly associated with a dest, we try to get action + CPDF_Action action = link.GetAction(); + if (!action.GetDict()) + return nullptr; + return action.GetDest(pDoc).GetObject(); +} + +FPDF_EXPORT FPDF_ACTION FPDF_CALLCONV FPDFLink_GetAction(FPDF_LINK pDict) { + if (!pDict) + return nullptr; + + CPDF_Link link(CPDFDictionaryFromFPDFLink(pDict)); + return link.GetAction().GetDict(); +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_Enumerate(FPDF_PAGE page, + int* start_pos, + FPDF_LINK* link_annot) { + if (!start_pos || !link_annot) + return false; + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage || !pPage->m_pFormDict) + return false; + CPDF_Array* pAnnots = pPage->m_pFormDict->GetArrayFor("Annots"); + if (!pAnnots) + return false; + for (size_t i = *start_pos; i < pAnnots->GetCount(); i++) { + CPDF_Dictionary* pDict = ToDictionary(pAnnots->GetDirectObjectAt(i)); + if (!pDict) + continue; + if (pDict->GetStringFor("Subtype") == "Link") { + *start_pos = static_cast<int>(i + 1); + *link_annot = static_cast<FPDF_LINK>(pDict); + return true; + } + } + return false; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDFLink_GetAnnotRect(FPDF_LINK link_annot, + FS_RECTF* rect) { + if (!link_annot || !rect) + return false; + CPDF_Dictionary* pAnnotDict = CPDFDictionaryFromFPDFLink(link_annot); + FSRECTFFromCFXFloatRect(pAnnotDict->GetRectFor("Rect"), rect); + return true; +} + +FPDF_EXPORT int FPDF_CALLCONV FPDFLink_CountQuadPoints(FPDF_LINK link_annot) { + const CPDF_Array* pArray = + GetQuadPointsArrayFromDictionary(CPDFDictionaryFromFPDFLink(link_annot)); + return pArray ? static_cast<int>(pArray->GetCount() / 8) : 0; +} + +FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV +FPDFLink_GetQuadPoints(FPDF_LINK link_annot, + int quad_index, + FS_QUADPOINTSF* quad_points) { + if (!quad_points || quad_index < 0) + return false; + return GetQuadPointsFromDictionary(CPDFDictionaryFromFPDFLink(link_annot), + static_cast<size_t>(quad_index), + quad_points); +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetMetaText(FPDF_DOCUMENT document, + FPDF_BYTESTRING tag, + void* buffer, + unsigned long buflen) { + if (!tag) + return 0; + CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document); + if (!pDoc) + return 0; + pDoc->LoadDocumentInfo(); + const CPDF_Dictionary* pInfo = pDoc->GetInfo(); + if (!pInfo) + return 0; + WideString text = pInfo->GetUnicodeTextFor(tag); + return Utf16EncodeMaybeCopyAndReturnLength(text, buffer, buflen); +} + +FPDF_EXPORT unsigned long FPDF_CALLCONV +FPDF_GetPageLabel(FPDF_DOCUMENT document, + int page_index, + void* buffer, + unsigned long buflen) { + if (page_index < 0) + return 0; + + // CPDF_PageLabel can deal with NULL |document|. + CPDF_PageLabel label(CPDFDocumentFromFPDFDocument(document)); + Optional<WideString> str = label.GetLabel(page_index); + return str.has_value() + ? Utf16EncodeMaybeCopyAndReturnLength(str.value(), buffer, buflen) + : 0; +} |