xref: /aosp_15_r20/external/pdfium/fpdfsdk/fpdf_structtree.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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