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