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