1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "public/fpdf_structtree.h"
6
7 #include <memory>
8
9 #include "core/fpdfapi/page/cpdf_page.h"
10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
11 #include "core/fpdfdoc/cpdf_structelement.h"
12 #include "core/fpdfdoc/cpdf_structtree.h"
13 #include "fpdfsdk/fsdk_define.h"
14
15 namespace {
16
ToStructTree(FPDF_STRUCTTREE struct_tree)17 CPDF_StructTree* ToStructTree(FPDF_STRUCTTREE struct_tree) {
18 return static_cast<CPDF_StructTree*>(struct_tree);
19 }
20
ToStructTreeElement(FPDF_STRUCTELEMENT struct_element)21 CPDF_StructElement* ToStructTreeElement(FPDF_STRUCTELEMENT struct_element) {
22 return static_cast<CPDF_StructElement*>(struct_element);
23 }
24
WideStringToBuffer(const WideString & str,void * buffer,unsigned long buflen)25 unsigned long WideStringToBuffer(const WideString& str,
26 void* buffer,
27 unsigned long buflen) {
28 if (str.IsEmpty())
29 return 0;
30
31 ByteString encodedStr = str.UTF16LE_Encode();
32 const unsigned long len = encodedStr.GetLength();
33 if (buffer && len <= buflen)
34 memcpy(buffer, encodedStr.c_str(), len);
35 return len;
36 }
37
38 } // namespace
39
40 FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV
FPDF_StructTree_GetForPage(FPDF_PAGE page)41 FPDF_StructTree_GetForPage(FPDF_PAGE page) {
42 CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
43 if (!pPage)
44 return nullptr;
45 return CPDF_StructTree::LoadPage(pPage->m_pDocument.Get(),
46 pPage->m_pFormDict.Get())
47 .release();
48 }
49
50 FPDF_EXPORT void FPDF_CALLCONV
FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree)51 FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree) {
52 std::unique_ptr<CPDF_StructTree>(ToStructTree(struct_tree));
53 }
54
55 FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree)56 FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree) {
57 CPDF_StructTree* tree = ToStructTree(struct_tree);
58 if (!tree)
59 return -1;
60
61 pdfium::base::CheckedNumeric<int> tmp_size = tree->CountTopElements();
62 return tmp_size.ValueOrDefault(-1);
63 }
64
65 FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree,int index)66 FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index) {
67 CPDF_StructTree* tree = ToStructTree(struct_tree);
68 if (!tree || index < 0 ||
69 static_cast<size_t>(index) >= tree->CountTopElements()) {
70 return nullptr;
71 }
72 return tree->GetTopElement(static_cast<size_t>(index));
73 }
74
75 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)76 FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,
77 void* buffer,
78 unsigned long buflen) {
79 CPDF_StructElement* elem = ToStructTreeElement(struct_element);
80 return (elem && elem->GetDict())
81 ? WideStringToBuffer(elem->GetDict()->GetUnicodeTextFor("Alt"),
82 buffer, buflen)
83 : 0;
84 }
85
86 FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element)87 FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element) {
88 CPDF_StructElement* elem = ToStructTreeElement(struct_element);
89 CPDF_Object* p =
90 (elem && elem->GetDict()) ? elem->GetDict()->GetObjectFor("K") : nullptr;
91 return p && p->IsNumber() ? p->GetInteger() : -1;
92 }
93
94 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)95 FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,
96 void* buffer,
97 unsigned long buflen) {
98 CPDF_StructElement* elem = ToStructTreeElement(struct_element);
99 return elem ? WideStringToBuffer(elem->GetType().UTF8Decode(), buffer, buflen)
100 : 0;
101 }
102
103 FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)104 FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,
105 void* buffer,
106 unsigned long buflen) {
107 CPDF_StructElement* elem = ToStructTreeElement(struct_element);
108 return elem
109 ? WideStringToBuffer(elem->GetTitle().UTF8Decode(), buffer, buflen)
110 : 0;
111 }
112
113 FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element)114 FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element) {
115 CPDF_StructElement* elem = ToStructTreeElement(struct_element);
116 if (!elem)
117 return -1;
118
119 pdfium::base::CheckedNumeric<int> tmp_size = elem->CountKids();
120 return tmp_size.ValueOrDefault(-1);
121 }
122
123 FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,int index)124 FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,
125 int index) {
126 CPDF_StructElement* elem = ToStructTreeElement(struct_element);
127 if (!elem || index < 0 || static_cast<size_t>(index) >= elem->CountKids())
128 return nullptr;
129
130 return elem->GetKidIfElement(static_cast<size_t>(index));
131 }
132