1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // 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/cfxjse_engine.h"
12 #include "fxjs/cfxjse_value.h"
13 #include "fxjs/js_resources.h"
14 #include "third_party/base/ptr_util.h"
15 #include "xfa/fxfa/parser/cxfa_arraynodelist.h"
16 #include "xfa/fxfa/parser/cxfa_attachnodelist.h"
17 #include "xfa/fxfa/parser/cxfa_document.h"
18 #include "xfa/fxfa/parser/cxfa_node.h"
19 #include "xfa/fxfa/parser/cxfa_object.h"
20 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
21
22 const CJX_MethodSpec CJX_Tree::MethodSpecs[] = {
23 {"resolveNode", resolveNode_static},
24 {"resolveNodes", resolveNodes_static}};
25
CJX_Tree(CXFA_Object * obj)26 CJX_Tree::CJX_Tree(CXFA_Object* obj) : CJX_Object(obj) {
27 DefineMethods(MethodSpecs, FX_ArraySize(MethodSpecs));
28 }
29
~CJX_Tree()30 CJX_Tree::~CJX_Tree() {}
31
resolveNode(CJS_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)32 CJS_Return CJX_Tree::resolveNode(
33 CJS_V8* runtime,
34 const std::vector<v8::Local<v8::Value>>& params) {
35 if (params.size() != 1)
36 return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
37
38 WideString expression = runtime->ToWideString(params[0]);
39 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
40 if (!pScriptContext)
41 return CJS_Return(true);
42
43 CXFA_Object* refNode = GetXFAObject();
44 if (refNode->GetElementType() == XFA_Element::Xfa)
45 refNode = pScriptContext->GetThisObject();
46
47 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
48 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
49 XFA_RESOLVENODE_Siblings;
50 XFA_RESOLVENODE_RS resolveNodeRS;
51 if (!pScriptContext->ResolveObjects(ToNode(refNode),
52 expression.AsStringView(), &resolveNodeRS,
53 dwFlag, nullptr)) {
54 return CJS_Return(runtime->NewNull());
55 }
56
57 if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
58 CXFA_Object* pObject = resolveNodeRS.objects.front();
59 CFXJSE_Value* value =
60 GetDocument()->GetScriptContext()->GetJSValueFromMap(pObject);
61 if (!value)
62 return CJS_Return(runtime->NewNull());
63
64 return CJS_Return(value->DirectGetValue().Get(runtime->GetIsolate()));
65 }
66
67 const XFA_SCRIPTATTRIBUTEINFO* lpAttributeInfo =
68 resolveNodeRS.pScriptAttribute;
69 if (!lpAttributeInfo ||
70 lpAttributeInfo->eValueType != XFA_ScriptType::Object) {
71 return CJS_Return(runtime->NewNull());
72 }
73
74 auto pValue = pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
75 CJX_Object* jsObject = resolveNodeRS.objects.front()->JSObject();
76 (jsObject->*(lpAttributeInfo->callback))(pValue.get(), false,
77 lpAttributeInfo->attribute);
78 return CJS_Return(pValue->DirectGetValue().Get(runtime->GetIsolate()));
79 }
80
resolveNodes(CJS_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)81 CJS_Return CJX_Tree::resolveNodes(
82 CJS_V8* runtime,
83 const std::vector<v8::Local<v8::Value>>& params) {
84 if (params.size() != 1)
85 return CJS_Return(JSGetStringFromID(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 if (!pScriptContext)
93 return CJS_Return(true);
94
95 auto pValue = pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
96 ResolveNodeList(pValue.get(), runtime->ToWideString(params[0]),
97 XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
98 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
99 XFA_RESOLVENODE_Siblings,
100 ToNode(refNode));
101 return CJS_Return(pValue->DirectGetValue().Get(runtime->GetIsolate()));
102 }
103
all(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)104 void CJX_Tree::all(CFXJSE_Value* pValue,
105 bool bSetting,
106 XFA_Attribute eAttribute) {
107 if (bSetting) {
108 ThrowInvalidPropertyException();
109 return;
110 }
111
112 uint32_t dwFlag = XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL;
113 WideString wsExpression = GetAttribute(XFA_Attribute::Name) + L"[*]";
114 ResolveNodeList(pValue, wsExpression, dwFlag, nullptr);
115 }
116
classAll(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)117 void CJX_Tree::classAll(CFXJSE_Value* pValue,
118 bool bSetting,
119 XFA_Attribute eAttribute) {
120 if (bSetting) {
121 ThrowInvalidPropertyException();
122 return;
123 }
124
125 WideString wsExpression = L"#" + GetXFAObject()->GetClassName() + L"[*]";
126 ResolveNodeList(pValue, wsExpression,
127 XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL, nullptr);
128 }
129
name(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)130 void CJX_Tree::name(CFXJSE_Value* pValue,
131 bool bSetting,
132 XFA_Attribute eAttribute) {
133 Script_Attribute_String(pValue, bSetting, eAttribute);
134 }
135
nodes(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)136 void CJX_Tree::nodes(CFXJSE_Value* pValue,
137 bool bSetting,
138 XFA_Attribute eAttribute) {
139 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
140 if (!pScriptContext)
141 return;
142
143 if (bSetting) {
144 WideString wsMessage = L"Unable to set ";
145 FXJSE_ThrowMessage(wsMessage.UTF8Encode().AsStringView());
146 return;
147 }
148
149 CXFA_AttachNodeList* pNodeList =
150 new CXFA_AttachNodeList(GetDocument(), ToNode(GetXFAObject()));
151 pValue->SetObject(pNodeList, pScriptContext->GetJseNormalClass());
152 }
153
parent(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)154 void CJX_Tree::parent(CFXJSE_Value* pValue,
155 bool bSetting,
156 XFA_Attribute eAttribute) {
157 if (bSetting) {
158 ThrowInvalidPropertyException();
159 return;
160 }
161
162 CXFA_Node* pParent = ToNode(GetXFAObject())->GetParent();
163 if (!pParent) {
164 pValue->SetNull();
165 return;
166 }
167
168 pValue->Assign(GetDocument()->GetScriptContext()->GetJSValueFromMap(pParent));
169 }
170
index(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)171 void CJX_Tree::index(CFXJSE_Value* pValue,
172 bool bSetting,
173 XFA_Attribute eAttribute) {
174 if (bSetting) {
175 ThrowInvalidPropertyException();
176 return;
177 }
178 pValue->SetInteger(ToNode(GetXFAObject())->GetNodeSameNameIndex());
179 }
180
classIndex(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)181 void CJX_Tree::classIndex(CFXJSE_Value* pValue,
182 bool bSetting,
183 XFA_Attribute eAttribute) {
184 if (bSetting) {
185 ThrowInvalidPropertyException();
186 return;
187 }
188 pValue->SetInteger(ToNode(GetXFAObject())->GetNodeSameClassIndex());
189 }
190
somExpression(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)191 void CJX_Tree::somExpression(CFXJSE_Value* pValue,
192 bool bSetting,
193 XFA_Attribute eAttribute) {
194 if (bSetting) {
195 ThrowInvalidPropertyException();
196 return;
197 }
198
199 WideString wsSOMExpression = GetXFAObject()->GetSOMExpression();
200 pValue->SetString(wsSOMExpression.UTF8Encode().AsStringView());
201 }
202
ResolveNodeList(CFXJSE_Value * pValue,WideString wsExpression,uint32_t dwFlag,CXFA_Node * refNode)203 void CJX_Tree::ResolveNodeList(CFXJSE_Value* pValue,
204 WideString wsExpression,
205 uint32_t dwFlag,
206 CXFA_Node* refNode) {
207 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
208 if (!pScriptContext)
209 return;
210 if (!refNode)
211 refNode = ToNode(GetXFAObject());
212
213 XFA_RESOLVENODE_RS resolveNodeRS;
214 pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
215 &resolveNodeRS, dwFlag, nullptr);
216 CXFA_ArrayNodeList* pNodeList = new CXFA_ArrayNodeList(GetDocument());
217 if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
218 for (CXFA_Object* pObject : resolveNodeRS.objects) {
219 if (pObject->IsNode())
220 pNodeList->Append(pObject->AsNode());
221 }
222 } else {
223 if (resolveNodeRS.pScriptAttribute &&
224 resolveNodeRS.pScriptAttribute->eValueType == XFA_ScriptType::Object) {
225 for (CXFA_Object* pObject : resolveNodeRS.objects) {
226 auto pValue =
227 pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
228 CJX_Object* jsObject = pObject->JSObject();
229 (jsObject->*(resolveNodeRS.pScriptAttribute->callback))(
230 pValue.get(), false, resolveNodeRS.pScriptAttribute->attribute);
231
232 CXFA_Object* obj = CFXJSE_Engine::ToObject(pValue.get(), nullptr);
233 if (obj->IsNode())
234 pNodeList->Append(obj->AsNode());
235 }
236 }
237 }
238 pValue->SetObject(pNodeList, pScriptContext->GetJseNormalClass());
239 }
240