From 9067fd683ebf8d6467f8cc5aa7daf5e1f950f846 Mon Sep 17 00:00:00 2001 From: thestig Date: Wed, 23 Nov 2016 14:10:06 -0800 Subject: Add APIs for limited use of document tagged code. BUG=pdfium:568 Review-Url: https://codereview.chromium.org/2519343002 --- fpdfsdk/fpdf_structtree.cpp | 88 ++++++++++++++++++++++++++++++++ fpdfsdk/fpdf_structtree_embeddertest.cpp | 70 +++++++++++++++++++++++++ fpdfsdk/fpdfdoc.cpp | 6 +-- fpdfsdk/fpdfview.cpp | 2 +- fpdfsdk/fpdfview_c_api_test.c | 10 ++++ 5 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 fpdfsdk/fpdf_structtree.cpp create mode 100644 fpdfsdk/fpdf_structtree_embeddertest.cpp (limited to 'fpdfsdk') diff --git a/fpdfsdk/fpdf_structtree.cpp b/fpdfsdk/fpdf_structtree.cpp new file mode 100644 index 0000000000..541c46b378 --- /dev/null +++ b/fpdfsdk/fpdf_structtree.cpp @@ -0,0 +1,88 @@ +// Copyright 2016 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. + +#include "public/fpdf_structtree.h" + +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" +#include "core/fpdfdoc/fpdf_tagged.h" +#include "fpdfsdk/fsdk_define.h" + +namespace { + +IPDF_StructTree* ToStructTree(FPDF_STRUCTTREE struct_tree) { + return reinterpret_cast(struct_tree); +} + +IPDF_StructElement* ToStructTreeElement(FPDF_STRUCTELEMENT struct_element) { + return reinterpret_cast(struct_element); +} + +} // namespace + +DLLEXPORT FPDF_STRUCTTREE STDCALL FPDF_StructTree_GetForPage(FPDF_PAGE page) { + CPDF_Page* pPage = CPDFPageFromFPDFPage(page); + if (!pPage) + return nullptr; + return IPDF_StructTree::LoadPage(pPage->m_pDocument, pPage->m_pFormDict); +} + +DLLEXPORT void STDCALL FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree) { + delete ToStructTree(struct_tree); +} + +DLLEXPORT int STDCALL +FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree) { + IPDF_StructTree* tree = ToStructTree(struct_tree); + return tree ? tree->CountTopElements() : -1; +} + +DLLEXPORT FPDF_STRUCTELEMENT STDCALL +FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index) { + IPDF_StructTree* tree = ToStructTree(struct_tree); + if (!tree || index < 0 || index >= tree->CountTopElements()) + return nullptr; + return tree->GetTopElement(index); +} + +DLLEXPORT unsigned long STDCALL +FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element, + void* buffer, + unsigned long buflen) { + IPDF_StructElement* elem = ToStructTreeElement(struct_element); + if (!elem) + return 0; + + CPDF_Dictionary* dict = elem->GetDict(); + if (!dict) + return 0; + + CFX_WideString str = elem->GetDict()->GetUnicodeTextFor("Alt"); + if (str.IsEmpty()) + return 0; + + CFX_ByteString encodedStr = str.UTF16LE_Encode(); + const unsigned long len = encodedStr.GetLength(); + if (buffer && len <= buflen) + FXSYS_memcpy(buffer, encodedStr.c_str(), len); + return len; +} + +DLLEXPORT int STDCALL +FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element) { + IPDF_StructElement* elem = ToStructTreeElement(struct_element); + return elem ? elem->CountKids() : -1; +} + +DLLEXPORT FPDF_STRUCTELEMENT STDCALL +FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element, + int index) { + IPDF_StructElement* elem = ToStructTreeElement(struct_element); + if (!elem || index < 0 || index >= elem->CountKids()) + return nullptr; + + CPDF_StructKid kid = elem->GetKid(index); + return kid.m_Type == CPDF_StructKid::Element ? kid.m_Element.m_pElement + : nullptr; +} diff --git a/fpdfsdk/fpdf_structtree_embeddertest.cpp b/fpdfsdk/fpdf_structtree_embeddertest.cpp new file mode 100644 index 0000000000..58b3172057 --- /dev/null +++ b/fpdfsdk/fpdf_structtree_embeddertest.cpp @@ -0,0 +1,70 @@ +// Copyright 2016 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. + +#include "core/fxcrt/fx_string.h" +#include "public/fpdf_structtree.h" +#include "testing/embedder_test.h" +#include "testing/test_support.h" + +class FPDFStructTreeEmbeddertest : public EmbedderTest, public TestSaver {}; + +TEST_F(FPDFStructTreeEmbeddertest, GetAltText) { + ASSERT_TRUE(OpenDocument("tagged_alt_text.pdf")); + FPDF_PAGE page = LoadPage(0); + ASSERT_TRUE(page); + + FPDF_STRUCTTREE struct_tree = FPDF_StructTree_GetForPage(page); + ASSERT_TRUE(struct_tree); + ASSERT_EQ(1, FPDF_StructTree_CountChildren(struct_tree)); + + FPDF_STRUCTELEMENT element = FPDF_StructTree_GetChildAtIndex(struct_tree, -1); + EXPECT_EQ(nullptr, element); + element = FPDF_StructTree_GetChildAtIndex(struct_tree, 1); + EXPECT_EQ(nullptr, element); + element = FPDF_StructTree_GetChildAtIndex(struct_tree, 0); + ASSERT_NE(nullptr, element); + EXPECT_EQ(0U, FPDF_StructElement_GetAltText(element, nullptr, 0)); + + ASSERT_EQ(1, FPDF_StructElement_CountChildren(element)); + FPDF_STRUCTELEMENT child_element = + FPDF_StructElement_GetChildAtIndex(element, -1); + EXPECT_EQ(nullptr, child_element); + child_element = FPDF_StructElement_GetChildAtIndex(element, 1); + EXPECT_EQ(nullptr, child_element); + child_element = FPDF_StructElement_GetChildAtIndex(element, 0); + ASSERT_NE(nullptr, child_element); + EXPECT_EQ(0U, FPDF_StructElement_GetAltText(child_element, nullptr, 0)); + + ASSERT_EQ(1, FPDF_StructElement_CountChildren(child_element)); + FPDF_STRUCTELEMENT gchild_element = + FPDF_StructElement_GetChildAtIndex(child_element, -1); + EXPECT_EQ(nullptr, gchild_element); + gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 1); + EXPECT_EQ(nullptr, gchild_element); + gchild_element = FPDF_StructElement_GetChildAtIndex(child_element, 0); + ASSERT_NE(nullptr, gchild_element); + ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, nullptr, 0)); + + unsigned short buffer[12]; + memset(buffer, 0, sizeof(buffer)); + // Deliberately pass in a small buffer size to make sure |buffer| remains + // untouched. + ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer, 1)); + for (size_t i = 0; i < FX_ArraySize(buffer); ++i) + EXPECT_EQ(0U, buffer[i]); + + ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer, + sizeof(buffer))); + const FX_WCHAR kExpected[] = L"Black Image"; + EXPECT_EQ(CFX_WideString(kExpected), + CFX_WideString::FromUTF16LE(buffer, FXSYS_len(kExpected))); + + ASSERT_EQ(1, FPDF_StructElement_CountChildren(gchild_element)); + FPDF_STRUCTELEMENT ggchild_element = + FPDF_StructElement_GetChildAtIndex(gchild_element, 0); + EXPECT_EQ(nullptr, ggchild_element); + + FPDF_StructTree_Close(struct_tree); + FPDF_ClosePage(page); +} diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp index 254be3f883..2dcf606a7c 100644 --- a/fpdfsdk/fpdfdoc.cpp +++ b/fpdfsdk/fpdfdoc.cpp @@ -64,7 +64,7 @@ unsigned long Utf16EncodeMaybeCopyAndReturnLength(const CFX_WideString& text, unsigned long buflen) { CFX_ByteString encodedText = text.UTF16LE_Encode(); unsigned long len = encodedText.GetLength(); - if (buffer && buflen >= len) + if (buffer && len <= buflen) FXSYS_memcpy(buffer, encodedText.c_str(), len); return len; } @@ -186,7 +186,7 @@ DLLEXPORT unsigned long STDCALL FPDFAction_GetFilePath(FPDF_ACTION pDict, CPDF_Action action(ToDictionary(static_cast(pDict))); CFX_ByteString path = action.GetFilePath().UTF8Encode(); unsigned long len = path.GetLength() + 1; - if (buffer && buflen >= len) + if (buffer && len <= buflen) FXSYS_memcpy(buffer, path.c_str(), len); return len; } @@ -203,7 +203,7 @@ DLLEXPORT unsigned long STDCALL FPDFAction_GetURIPath(FPDF_DOCUMENT document, CPDF_Action action(ToDictionary(static_cast(pDict))); CFX_ByteString path = action.GetURI(pDoc); unsigned long len = path.GetLength() + 1; - if (buffer && buflen >= len) + if (buffer && len <= buflen) FXSYS_memcpy(buffer, path.c_str(), len); return len; } diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp index 959bf14390..3f5115afd6 100644 --- a/fpdfsdk/fpdfview.cpp +++ b/fpdfsdk/fpdfview.cpp @@ -1110,7 +1110,7 @@ DLLEXPORT FPDF_DEST STDCALL FPDF_GetNamedDest(FPDF_DOCUMENT document, int len = utf16Name.GetLength(); if (!buffer) { *buflen = len; - } else if (*buflen >= len) { + } else if (len <= *buflen) { memcpy(buffer, utf16Name.c_str(), len); *buflen = len; } else { diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c index 5e6c36f2b1..ed9a3fafe2 100644 --- a/fpdfsdk/fpdfview_c_api_test.c +++ b/fpdfsdk/fpdfview_c_api_test.c @@ -20,6 +20,7 @@ #include "public/fpdf_progressive.h" #include "public/fpdf_save.h" #include "public/fpdf_searchex.h" +#include "public/fpdf_structtree.h" #include "public/fpdf_sysfontinfo.h" #include "public/fpdf_text.h" #include "public/fpdf_transformpage.h" @@ -154,6 +155,15 @@ int CheckPDFiumCApi() { // fpdf_searchex.h CHK(FPDFText_GetCharIndexFromTextIndex); + // fpdf_structtree.h + CHK(FPDF_StructTree_GetForPage); + CHK(FPDF_StructTree_Close); + CHK(FPDF_StructTree_CountChildren); + CHK(FPDF_StructTree_GetChildAtIndex); + CHK(FPDF_StructElement_GetAltText); + CHK(FPDF_StructElement_CountChildren); + CHK(FPDF_StructElement_GetChildAtIndex); + // fpdf_sysfontinfo.h CHK(FPDF_GetDefaultTTFMap); CHK(FPDF_AddInstalledFont); -- cgit v1.2.3