1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2016 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker
5*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_structtree.h"
6*3ac0a46fSAndroid Build Coastguard Worker
7*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
8*3ac0a46fSAndroid Build Coastguard Worker
9*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_page.h"
10*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_array.h"
11*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_dictionary.h"
12*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfdoc/cpdf_structelement.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfdoc/cpdf_structtree.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_safe_types.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/stl_util.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/numerics/safe_conversions.h"
18*3ac0a46fSAndroid Build Coastguard Worker
19*3ac0a46fSAndroid Build Coastguard Worker namespace {
20*3ac0a46fSAndroid Build Coastguard Worker
WideStringToBuffer(const WideString & str,void * buffer,unsigned long buflen)21*3ac0a46fSAndroid Build Coastguard Worker unsigned long WideStringToBuffer(const WideString& str,
22*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
23*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
24*3ac0a46fSAndroid Build Coastguard Worker if (str.IsEmpty())
25*3ac0a46fSAndroid Build Coastguard Worker return 0;
26*3ac0a46fSAndroid Build Coastguard Worker
27*3ac0a46fSAndroid Build Coastguard Worker ByteString encodedStr = str.ToUTF16LE();
28*3ac0a46fSAndroid Build Coastguard Worker const unsigned long len =
29*3ac0a46fSAndroid Build Coastguard Worker pdfium::base::checked_cast<unsigned long>(encodedStr.GetLength());
30*3ac0a46fSAndroid Build Coastguard Worker if (buffer && len <= buflen)
31*3ac0a46fSAndroid Build Coastguard Worker memcpy(buffer, encodedStr.c_str(), len);
32*3ac0a46fSAndroid Build Coastguard Worker return len;
33*3ac0a46fSAndroid Build Coastguard Worker }
34*3ac0a46fSAndroid Build Coastguard Worker
GetMcidFromDict(const CPDF_Dictionary * dict)35*3ac0a46fSAndroid Build Coastguard Worker int GetMcidFromDict(const CPDF_Dictionary* dict) {
36*3ac0a46fSAndroid Build Coastguard Worker if (dict && dict->GetNameFor("Type") == "MCR") {
37*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> obj = dict->GetObjectFor("MCID");
38*3ac0a46fSAndroid Build Coastguard Worker if (obj && obj->IsNumber())
39*3ac0a46fSAndroid Build Coastguard Worker return obj->GetInteger();
40*3ac0a46fSAndroid Build Coastguard Worker }
41*3ac0a46fSAndroid Build Coastguard Worker return -1;
42*3ac0a46fSAndroid Build Coastguard Worker }
43*3ac0a46fSAndroid Build Coastguard Worker
44*3ac0a46fSAndroid Build Coastguard Worker } // namespace
45*3ac0a46fSAndroid Build Coastguard Worker
46*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_STRUCTTREE FPDF_CALLCONV
FPDF_StructTree_GetForPage(FPDF_PAGE page)47*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructTree_GetForPage(FPDF_PAGE page) {
48*3ac0a46fSAndroid Build Coastguard Worker CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
49*3ac0a46fSAndroid Build Coastguard Worker if (!pPage)
50*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
51*3ac0a46fSAndroid Build Coastguard Worker
52*3ac0a46fSAndroid Build Coastguard Worker // Caller takes onwership.
53*3ac0a46fSAndroid Build Coastguard Worker return FPDFStructTreeFromCPDFStructTree(
54*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructTree::LoadPage(pPage->GetDocument(), pPage->GetDict())
55*3ac0a46fSAndroid Build Coastguard Worker .release());
56*3ac0a46fSAndroid Build Coastguard Worker }
57*3ac0a46fSAndroid Build Coastguard Worker
58*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT void FPDF_CALLCONV
FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree)59*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructTree_Close(FPDF_STRUCTTREE struct_tree) {
60*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<CPDF_StructTree>(
61*3ac0a46fSAndroid Build Coastguard Worker CPDFStructTreeFromFPDFStructTree(struct_tree));
62*3ac0a46fSAndroid Build Coastguard Worker }
63*3ac0a46fSAndroid Build Coastguard Worker
64*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree)65*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructTree_CountChildren(FPDF_STRUCTTREE struct_tree) {
66*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructTree* tree = CPDFStructTreeFromFPDFStructTree(struct_tree);
67*3ac0a46fSAndroid Build Coastguard Worker if (!tree)
68*3ac0a46fSAndroid Build Coastguard Worker return -1;
69*3ac0a46fSAndroid Build Coastguard Worker
70*3ac0a46fSAndroid Build Coastguard Worker FX_SAFE_INT32 tmp_size = tree->CountTopElements();
71*3ac0a46fSAndroid Build Coastguard Worker return tmp_size.ValueOrDefault(-1);
72*3ac0a46fSAndroid Build Coastguard Worker }
73*3ac0a46fSAndroid Build Coastguard Worker
74*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree,int index)75*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructTree_GetChildAtIndex(FPDF_STRUCTTREE struct_tree, int index) {
76*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructTree* tree = CPDFStructTreeFromFPDFStructTree(struct_tree);
77*3ac0a46fSAndroid Build Coastguard Worker if (!tree || index < 0 ||
78*3ac0a46fSAndroid Build Coastguard Worker static_cast<size_t>(index) >= tree->CountTopElements()) {
79*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
80*3ac0a46fSAndroid Build Coastguard Worker }
81*3ac0a46fSAndroid Build Coastguard Worker return FPDFStructElementFromCPDFStructElement(
82*3ac0a46fSAndroid Build Coastguard Worker tree->GetTopElement(static_cast<size_t>(index)));
83*3ac0a46fSAndroid Build Coastguard Worker }
84*3ac0a46fSAndroid Build Coastguard Worker
85*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)86*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetAltText(FPDF_STRUCTELEMENT struct_element,
87*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
88*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
89*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
90*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
91*3ac0a46fSAndroid Build Coastguard Worker return elem ? WideStringToBuffer(elem->GetAltText(), buffer, buflen) : 0;
92*3ac0a46fSAndroid Build Coastguard Worker }
93*3ac0a46fSAndroid Build Coastguard Worker
94*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)95*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetActualText(FPDF_STRUCTELEMENT struct_element,
96*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
97*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
98*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
99*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
100*3ac0a46fSAndroid Build Coastguard Worker return elem ? WideStringToBuffer(elem->GetActualText(), buffer, buflen) : 0;
101*3ac0a46fSAndroid Build Coastguard Worker }
102*3ac0a46fSAndroid Build Coastguard Worker
103*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)104*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetID(FPDF_STRUCTELEMENT struct_element,
105*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
106*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
107*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
108*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
109*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
110*3ac0a46fSAndroid Build Coastguard Worker return 0;
111*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> id = elem->GetID();
112*3ac0a46fSAndroid Build Coastguard Worker if (!id.has_value())
113*3ac0a46fSAndroid Build Coastguard Worker return 0;
114*3ac0a46fSAndroid Build Coastguard Worker return Utf16EncodeMaybeCopyAndReturnLength(id.value(), buffer, buflen);
115*3ac0a46fSAndroid Build Coastguard Worker }
116*3ac0a46fSAndroid Build Coastguard Worker
117*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)118*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetLang(FPDF_STRUCTELEMENT struct_element,
119*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
120*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
121*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
122*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
123*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
124*3ac0a46fSAndroid Build Coastguard Worker return 0;
125*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> lang = elem->GetLang();
126*3ac0a46fSAndroid Build Coastguard Worker if (!lang.has_value())
127*3ac0a46fSAndroid Build Coastguard Worker return 0;
128*3ac0a46fSAndroid Build Coastguard Worker return Utf16EncodeMaybeCopyAndReturnLength(lang.value(), buffer, buflen);
129*3ac0a46fSAndroid Build Coastguard Worker }
130*3ac0a46fSAndroid Build Coastguard Worker
131*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element)132*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetAttributeCount(FPDF_STRUCTELEMENT struct_element) {
133*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
134*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
135*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
136*3ac0a46fSAndroid Build Coastguard Worker return -1;
137*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> attr_obj = elem->GetA();
138*3ac0a46fSAndroid Build Coastguard Worker if (!attr_obj) {
139*3ac0a46fSAndroid Build Coastguard Worker return -1;
140*3ac0a46fSAndroid Build Coastguard Worker }
141*3ac0a46fSAndroid Build Coastguard Worker attr_obj = attr_obj->GetDirect();
142*3ac0a46fSAndroid Build Coastguard Worker if (!attr_obj)
143*3ac0a46fSAndroid Build Coastguard Worker return -1;
144*3ac0a46fSAndroid Build Coastguard Worker if (attr_obj->IsArray())
145*3ac0a46fSAndroid Build Coastguard Worker return fxcrt::CollectionSize<int>(*attr_obj->AsArray());
146*3ac0a46fSAndroid Build Coastguard Worker return attr_obj->IsDictionary() ? 1 : -1;
147*3ac0a46fSAndroid Build Coastguard Worker }
148*3ac0a46fSAndroid Build Coastguard Worker
149*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_STRUCTELEMENT_ATTR FPDF_CALLCONV
FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element,int index)150*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetAttributeAtIndex(FPDF_STRUCTELEMENT struct_element,
151*3ac0a46fSAndroid Build Coastguard Worker int index) {
152*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
153*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
154*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
155*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
156*3ac0a46fSAndroid Build Coastguard Worker
157*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> attr_obj = elem->GetA();
158*3ac0a46fSAndroid Build Coastguard Worker if (!attr_obj)
159*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
160*3ac0a46fSAndroid Build Coastguard Worker
161*3ac0a46fSAndroid Build Coastguard Worker attr_obj = attr_obj->GetDirect();
162*3ac0a46fSAndroid Build Coastguard Worker if (!attr_obj) {
163*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
164*3ac0a46fSAndroid Build Coastguard Worker }
165*3ac0a46fSAndroid Build Coastguard Worker if (attr_obj->IsDictionary()) {
166*3ac0a46fSAndroid Build Coastguard Worker return index == 0 ? FPDFStructElementAttrFromCPDFDictionary(
167*3ac0a46fSAndroid Build Coastguard Worker attr_obj->AsDictionary())
168*3ac0a46fSAndroid Build Coastguard Worker : nullptr;
169*3ac0a46fSAndroid Build Coastguard Worker }
170*3ac0a46fSAndroid Build Coastguard Worker if (attr_obj->IsArray()) {
171*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Array* array = attr_obj->AsArray();
172*3ac0a46fSAndroid Build Coastguard Worker if (index < 0 || static_cast<size_t>(index) >= array->size())
173*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
174*3ac0a46fSAndroid Build Coastguard Worker
175*3ac0a46fSAndroid Build Coastguard Worker // TODO(tsepez): should embedder take a reference here?
176*3ac0a46fSAndroid Build Coastguard Worker // Unretained reference in public API. NOLINTNEXTLINE
177*3ac0a46fSAndroid Build Coastguard Worker return FPDFStructElementAttrFromCPDFDictionary(array->GetDictAt(index));
178*3ac0a46fSAndroid Build Coastguard Worker }
179*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
180*3ac0a46fSAndroid Build Coastguard Worker }
181*3ac0a46fSAndroid Build Coastguard Worker
182*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element,FPDF_BYTESTRING attr_name,void * buffer,unsigned long buflen)183*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetStringAttribute(FPDF_STRUCTELEMENT struct_element,
184*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING attr_name,
185*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
186*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
187*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
188*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
189*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
190*3ac0a46fSAndroid Build Coastguard Worker return 0;
191*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Array> array = ToArray(elem->GetA());
192*3ac0a46fSAndroid Build Coastguard Worker if (!array)
193*3ac0a46fSAndroid Build Coastguard Worker return 0;
194*3ac0a46fSAndroid Build Coastguard Worker CPDF_ArrayLocker locker(array);
195*3ac0a46fSAndroid Build Coastguard Worker for (const RetainPtr<CPDF_Object>& obj : locker) {
196*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* obj_dict = obj->AsDictionary();
197*3ac0a46fSAndroid Build Coastguard Worker if (!obj_dict)
198*3ac0a46fSAndroid Build Coastguard Worker continue;
199*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> attr = obj_dict->GetObjectFor(attr_name);
200*3ac0a46fSAndroid Build Coastguard Worker if (!attr || !(attr->IsString() || attr->IsName()))
201*3ac0a46fSAndroid Build Coastguard Worker continue;
202*3ac0a46fSAndroid Build Coastguard Worker return Utf16EncodeMaybeCopyAndReturnLength(attr->GetUnicodeText(), buffer,
203*3ac0a46fSAndroid Build Coastguard Worker buflen);
204*3ac0a46fSAndroid Build Coastguard Worker }
205*3ac0a46fSAndroid Build Coastguard Worker return 0;
206*3ac0a46fSAndroid Build Coastguard Worker }
207*3ac0a46fSAndroid Build Coastguard Worker
208*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element)209*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetMarkedContentID(FPDF_STRUCTELEMENT struct_element) {
210*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
211*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
212*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
213*3ac0a46fSAndroid Build Coastguard Worker return -1;
214*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> p = elem->GetK();
215*3ac0a46fSAndroid Build Coastguard Worker return p && p->IsNumber() ? p->GetInteger() : -1;
216*3ac0a46fSAndroid Build Coastguard Worker }
217*3ac0a46fSAndroid Build Coastguard Worker
218*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)219*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetType(FPDF_STRUCTELEMENT struct_element,
220*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
221*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
222*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
223*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
224*3ac0a46fSAndroid Build Coastguard Worker return elem ? WideStringToBuffer(
225*3ac0a46fSAndroid Build Coastguard Worker WideString::FromUTF8(elem->GetType().AsStringView()),
226*3ac0a46fSAndroid Build Coastguard Worker buffer, buflen)
227*3ac0a46fSAndroid Build Coastguard Worker : 0;
228*3ac0a46fSAndroid Build Coastguard Worker }
229*3ac0a46fSAndroid Build Coastguard Worker
230*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)231*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetObjType(FPDF_STRUCTELEMENT struct_element,
232*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
233*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
234*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
235*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
236*3ac0a46fSAndroid Build Coastguard Worker return elem ? WideStringToBuffer(
237*3ac0a46fSAndroid Build Coastguard Worker WideString::FromUTF8(elem->GetObjType().AsStringView()),
238*3ac0a46fSAndroid Build Coastguard Worker buffer, buflen)
239*3ac0a46fSAndroid Build Coastguard Worker : 0;
240*3ac0a46fSAndroid Build Coastguard Worker }
241*3ac0a46fSAndroid Build Coastguard Worker
242*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT unsigned long FPDF_CALLCONV
FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,void * buffer,unsigned long buflen)243*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetTitle(FPDF_STRUCTELEMENT struct_element,
244*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
245*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen) {
246*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
247*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
248*3ac0a46fSAndroid Build Coastguard Worker return elem ? WideStringToBuffer(elem->GetTitle(), buffer, buflen) : 0;
249*3ac0a46fSAndroid Build Coastguard Worker }
250*3ac0a46fSAndroid Build Coastguard Worker
251*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element)252*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_CountChildren(FPDF_STRUCTELEMENT struct_element) {
253*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
254*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
255*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
256*3ac0a46fSAndroid Build Coastguard Worker return -1;
257*3ac0a46fSAndroid Build Coastguard Worker
258*3ac0a46fSAndroid Build Coastguard Worker FX_SAFE_INT32 tmp_size = elem->CountKids();
259*3ac0a46fSAndroid Build Coastguard Worker return tmp_size.ValueOrDefault(-1);
260*3ac0a46fSAndroid Build Coastguard Worker }
261*3ac0a46fSAndroid Build Coastguard Worker
262*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,int index)263*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetChildAtIndex(FPDF_STRUCTELEMENT struct_element,
264*3ac0a46fSAndroid Build Coastguard Worker int index) {
265*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
266*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
267*3ac0a46fSAndroid Build Coastguard Worker if (!elem || index < 0 || static_cast<size_t>(index) >= elem->CountKids())
268*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
269*3ac0a46fSAndroid Build Coastguard Worker
270*3ac0a46fSAndroid Build Coastguard Worker return FPDFStructElementFromCPDFStructElement(elem->GetKidIfElement(index));
271*3ac0a46fSAndroid Build Coastguard Worker }
272*3ac0a46fSAndroid Build Coastguard Worker
273*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_STRUCTELEMENT FPDF_CALLCONV
FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element)274*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetParent(FPDF_STRUCTELEMENT struct_element) {
275*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
276*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
277*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* parent = elem ? elem->GetParent() : nullptr;
278*3ac0a46fSAndroid Build Coastguard Worker if (!parent) {
279*3ac0a46fSAndroid Build Coastguard Worker return nullptr;
280*3ac0a46fSAndroid Build Coastguard Worker }
281*3ac0a46fSAndroid Build Coastguard Worker return FPDFStructElementFromCPDFStructElement(parent);
282*3ac0a46fSAndroid Build Coastguard Worker }
283*3ac0a46fSAndroid Build Coastguard Worker
284*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute)285*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_Attr_GetCount(FPDF_STRUCTELEMENT_ATTR struct_attribute) {
286*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
287*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
288*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
289*3ac0a46fSAndroid Build Coastguard Worker return -1;
290*3ac0a46fSAndroid Build Coastguard Worker return fxcrt::CollectionSize<int>(*dict);
291*3ac0a46fSAndroid Build Coastguard Worker }
292*3ac0a46fSAndroid Build Coastguard Worker
293*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute,int index,void * buffer,unsigned long buflen,unsigned long * out_buflen)294*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_Attr_GetName(FPDF_STRUCTELEMENT_ATTR struct_attribute,
295*3ac0a46fSAndroid Build Coastguard Worker int index,
296*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
297*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen,
298*3ac0a46fSAndroid Build Coastguard Worker unsigned long* out_buflen) {
299*3ac0a46fSAndroid Build Coastguard Worker if (!out_buflen) {
300*3ac0a46fSAndroid Build Coastguard Worker return false;
301*3ac0a46fSAndroid Build Coastguard Worker }
302*3ac0a46fSAndroid Build Coastguard Worker
303*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
304*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
305*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
306*3ac0a46fSAndroid Build Coastguard Worker return false;
307*3ac0a46fSAndroid Build Coastguard Worker
308*3ac0a46fSAndroid Build Coastguard Worker CPDF_DictionaryLocker locker(dict);
309*3ac0a46fSAndroid Build Coastguard Worker for (auto& it : locker) {
310*3ac0a46fSAndroid Build Coastguard Worker if (index == 0) {
311*3ac0a46fSAndroid Build Coastguard Worker *out_buflen =
312*3ac0a46fSAndroid Build Coastguard Worker NulTerminateMaybeCopyAndReturnLength(it.first, buffer, buflen);
313*3ac0a46fSAndroid Build Coastguard Worker return true;
314*3ac0a46fSAndroid Build Coastguard Worker }
315*3ac0a46fSAndroid Build Coastguard Worker --index;
316*3ac0a46fSAndroid Build Coastguard Worker }
317*3ac0a46fSAndroid Build Coastguard Worker return false;
318*3ac0a46fSAndroid Build Coastguard Worker }
319*3ac0a46fSAndroid Build Coastguard Worker
320*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_OBJECT_TYPE FPDF_CALLCONV
FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR struct_attribute,FPDF_BYTESTRING name)321*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_Attr_GetType(FPDF_STRUCTELEMENT_ATTR struct_attribute,
322*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING name) {
323*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
324*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
325*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
326*3ac0a46fSAndroid Build Coastguard Worker return FPDF_OBJECT_UNKNOWN;
327*3ac0a46fSAndroid Build Coastguard Worker
328*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> obj = dict->GetObjectFor(name);
329*3ac0a46fSAndroid Build Coastguard Worker return obj ? obj->GetType() : FPDF_OBJECT_UNKNOWN;
330*3ac0a46fSAndroid Build Coastguard Worker }
331*3ac0a46fSAndroid Build Coastguard Worker
FPDF_StructElement_Attr_GetBooleanValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,FPDF_BYTESTRING name,FPDF_BOOL * out_value)332*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FPDF_StructElement_Attr_GetBooleanValue(
333*3ac0a46fSAndroid Build Coastguard Worker FPDF_STRUCTELEMENT_ATTR struct_attribute,
334*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING name,
335*3ac0a46fSAndroid Build Coastguard Worker FPDF_BOOL* out_value) {
336*3ac0a46fSAndroid Build Coastguard Worker if (!out_value)
337*3ac0a46fSAndroid Build Coastguard Worker return false;
338*3ac0a46fSAndroid Build Coastguard Worker
339*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
340*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
341*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
342*3ac0a46fSAndroid Build Coastguard Worker return false;
343*3ac0a46fSAndroid Build Coastguard Worker
344*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> obj = dict->GetObjectFor(name);
345*3ac0a46fSAndroid Build Coastguard Worker if (!obj || !obj->IsBoolean())
346*3ac0a46fSAndroid Build Coastguard Worker return false;
347*3ac0a46fSAndroid Build Coastguard Worker
348*3ac0a46fSAndroid Build Coastguard Worker *out_value = obj->GetInteger();
349*3ac0a46fSAndroid Build Coastguard Worker return true;
350*3ac0a46fSAndroid Build Coastguard Worker }
351*3ac0a46fSAndroid Build Coastguard Worker
352*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,FPDF_BYTESTRING name,float * out_value)353*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_Attr_GetNumberValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,
354*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING name,
355*3ac0a46fSAndroid Build Coastguard Worker float* out_value) {
356*3ac0a46fSAndroid Build Coastguard Worker if (!out_value)
357*3ac0a46fSAndroid Build Coastguard Worker return false;
358*3ac0a46fSAndroid Build Coastguard Worker
359*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
360*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
361*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
362*3ac0a46fSAndroid Build Coastguard Worker return false;
363*3ac0a46fSAndroid Build Coastguard Worker
364*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> obj = dict->GetDirectObjectFor(name);
365*3ac0a46fSAndroid Build Coastguard Worker if (!obj || !obj->IsNumber())
366*3ac0a46fSAndroid Build Coastguard Worker return false;
367*3ac0a46fSAndroid Build Coastguard Worker
368*3ac0a46fSAndroid Build Coastguard Worker *out_value = obj->GetNumber();
369*3ac0a46fSAndroid Build Coastguard Worker return true;
370*3ac0a46fSAndroid Build Coastguard Worker }
371*3ac0a46fSAndroid Build Coastguard Worker
372*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,FPDF_BYTESTRING name,void * buffer,unsigned long buflen,unsigned long * out_buflen)373*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_Attr_GetStringValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,
374*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING name,
375*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
376*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen,
377*3ac0a46fSAndroid Build Coastguard Worker unsigned long* out_buflen) {
378*3ac0a46fSAndroid Build Coastguard Worker if (!out_buflen)
379*3ac0a46fSAndroid Build Coastguard Worker return false;
380*3ac0a46fSAndroid Build Coastguard Worker
381*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
382*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
383*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
384*3ac0a46fSAndroid Build Coastguard Worker return false;
385*3ac0a46fSAndroid Build Coastguard Worker
386*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> obj = dict->GetObjectFor(name);
387*3ac0a46fSAndroid Build Coastguard Worker if (!obj || !(obj->IsString() || obj->IsName()))
388*3ac0a46fSAndroid Build Coastguard Worker return false;
389*3ac0a46fSAndroid Build Coastguard Worker
390*3ac0a46fSAndroid Build Coastguard Worker *out_buflen = Utf16EncodeMaybeCopyAndReturnLength(
391*3ac0a46fSAndroid Build Coastguard Worker WideString::FromUTF8(obj->GetString().AsStringView()), buffer, buflen);
392*3ac0a46fSAndroid Build Coastguard Worker return true;
393*3ac0a46fSAndroid Build Coastguard Worker }
394*3ac0a46fSAndroid Build Coastguard Worker
395*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,FPDF_BYTESTRING name,void * buffer,unsigned long buflen,unsigned long * out_buflen)396*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_Attr_GetBlobValue(FPDF_STRUCTELEMENT_ATTR struct_attribute,
397*3ac0a46fSAndroid Build Coastguard Worker FPDF_BYTESTRING name,
398*3ac0a46fSAndroid Build Coastguard Worker void* buffer,
399*3ac0a46fSAndroid Build Coastguard Worker unsigned long buflen,
400*3ac0a46fSAndroid Build Coastguard Worker unsigned long* out_buflen) {
401*3ac0a46fSAndroid Build Coastguard Worker if (!out_buflen)
402*3ac0a46fSAndroid Build Coastguard Worker return false;
403*3ac0a46fSAndroid Build Coastguard Worker
404*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Dictionary* dict =
405*3ac0a46fSAndroid Build Coastguard Worker CPDFDictionaryFromFPDFStructElementAttr(struct_attribute);
406*3ac0a46fSAndroid Build Coastguard Worker if (!dict)
407*3ac0a46fSAndroid Build Coastguard Worker return false;
408*3ac0a46fSAndroid Build Coastguard Worker
409*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> obj = dict->GetObjectFor(name);
410*3ac0a46fSAndroid Build Coastguard Worker if (!obj || !obj->IsString())
411*3ac0a46fSAndroid Build Coastguard Worker return false;
412*3ac0a46fSAndroid Build Coastguard Worker
413*3ac0a46fSAndroid Build Coastguard Worker ByteString result = obj->GetString();
414*3ac0a46fSAndroid Build Coastguard Worker const unsigned long len =
415*3ac0a46fSAndroid Build Coastguard Worker pdfium::base::checked_cast<unsigned long>(result.GetLength());
416*3ac0a46fSAndroid Build Coastguard Worker if (buffer && len <= buflen)
417*3ac0a46fSAndroid Build Coastguard Worker memcpy(buffer, result.c_str(), len);
418*3ac0a46fSAndroid Build Coastguard Worker
419*3ac0a46fSAndroid Build Coastguard Worker *out_buflen = len;
420*3ac0a46fSAndroid Build Coastguard Worker return true;
421*3ac0a46fSAndroid Build Coastguard Worker }
422*3ac0a46fSAndroid Build Coastguard Worker
423*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element)424*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetMarkedContentIdCount(FPDF_STRUCTELEMENT struct_element) {
425*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
426*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
427*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
428*3ac0a46fSAndroid Build Coastguard Worker return -1;
429*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> p = elem->GetK();
430*3ac0a46fSAndroid Build Coastguard Worker if (!p)
431*3ac0a46fSAndroid Build Coastguard Worker return -1;
432*3ac0a46fSAndroid Build Coastguard Worker
433*3ac0a46fSAndroid Build Coastguard Worker if (p->IsNumber() || p->IsDictionary())
434*3ac0a46fSAndroid Build Coastguard Worker return 1;
435*3ac0a46fSAndroid Build Coastguard Worker
436*3ac0a46fSAndroid Build Coastguard Worker return p->IsArray() ? fxcrt::CollectionSize<int>(*p->AsArray()) : -1;
437*3ac0a46fSAndroid Build Coastguard Worker }
438*3ac0a46fSAndroid Build Coastguard Worker
439*3ac0a46fSAndroid Build Coastguard Worker FPDF_EXPORT int FPDF_CALLCONV
FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element,int index)440*3ac0a46fSAndroid Build Coastguard Worker FPDF_StructElement_GetMarkedContentIdAtIndex(FPDF_STRUCTELEMENT struct_element,
441*3ac0a46fSAndroid Build Coastguard Worker int index) {
442*3ac0a46fSAndroid Build Coastguard Worker CPDF_StructElement* elem =
443*3ac0a46fSAndroid Build Coastguard Worker CPDFStructElementFromFPDFStructElement(struct_element);
444*3ac0a46fSAndroid Build Coastguard Worker if (!elem)
445*3ac0a46fSAndroid Build Coastguard Worker return -1;
446*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> p = elem->GetK();
447*3ac0a46fSAndroid Build Coastguard Worker if (!p)
448*3ac0a46fSAndroid Build Coastguard Worker return -1;
449*3ac0a46fSAndroid Build Coastguard Worker
450*3ac0a46fSAndroid Build Coastguard Worker if (p->IsNumber())
451*3ac0a46fSAndroid Build Coastguard Worker return index == 0 ? p->GetInteger() : -1;
452*3ac0a46fSAndroid Build Coastguard Worker
453*3ac0a46fSAndroid Build Coastguard Worker if (p->IsDictionary())
454*3ac0a46fSAndroid Build Coastguard Worker return GetMcidFromDict(p->GetDict().Get());
455*3ac0a46fSAndroid Build Coastguard Worker
456*3ac0a46fSAndroid Build Coastguard Worker if (p->IsArray()) {
457*3ac0a46fSAndroid Build Coastguard Worker const CPDF_Array* array = p->AsArray();
458*3ac0a46fSAndroid Build Coastguard Worker if (index < 0 || static_cast<size_t>(index) >= array->size())
459*3ac0a46fSAndroid Build Coastguard Worker return -1;
460*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<const CPDF_Object> array_elem = array->GetObjectAt(index);
461*3ac0a46fSAndroid Build Coastguard Worker if (array_elem->IsNumber())
462*3ac0a46fSAndroid Build Coastguard Worker return array_elem->GetInteger();
463*3ac0a46fSAndroid Build Coastguard Worker if (array_elem->IsDictionary()) {
464*3ac0a46fSAndroid Build Coastguard Worker return GetMcidFromDict(array_elem->GetDict().Get());
465*3ac0a46fSAndroid Build Coastguard Worker }
466*3ac0a46fSAndroid Build Coastguard Worker }
467*3ac0a46fSAndroid Build Coastguard Worker return -1;
468*3ac0a46fSAndroid Build Coastguard Worker }
469