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/js_resources.h"
12 #include "fxjs/xfa/cfxjse_engine.h"
13 #include "fxjs/xfa/cfxjse_value.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);
28 }
29
~CJX_Tree()30 CJX_Tree::~CJX_Tree() {}
31
DynamicTypeIs(TypeTag eType) const32 bool CJX_Tree::DynamicTypeIs(TypeTag eType) const {
33 return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
34 }
35
resolveNode(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)36 CJS_Result CJX_Tree::resolveNode(
37 CFX_V8* runtime,
38 const std::vector<v8::Local<v8::Value>>& params) {
39 if (params.size() != 1)
40 return CJS_Result::Failure(JSMessage::kParamError);
41
42 WideString expression = runtime->ToWideString(params[0]);
43 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
44 CXFA_Object* refNode = GetXFAObject();
45 if (refNode->GetElementType() == XFA_Element::Xfa)
46 refNode = pScriptContext->GetThisObject();
47
48 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
49 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
50 XFA_RESOLVENODE_Siblings;
51 XFA_RESOLVENODE_RS resolveNodeRS;
52 if (!pScriptContext->ResolveObjects(ToNode(refNode),
53 expression.AsStringView(), &resolveNodeRS,
54 dwFlag, nullptr)) {
55 return CJS_Result::Success(runtime->NewNull());
56 }
57
58 if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
59 CXFA_Object* pObject = resolveNodeRS.objects.front().Get();
60 CFXJSE_Value* value =
61 GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(pObject);
62
63 return CJS_Result::Success(
64 value->DirectGetValue().Get(runtime->GetIsolate()));
65 }
66
67 if (!resolveNodeRS.script_attribute.callback ||
68 resolveNodeRS.script_attribute.eValueType != XFA_ScriptType::Object) {
69 return CJS_Result::Success(runtime->NewNull());
70 }
71
72 auto pValue = pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
73 CJX_Object* jsObject = resolveNodeRS.objects.front()->JSObject();
74 (*resolveNodeRS.script_attribute.callback)(
75 jsObject, pValue.get(), false, resolveNodeRS.script_attribute.attribute);
76 return CJS_Result::Success(
77 pValue->DirectGetValue().Get(runtime->GetIsolate()));
78 }
79
resolveNodes(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)80 CJS_Result CJX_Tree::resolveNodes(
81 CFX_V8* runtime,
82 const std::vector<v8::Local<v8::Value>>& params) {
83 if (params.size() != 1)
84 return CJS_Result::Failure(JSMessage::kParamError);
85
86 CXFA_Object* refNode = GetXFAObject();
87 if (refNode->GetElementType() == XFA_Element::Xfa)
88 refNode = GetDocument()->GetScriptContext()->GetThisObject();
89
90 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
91 auto pValue = pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
92 ResolveNodeList(pValue.get(), runtime->ToWideString(params[0]),
93 XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
94 XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
95 XFA_RESOLVENODE_Siblings,
96 ToNode(refNode));
97 return CJS_Result::Success(
98 pValue->DirectGetValue().Get(runtime->GetIsolate()));
99 }
100
all(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)101 void CJX_Tree::all(CFXJSE_Value* pValue,
102 bool bSetting,
103 XFA_Attribute eAttribute) {
104 if (bSetting) {
105 ThrowInvalidPropertyException();
106 return;
107 }
108
109 uint32_t dwFlag = XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL;
110 WideString wsExpression = GetAttribute(XFA_Attribute::Name) + L"[*]";
111 ResolveNodeList(pValue, wsExpression, dwFlag, nullptr);
112 }
113
classAll(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)114 void CJX_Tree::classAll(CFXJSE_Value* pValue,
115 bool bSetting,
116 XFA_Attribute eAttribute) {
117 if (bSetting) {
118 ThrowInvalidPropertyException();
119 return;
120 }
121
122 WideString wsExpression =
123 L"#" + WideString::FromASCII(GetXFAObject()->GetClassName()) + L"[*]";
124 ResolveNodeList(pValue, wsExpression,
125 XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL, nullptr);
126 }
127
nodes(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)128 void CJX_Tree::nodes(CFXJSE_Value* pValue,
129 bool bSetting,
130 XFA_Attribute eAttribute) {
131 if (bSetting) {
132 WideString wsMessage = L"Unable to set ";
133 FXJSE_ThrowMessage(wsMessage.ToUTF8().AsStringView());
134 return;
135 }
136
137 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
138 CXFA_AttachNodeList* pNodeList =
139 new CXFA_AttachNodeList(GetDocument(), ToNode(GetXFAObject()));
140 pValue->SetHostObject(pNodeList, pScriptContext->GetJseNormalClass());
141 }
142
parent(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)143 void CJX_Tree::parent(CFXJSE_Value* pValue,
144 bool bSetting,
145 XFA_Attribute eAttribute) {
146 if (bSetting) {
147 ThrowInvalidPropertyException();
148 return;
149 }
150
151 CXFA_Node* pParent = ToNode(GetXFAObject())->GetParent();
152 if (!pParent) {
153 pValue->SetNull();
154 return;
155 }
156
157 pValue->Assign(
158 GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(pParent));
159 }
160
index(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)161 void CJX_Tree::index(CFXJSE_Value* pValue,
162 bool bSetting,
163 XFA_Attribute eAttribute) {
164 if (bSetting) {
165 ThrowInvalidPropertyException();
166 return;
167 }
168
169 CXFA_Node* pNode = ToNode(GetXFAObject());
170 size_t iIndex = pNode ? pNode->GetIndexByName() : 0;
171 pValue->SetInteger(pdfium::base::checked_cast<int32_t>(iIndex));
172 }
173
classIndex(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)174 void CJX_Tree::classIndex(CFXJSE_Value* pValue,
175 bool bSetting,
176 XFA_Attribute eAttribute) {
177 if (bSetting) {
178 ThrowInvalidPropertyException();
179 return;
180 }
181
182 CXFA_Node* pNode = ToNode(GetXFAObject());
183 size_t iIndex = pNode ? pNode->GetIndexByClassName() : 0;
184 pValue->SetInteger(pdfium::base::checked_cast<int32_t>(iIndex));
185 }
186
somExpression(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)187 void CJX_Tree::somExpression(CFXJSE_Value* pValue,
188 bool bSetting,
189 XFA_Attribute eAttribute) {
190 if (bSetting) {
191 ThrowInvalidPropertyException();
192 return;
193 }
194
195 WideString wsSOMExpression = GetXFAObject()->GetSOMExpression();
196 pValue->SetString(wsSOMExpression.ToUTF8().AsStringView());
197 }
198
ResolveNodeList(CFXJSE_Value * pValue,WideString wsExpression,uint32_t dwFlag,CXFA_Node * refNode)199 void CJX_Tree::ResolveNodeList(CFXJSE_Value* pValue,
200 WideString wsExpression,
201 uint32_t dwFlag,
202 CXFA_Node* refNode) {
203 if (!refNode)
204 refNode = ToNode(GetXFAObject());
205
206 XFA_RESOLVENODE_RS resolveNodeRS;
207 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
208 pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
209 &resolveNodeRS, dwFlag, nullptr);
210 CXFA_ArrayNodeList* pNodeList = new CXFA_ArrayNodeList(GetDocument());
211 if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
212 for (auto& pObject : resolveNodeRS.objects) {
213 if (pObject->IsNode())
214 pNodeList->Append(pObject->AsNode());
215 }
216 } else {
217 if (resolveNodeRS.script_attribute.callback &&
218 resolveNodeRS.script_attribute.eValueType == XFA_ScriptType::Object) {
219 for (auto& pObject : resolveNodeRS.objects) {
220 auto innerValue =
221 pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
222 CJX_Object* jsObject = pObject->JSObject();
223 (*resolveNodeRS.script_attribute.callback)(
224 jsObject, innerValue.get(), false,
225 resolveNodeRS.script_attribute.attribute);
226 CXFA_Object* obj = CFXJSE_Engine::ToObject(innerValue.get());
227 if (obj->IsNode())
228 pNodeList->Append(obj->AsNode());
229 }
230 }
231 }
232 pValue->SetHostObject(pNodeList, pScriptContext->GetJseNormalClass());
233 }
234