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 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
47 CXFA_Object* pRefNode = GetXFAObject();
48 if (pRefNode->GetElementType() == XFA_Element::Xfa)
49 pRefNode = pScriptContext->GetThisObject();
50
51 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
52 pScriptContext->ResolveObjects(
53 ToNode(pRefNode), wsExpression.AsStringView(),
54 Mask<XFA_ResolveFlag>{
55 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
56 XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
57 XFA_ResolveFlag::kSiblings});
58 if (!maybeResult.has_value())
59 return CJS_Result::Success(runtime->NewNull());
60
61 if (maybeResult.value().type == CFXJSE_Engine::ResolveResult::Type::kNodes) {
62 return CJS_Result::Success(
63 GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
64 maybeResult.value().objects.front().Get()));
65 }
66
67 if (!maybeResult.value().script_attribute.callback ||
68 maybeResult.value().script_attribute.eValueType !=
69 XFA_ScriptType::Object) {
70 return CJS_Result::Success(runtime->NewNull());
71 }
72
73 v8::Local<v8::Value> pValue;
74 CJX_Object* jsObject = maybeResult.value().objects.front()->JSObject();
75 (*maybeResult.value().script_attribute.callback)(
76 runtime->GetIsolate(), jsObject, &pValue, false,
77 maybeResult.value().script_attribute.attribute);
78 return CJS_Result::Success(pValue);
79 }
80
resolveNodes(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)81 CJS_Result CJX_Tree::resolveNodes(
82 CFXJSE_Engine* runtime,
83 const std::vector<v8::Local<v8::Value>>& params) {
84 if (params.size() != 1)
85 return CJS_Result::Failure(JSMessage::kParamError);
86
87 CXFA_Object* refNode = GetXFAObject();
88 if (refNode->GetElementType() == XFA_Element::Xfa)
89 refNode = GetDocument()->GetScriptContext()->GetThisObject();
90
91 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
92 const Mask<XFA_ResolveFlag> kFlags = {
93 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
94 XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
95 XFA_ResolveFlag::kSiblings};
96 return CJS_Result::Success(ResolveNodeList(pScriptContext->GetIsolate(),
97 runtime->ToWideString(params[0]),
98 kFlags, ToNode(refNode)));
99 }
100
all(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)101 void CJX_Tree::all(v8::Isolate* pIsolate,
102 v8::Local<v8::Value>* pValue,
103 bool bSetting,
104 XFA_Attribute eAttribute) {
105 if (bSetting) {
106 ThrowInvalidPropertyException(pIsolate);
107 return;
108 }
109 const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
110 XFA_ResolveFlag::kALL};
111 WideString wsExpression = GetAttributeByEnum(XFA_Attribute::Name) + L"[*]";
112 *pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
113 }
114
classAll(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)115 void CJX_Tree::classAll(v8::Isolate* pIsolate,
116 v8::Local<v8::Value>* pValue,
117 bool bSetting,
118 XFA_Attribute eAttribute) {
119 if (bSetting) {
120 ThrowInvalidPropertyException(pIsolate);
121 return;
122 }
123 const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
124 XFA_ResolveFlag::kALL};
125 WideString wsExpression =
126 L"#" + WideString::FromASCII(GetXFAObject()->GetClassName()) + L"[*]";
127 *pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
128 }
129
nodes(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)130 void CJX_Tree::nodes(v8::Isolate* pIsolate,
131 v8::Local<v8::Value>* pValue,
132 bool bSetting,
133 XFA_Attribute eAttribute) {
134 if (bSetting) {
135 WideString wsMessage = L"Unable to set ";
136 FXJSE_ThrowMessage(pIsolate, wsMessage.ToUTF8().AsStringView());
137 return;
138 }
139
140 CXFA_Document* pDoc = GetDocument();
141 auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_AttachNodeList>(
142 pDoc->GetHeap()->GetAllocationHandle(), pDoc, GetXFANode());
143 pDoc->GetNodeOwner()->PersistList(pNodeList);
144
145 CFXJSE_Engine* pEngine = pDoc->GetScriptContext();
146 *pValue = pNodeList->JSObject()->NewBoundV8Object(
147 pIsolate, pEngine->GetJseNormalClass()->GetTemplate(pIsolate));
148 }
149
parent(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)150 void CJX_Tree::parent(v8::Isolate* pIsolate,
151 v8::Local<v8::Value>* pValue,
152 bool bSetting,
153 XFA_Attribute eAttribute) {
154 if (bSetting) {
155 ThrowInvalidPropertyException(pIsolate);
156 return;
157 }
158
159 CXFA_Node* pParent = GetXFANode()->GetParent();
160 *pValue = pParent ? GetDocument()
161 ->GetScriptContext()
162 ->GetOrCreateJSBindingFromMap(pParent)
163 .As<v8::Value>()
164 : fxv8::NewNullHelper(pIsolate).As<v8::Value>();
165 }
166
index(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)167 void CJX_Tree::index(v8::Isolate* pIsolate,
168 v8::Local<v8::Value>* pValue,
169 bool bSetting,
170 XFA_Attribute eAttribute) {
171 if (bSetting) {
172 ThrowInvalidPropertyException(pIsolate);
173 return;
174 }
175
176 CXFA_Node* pNode = GetXFANode();
177 size_t iIndex = pNode ? pNode->GetIndexByName() : 0;
178 *pValue = fxv8::NewNumberHelper(pIsolate,
179 pdfium::base::checked_cast<int32_t>(iIndex));
180 }
181
classIndex(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)182 void CJX_Tree::classIndex(v8::Isolate* pIsolate,
183 v8::Local<v8::Value>* pValue,
184 bool bSetting,
185 XFA_Attribute eAttribute) {
186 if (bSetting) {
187 ThrowInvalidPropertyException(pIsolate);
188 return;
189 }
190
191 CXFA_Node* pNode = GetXFANode();
192 size_t iIndex = pNode ? pNode->GetIndexByClassName() : 0;
193 *pValue = fxv8::NewNumberHelper(pIsolate,
194 pdfium::base::checked_cast<int32_t>(iIndex));
195 }
196
somExpression(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)197 void CJX_Tree::somExpression(v8::Isolate* pIsolate,
198 v8::Local<v8::Value>* pValue,
199 bool bSetting,
200 XFA_Attribute eAttribute) {
201 if (bSetting) {
202 ThrowInvalidPropertyException(pIsolate);
203 return;
204 }
205
206 ByteString bsSOMExpression = GetXFAObject()->GetSOMExpression().ToUTF8();
207 *pValue = fxv8::NewStringHelper(pIsolate, bsSOMExpression.AsStringView());
208 }
209
ResolveNodeList(v8::Isolate * pIsolate,WideString wsExpression,Mask<XFA_ResolveFlag> dwFlag,CXFA_Node * refNode)210 v8::Local<v8::Value> CJX_Tree::ResolveNodeList(v8::Isolate* pIsolate,
211 WideString wsExpression,
212 Mask<XFA_ResolveFlag> dwFlag,
213 CXFA_Node* refNode) {
214 if (!refNode)
215 refNode = GetXFANode();
216
217 CXFA_Document* pDoc = GetDocument();
218 auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_ArrayNodeList>(
219 pDoc->GetHeap()->GetAllocationHandle(), pDoc);
220 pDoc->GetNodeOwner()->PersistList(pNodeList);
221
222 CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
223 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
224 pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
225 dwFlag);
226
227 if (maybeResult.has_value()) {
228 if (maybeResult.value().type ==
229 CFXJSE_Engine::ResolveResult::Type::kNodes) {
230 for (auto& pObject : maybeResult.value().objects) {
231 if (pObject->IsNode())
232 pNodeList->Append(pObject->AsNode());
233 }
234 } else {
235 if (maybeResult.value().script_attribute.callback &&
236 maybeResult.value().script_attribute.eValueType ==
237 XFA_ScriptType::Object) {
238 for (auto& pObject : maybeResult.value().objects) {
239 v8::Local<v8::Value> innerValue;
240 CJX_Object* jsObject = pObject->JSObject();
241 (*maybeResult.value().script_attribute.callback)(
242 pIsolate, jsObject, &innerValue, false,
243 maybeResult.value().script_attribute.attribute);
244 CXFA_Object* obj =
245 CFXJSE_Engine::ToObject(pScriptContext->GetIsolate(), innerValue);
246 if (obj->IsNode())
247 pNodeList->Append(obj->AsNode());
248 }
249 }
250 }
251 }
252 return pNodeList->JSObject()->NewBoundV8Object(
253 pIsolate, pScriptContext->GetJseNormalClass()->GetTemplate(pIsolate));
254 }
255