1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "fxjs/xfa/cjx_tree.h"
8
9 #include <vector>
10
11 #include "fxjs/fxv8.h"
12 #include "fxjs/js_resources.h"
13 #include "fxjs/xfa/cfxjse_class.h"
14 #include "fxjs/xfa/cfxjse_engine.h"
15 #include "third_party/base/numerics/safe_conversions.h"
16 #include "v8/include/cppgc/allocation.h"
17 #include "v8/include/v8-object.h"
18 #include "v8/include/v8-primitive.h"
19 #include "xfa/fxfa/parser/cxfa_arraynodelist.h"
20 #include "xfa/fxfa/parser/cxfa_attachnodelist.h"
21 #include "xfa/fxfa/parser/cxfa_document.h"
22 #include "xfa/fxfa/parser/cxfa_node.h"
23 #include "xfa/fxfa/parser/cxfa_object.h"
24
25 const CJX_MethodSpec CJX_Tree::MethodSpecs[] = {
26 {"resolveNode", resolveNode_static},
27 {"resolveNodes", resolveNodes_static}};
28
CJX_Tree(CXFA_Object * obj)29 CJX_Tree::CJX_Tree(CXFA_Object* obj) : CJX_Object(obj) {
30 DefineMethods(MethodSpecs);
31 }
32
33 CJX_Tree::~CJX_Tree() = default;
34
DynamicTypeIs(TypeTag eType) const35 bool CJX_Tree::DynamicTypeIs(TypeTag eType) const {
36 return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
37 }
38
resolveNode(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)39 CJS_Result CJX_Tree::resolveNode(
40 CFXJSE_Engine* runtime,
41 const std::vector<v8::Local<v8::Value>>& params) {
42 if (params.size() != 1)
43 return CJS_Result::Failure(JSMessage::kParamError);
44
45 WideString wsExpression = runtime->ToWideString(params[0]);
46 CXFA_Object* pRefNode = GetXFAObject();
47 if (pRefNode->GetElementType() == XFA_Element::Xfa)
48 pRefNode = runtime->GetThisObject();
49
50 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
51 runtime->ResolveObjects(
52 ToNode(pRefNode), wsExpression.AsStringView(),
53 Mask<XFA_ResolveFlag>{
54 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
55 XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
56 XFA_ResolveFlag::kSiblings});
57 if (!maybeResult.has_value())
58 return CJS_Result::Success(runtime->NewNull());
59
60 if (maybeResult.value().type == CFXJSE_Engine::ResolveResult::Type::kNodes) {
61 return CJS_Result::Success(runtime->GetOrCreateJSBindingFromMap(
62 maybeResult.value().objects.front().Get()));
63 }
64
65 if (!maybeResult.value().script_attribute.callback ||
66 maybeResult.value().script_attribute.eValueType !=
67 XFA_ScriptType::Object) {
68 return CJS_Result::Success(runtime->NewNull());
69 }
70
71 v8::Local<v8::Value> pValue;
72 CJX_Object* jsObject = maybeResult.value().objects.front()->JSObject();
73 (*maybeResult.value().script_attribute.callback)(
74 runtime->GetIsolate(), jsObject, &pValue, false,
75 maybeResult.value().script_attribute.attribute);
76 return CJS_Result::Success(pValue);
77 }
78
resolveNodes(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)79 CJS_Result CJX_Tree::resolveNodes(
80 CFXJSE_Engine* runtime,
81 const std::vector<v8::Local<v8::Value>>& params) {
82 if (params.size() != 1)
83 return CJS_Result::Failure(JSMessage::kParamError);
84
85 CXFA_Object* refNode = GetXFAObject();
86 if (refNode->GetElementType() == XFA_Element::Xfa)
87 refNode = runtime->GetThisObject();
88
89 const Mask<XFA_ResolveFlag> kFlags = {
90 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
91 XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
92 XFA_ResolveFlag::kSiblings};
93 return CJS_Result::Success(ResolveNodeList(runtime->GetIsolate(),
94 runtime->ToWideString(params[0]),
95 kFlags, ToNode(refNode)));
96 }
97
all(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)98 void CJX_Tree::all(v8::Isolate* pIsolate,
99 v8::Local<v8::Value>* pValue,
100 bool bSetting,
101 XFA_Attribute eAttribute) {
102 if (bSetting) {
103 ThrowInvalidPropertyException(pIsolate);
104 return;
105 }
106 const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
107 XFA_ResolveFlag::kALL};
108 WideString wsExpression = GetAttributeByEnum(XFA_Attribute::Name) + L"[*]";
109 *pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
110 }
111
classAll(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)112 void CJX_Tree::classAll(v8::Isolate* pIsolate,
113 v8::Local<v8::Value>* pValue,
114 bool bSetting,
115 XFA_Attribute eAttribute) {
116 if (bSetting) {
117 ThrowInvalidPropertyException(pIsolate);
118 return;
119 }
120 const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
121 XFA_ResolveFlag::kALL};
122 WideString wsExpression =
123 L"#" + WideString::FromASCII(GetXFAObject()->GetClassName()) + L"[*]";
124 *pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
125 }
126
nodes(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)127 void CJX_Tree::nodes(v8::Isolate* pIsolate,
128 v8::Local<v8::Value>* pValue,
129 bool bSetting,
130 XFA_Attribute eAttribute) {
131 if (bSetting) {
132 WideString wsMessage = L"Unable to set ";
133 FXJSE_ThrowMessage(pIsolate, wsMessage.ToUTF8().AsStringView());
134 return;
135 }
136
137 CXFA_Document* pDoc = GetDocument();
138 auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_AttachNodeList>(
139 pDoc->GetHeap()->GetAllocationHandle(), pDoc, GetXFANode());
140 pDoc->GetNodeOwner()->PersistList(pNodeList);
141
142 CFXJSE_Engine* pEngine = pDoc->GetScriptContext();
143 *pValue = pNodeList->JSObject()->NewBoundV8Object(
144 pIsolate, pEngine->GetJseNormalClass()->GetTemplate(pIsolate));
145 }
146
parent(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)147 void CJX_Tree::parent(v8::Isolate* pIsolate,
148 v8::Local<v8::Value>* pValue,
149 bool bSetting,
150 XFA_Attribute eAttribute) {
151 if (bSetting) {
152 ThrowInvalidPropertyException(pIsolate);
153 return;
154 }
155
156 CXFA_Node* pParent = GetXFANode()->GetParent();
157 *pValue = pParent ? GetDocument()
158 ->GetScriptContext()
159 ->GetOrCreateJSBindingFromMap(pParent)
160 .As<v8::Value>()
161 : fxv8::NewNullHelper(pIsolate).As<v8::Value>();
162 }
163
index(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)164 void CJX_Tree::index(v8::Isolate* pIsolate,
165 v8::Local<v8::Value>* pValue,
166 bool bSetting,
167 XFA_Attribute eAttribute) {
168 if (bSetting) {
169 ThrowInvalidPropertyException(pIsolate);
170 return;
171 }
172
173 CXFA_Node* pNode = GetXFANode();
174 size_t iIndex = pNode ? pNode->GetIndexByName() : 0;
175 *pValue = fxv8::NewNumberHelper(pIsolate,
176 pdfium::base::checked_cast<int32_t>(iIndex));
177 }
178
classIndex(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)179 void CJX_Tree::classIndex(v8::Isolate* pIsolate,
180 v8::Local<v8::Value>* pValue,
181 bool bSetting,
182 XFA_Attribute eAttribute) {
183 if (bSetting) {
184 ThrowInvalidPropertyException(pIsolate);
185 return;
186 }
187
188 CXFA_Node* pNode = GetXFANode();
189 size_t iIndex = pNode ? pNode->GetIndexByClassName() : 0;
190 *pValue = fxv8::NewNumberHelper(pIsolate,
191 pdfium::base::checked_cast<int32_t>(iIndex));
192 }
193
somExpression(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)194 void CJX_Tree::somExpression(v8::Isolate* pIsolate,
195 v8::Local<v8::Value>* pValue,
196 bool bSetting,
197 XFA_Attribute eAttribute) {
198 if (bSetting) {
199 ThrowInvalidPropertyException(pIsolate);
200 return;
201 }
202
203 ByteString bsSOMExpression = GetXFAObject()->GetSOMExpression().ToUTF8();
204 *pValue = fxv8::NewStringHelper(pIsolate, bsSOMExpression.AsStringView());
205 }
206
ResolveNodeList(v8::Isolate * pIsolate,WideString wsExpression,Mask<XFA_ResolveFlag> dwFlag,CXFA_Node * refNode)207 v8::Local<v8::Value> CJX_Tree::ResolveNodeList(v8::Isolate* pIsolate,
208 WideString wsExpression,
209 Mask<XFA_ResolveFlag> dwFlag,
210 CXFA_Node* refNode) {
211 if (!refNode)
212 refNode = GetXFANode();
213
214 CXFA_Document* pDoc = GetDocument();
215 auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_ArrayNodeList>(
216 pDoc->GetHeap()->GetAllocationHandle(), pDoc);
217 pDoc->GetNodeOwner()->PersistList(pNodeList);
218
219 CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
220 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
221 pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
222 dwFlag);
223
224 if (maybeResult.has_value()) {
225 if (maybeResult.value().type ==
226 CFXJSE_Engine::ResolveResult::Type::kNodes) {
227 for (auto& pObject : maybeResult.value().objects) {
228 if (pObject->IsNode())
229 pNodeList->Append(pObject->AsNode());
230 }
231 } else {
232 if (maybeResult.value().script_attribute.callback &&
233 maybeResult.value().script_attribute.eValueType ==
234 XFA_ScriptType::Object) {
235 for (auto& pObject : maybeResult.value().objects) {
236 v8::Local<v8::Value> innerValue;
237 CJX_Object* jsObject = pObject->JSObject();
238 (*maybeResult.value().script_attribute.callback)(
239 pIsolate, jsObject, &innerValue, false,
240 maybeResult.value().script_attribute.attribute);
241 CXFA_Object* obj =
242 CFXJSE_Engine::ToObject(pScriptContext->GetIsolate(), innerValue);
243 if (obj->IsNode())
244 pNodeList->Append(obj->AsNode());
245 }
246 }
247 }
248 }
249 return pNodeList->JSObject()->NewBoundV8Object(
250 pIsolate, pScriptContext->GetJseNormalClass()->GetTemplate(pIsolate));
251 }
252