• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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