• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/cfxjse_engine.h"
8 
9 #include <utility>
10 
11 #include "core/fxcrt/autorestorer.h"
12 #include "core/fxcrt/cfx_widetextbuf.h"
13 #include "core/fxcrt/fx_extension.h"
14 #include "fxjs/cfxjse_class.h"
15 #include "fxjs/cfxjse_resolveprocessor.h"
16 #include "fxjs/cfxjse_value.h"
17 #include "third_party/base/ptr_util.h"
18 #include "third_party/base/stl_util.h"
19 #include "xfa/fxfa/cxfa_eventparam.h"
20 #include "xfa/fxfa/cxfa_ffnotify.h"
21 #include "xfa/fxfa/parser/cxfa_document.h"
22 #include "xfa/fxfa/parser/cxfa_localemgr.h"
23 #include "xfa/fxfa/parser/cxfa_node.h"
24 #include "xfa/fxfa/parser/cxfa_nodehelper.h"
25 #include "xfa/fxfa/parser/cxfa_object.h"
26 #include "xfa/fxfa/parser/cxfa_thisproxy.h"
27 #include "xfa/fxfa/parser/cxfa_treelist.h"
28 #include "xfa/fxfa/parser/xfa_basic_data.h"
29 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
30 #include "xfa/fxfa/parser/xfa_utils.h"
31 
32 namespace {
33 
34 const FXJSE_CLASS_DESCRIPTOR GlobalClassDescriptor = {
35     "Root",   // name
36     nullptr,  // methods
37     0,        // method count
38     CFXJSE_Engine::GlobalPropTypeGetter,
39     CFXJSE_Engine::GlobalPropertyGetter,
40     CFXJSE_Engine::GlobalPropertySetter,
41     CFXJSE_Engine::NormalMethodCall,
42 };
43 
44 const FXJSE_CLASS_DESCRIPTOR NormalClassDescriptor = {
45     "XFAObject",  // name
46     nullptr,      // methods
47     0,            // method count
48     CFXJSE_Engine::NormalPropTypeGetter,
49     CFXJSE_Engine::NormalPropertyGetter,
50     CFXJSE_Engine::NormalPropertySetter,
51     CFXJSE_Engine::NormalMethodCall,
52 };
53 
54 const FXJSE_CLASS_DESCRIPTOR VariablesClassDescriptor = {
55     "XFAScriptObject",  // name
56     nullptr,            // methods
57     0,                  // method count
58     CFXJSE_Engine::NormalPropTypeGetter,
59     CFXJSE_Engine::GlobalPropertyGetter,
60     CFXJSE_Engine::GlobalPropertySetter,
61     CFXJSE_Engine::NormalMethodCall,
62 };
63 
64 const char kFormCalcRuntime[] = "pfm_rt";
65 
ToThisProxy(CFXJSE_Value * pValue,CFXJSE_Class * pClass)66 CXFA_ThisProxy* ToThisProxy(CFXJSE_Value* pValue, CFXJSE_Class* pClass) {
67   return static_cast<CXFA_ThisProxy*>(pValue->ToHostObject(pClass));
68 }
69 
70 }  // namespace
71 
72 // static
ToObject(const v8::FunctionCallbackInfo<v8::Value> & info)73 CXFA_Object* CFXJSE_Engine::ToObject(
74     const v8::FunctionCallbackInfo<v8::Value>& info) {
75   if (!info.Holder()->IsObject())
76     return nullptr;
77 
78   CFXJSE_HostObject* hostObj =
79       FXJSE_RetrieveObjectBinding(info.Holder().As<v8::Object>(), nullptr);
80   if (!hostObj || hostObj->type() != CFXJSE_HostObject::kXFA)
81     return nullptr;
82   return static_cast<CXFA_Object*>(hostObj);
83 }
84 
85 // static.
ToObject(CFXJSE_Value * pValue,CFXJSE_Class * pClass)86 CXFA_Object* CFXJSE_Engine::ToObject(CFXJSE_Value* pValue,
87                                      CFXJSE_Class* pClass) {
88   CFXJSE_HostObject* pHostObj = pValue->ToHostObject(pClass);
89   if (!pHostObj || pHostObj->type() != CFXJSE_HostObject::kXFA)
90     return nullptr;
91   return static_cast<CXFA_Object*>(pHostObj);
92 }
93 
CFXJSE_Engine(CXFA_Document * pDocument,v8::Isolate * pIsolate)94 CFXJSE_Engine::CFXJSE_Engine(CXFA_Document* pDocument, v8::Isolate* pIsolate)
95     : CJS_V8(pIsolate),
96       m_pDocument(pDocument),
97       m_JsContext(CFXJSE_Context::Create(pIsolate,
98                                          &GlobalClassDescriptor,
99                                          pDocument->GetRoot())),
100       m_pJsClass(nullptr),
101       m_eScriptType(CXFA_Script::Type::Unknown),
102       m_pScriptNodeArray(nullptr),
103       m_ResolveProcessor(pdfium::MakeUnique<CFXJSE_ResolveProcessor>()),
104       m_pThisObject(nullptr),
105       m_eRunAtType(XFA_AttributeEnum::Client) {
106   RemoveBuiltInObjs(m_JsContext.get());
107   m_JsContext->EnableCompatibleMode();
108 
109   // Don't know if this can happen before we remove the builtin objs and set
110   // compatibility mode.
111   m_pJsClass =
112       CFXJSE_Class::Create(m_JsContext.get(), &NormalClassDescriptor, false);
113 }
114 
~CFXJSE_Engine()115 CFXJSE_Engine::~CFXJSE_Engine() {
116   for (const auto& pair : m_mapVariableToContext)
117     delete ToThisProxy(pair.second->GetGlobalObject().get(), nullptr);
118 }
119 
RunScript(CXFA_Script::Type eScriptType,const WideStringView & wsScript,CFXJSE_Value * hRetValue,CXFA_Object * pThisObject)120 bool CFXJSE_Engine::RunScript(CXFA_Script::Type eScriptType,
121                               const WideStringView& wsScript,
122                               CFXJSE_Value* hRetValue,
123                               CXFA_Object* pThisObject) {
124   ByteString btScript;
125   AutoRestorer<CXFA_Script::Type> typeRestorer(&m_eScriptType);
126   m_eScriptType = eScriptType;
127   if (eScriptType == CXFA_Script::Type::Formcalc) {
128     if (!m_FM2JSContext) {
129       m_FM2JSContext = pdfium::MakeUnique<CFXJSE_FormCalcContext>(
130           GetIsolate(), m_JsContext.get(), m_pDocument.Get());
131     }
132     CFX_WideTextBuf wsJavaScript;
133     if (!CFXJSE_FormCalcContext::Translate(wsScript, &wsJavaScript)) {
134       hRetValue->SetUndefined();
135       return false;
136     }
137     btScript = FX_UTF8Encode(wsJavaScript.AsStringView());
138   } else {
139     btScript = FX_UTF8Encode(wsScript);
140   }
141   AutoRestorer<CXFA_Object*> nodeRestorer(&m_pThisObject);
142   m_pThisObject = pThisObject;
143   CFXJSE_Value* pValue = pThisObject ? GetJSValueFromMap(pThisObject) : nullptr;
144   return m_JsContext->ExecuteScript(btScript.c_str(), hRetValue, pValue);
145 }
146 
QueryNodeByFlag(CXFA_Node * refNode,const WideStringView & propname,CFXJSE_Value * pValue,uint32_t dwFlag,bool bSetting)147 bool CFXJSE_Engine::QueryNodeByFlag(CXFA_Node* refNode,
148                                     const WideStringView& propname,
149                                     CFXJSE_Value* pValue,
150                                     uint32_t dwFlag,
151                                     bool bSetting) {
152   if (!refNode)
153     return false;
154 
155   XFA_RESOLVENODE_RS resolveRs;
156   if (!ResolveObjects(refNode, propname, &resolveRs, dwFlag, nullptr))
157     return false;
158   if (resolveRs.dwFlags == XFA_ResolveNode_RSType_Nodes) {
159     pValue->Assign(GetJSValueFromMap(resolveRs.objects.front()));
160     return true;
161   }
162   if (resolveRs.dwFlags == XFA_ResolveNode_RSType_Attribute) {
163     const XFA_SCRIPTATTRIBUTEINFO* lpAttributeInfo = resolveRs.pScriptAttribute;
164     if (lpAttributeInfo) {
165       CJX_Object* jsObject = resolveRs.objects.front()->JSObject();
166       (jsObject->*(lpAttributeInfo->callback))(pValue, bSetting,
167                                                lpAttributeInfo->attribute);
168     }
169   }
170   return true;
171 }
172 
GlobalPropertySetter(CFXJSE_Value * pObject,const ByteStringView & szPropName,CFXJSE_Value * pValue)173 void CFXJSE_Engine::GlobalPropertySetter(CFXJSE_Value* pObject,
174                                          const ByteStringView& szPropName,
175                                          CFXJSE_Value* pValue) {
176   CXFA_Object* lpOrginalNode = ToObject(pObject, nullptr);
177   CXFA_Document* pDoc = lpOrginalNode->GetDocument();
178   CFXJSE_Engine* lpScriptContext = pDoc->GetScriptContext();
179   CXFA_Node* pRefNode = ToNode(lpScriptContext->GetThisObject());
180   if (lpOrginalNode->IsVariablesThis())
181     pRefNode = ToNode(lpScriptContext->GetVariablesThis(lpOrginalNode));
182 
183   WideString wsPropName = WideString::FromUTF8(szPropName);
184   if (lpScriptContext->QueryNodeByFlag(
185           pRefNode, wsPropName.AsStringView(), pValue,
186           XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings |
187               XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
188               XFA_RESOLVENODE_Attributes,
189           true)) {
190     return;
191   }
192   if (lpOrginalNode->IsVariablesThis()) {
193     if (pValue && pValue->IsUndefined()) {
194       pObject->SetObjectOwnProperty(szPropName, pValue);
195       return;
196     }
197   }
198   CXFA_FFNotify* pNotify = pDoc->GetNotify();
199   if (!pNotify)
200     return;
201 
202   pNotify->GetDocEnvironment()->SetGlobalProperty(pNotify->GetHDOC(),
203                                                   szPropName, pValue);
204 }
205 
GlobalPropertyGetter(CFXJSE_Value * pObject,const ByteStringView & szPropName,CFXJSE_Value * pValue)206 void CFXJSE_Engine::GlobalPropertyGetter(CFXJSE_Value* pObject,
207                                          const ByteStringView& szPropName,
208                                          CFXJSE_Value* pValue) {
209   CXFA_Object* pOriginalObject = ToObject(pObject, nullptr);
210   CXFA_Document* pDoc = pOriginalObject->GetDocument();
211   CFXJSE_Engine* lpScriptContext = pDoc->GetScriptContext();
212   WideString wsPropName = WideString::FromUTF8(szPropName);
213   if (lpScriptContext->GetType() == CXFA_Script::Type::Formcalc) {
214     if (szPropName == kFormCalcRuntime) {
215       lpScriptContext->m_FM2JSContext->GlobalPropertyGetter(pValue);
216       return;
217     }
218     XFA_HashCode uHashCode = static_cast<XFA_HashCode>(
219         FX_HashCode_GetW(wsPropName.AsStringView(), false));
220     if (uHashCode != XFA_HASHCODE_Layout) {
221       CXFA_Object* pObj =
222           lpScriptContext->GetDocument()->GetXFAObject(uHashCode);
223       if (pObj) {
224         pValue->Assign(lpScriptContext->GetJSValueFromMap(pObj));
225         return;
226       }
227     }
228   }
229 
230   CXFA_Node* pRefNode = ToNode(lpScriptContext->GetThisObject());
231   if (pOriginalObject->IsVariablesThis())
232     pRefNode = ToNode(lpScriptContext->GetVariablesThis(pOriginalObject));
233 
234   if (lpScriptContext->QueryNodeByFlag(
235           pRefNode, wsPropName.AsStringView(), pValue,
236           XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
237               XFA_RESOLVENODE_Attributes,
238           false)) {
239     return;
240   }
241 
242   if (lpScriptContext->QueryNodeByFlag(
243           pRefNode, wsPropName.AsStringView(), pValue,
244           XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings, false)) {
245     return;
246   }
247 
248   CXFA_Object* pScriptObject =
249       lpScriptContext->GetVariablesThis(pOriginalObject, true);
250   if (pScriptObject && lpScriptContext->QueryVariableValue(
251                            pScriptObject->AsNode(), szPropName, pValue, true)) {
252     return;
253   }
254 
255   CXFA_FFNotify* pNotify = pDoc->GetNotify();
256   if (!pNotify)
257     return;
258 
259   pNotify->GetDocEnvironment()->GetGlobalProperty(pNotify->GetHDOC(),
260                                                   szPropName, pValue);
261 }
262 
GlobalPropTypeGetter(CFXJSE_Value * pOriginalValue,const ByteStringView & szPropName,bool bQueryIn)263 int32_t CFXJSE_Engine::GlobalPropTypeGetter(CFXJSE_Value* pOriginalValue,
264                                             const ByteStringView& szPropName,
265                                             bool bQueryIn) {
266   CXFA_Object* pObject = ToObject(pOriginalValue, nullptr);
267   if (!pObject)
268     return FXJSE_ClassPropType_None;
269 
270   CFXJSE_Engine* lpScriptContext = pObject->GetDocument()->GetScriptContext();
271   pObject = lpScriptContext->GetVariablesThis(pObject);
272   WideString wsPropName = WideString::FromUTF8(szPropName);
273   if (pObject->JSObject()->HasMethod(wsPropName))
274     return FXJSE_ClassPropType_Method;
275 
276   return FXJSE_ClassPropType_Property;
277 }
278 
NormalPropertyGetter(CFXJSE_Value * pOriginalValue,const ByteStringView & szPropName,CFXJSE_Value * pReturnValue)279 void CFXJSE_Engine::NormalPropertyGetter(CFXJSE_Value* pOriginalValue,
280                                          const ByteStringView& szPropName,
281                                          CFXJSE_Value* pReturnValue) {
282   CXFA_Object* pOriginalObject = ToObject(pOriginalValue, nullptr);
283   if (!pOriginalObject) {
284     pReturnValue->SetUndefined();
285     return;
286   }
287 
288   WideString wsPropName = WideString::FromUTF8(szPropName);
289   CFXJSE_Engine* lpScriptContext =
290       pOriginalObject->GetDocument()->GetScriptContext();
291   CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOriginalObject);
292   if (wsPropName == L"xfa") {
293     CFXJSE_Value* pValue = lpScriptContext->GetJSValueFromMap(
294         lpScriptContext->GetDocument()->GetRoot());
295     pReturnValue->Assign(pValue);
296     return;
297   }
298 
299   bool bRet = lpScriptContext->QueryNodeByFlag(
300       ToNode(pObject), wsPropName.AsStringView(), pReturnValue,
301       XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
302           XFA_RESOLVENODE_Attributes,
303       false);
304   if (bRet)
305     return;
306 
307   if (pObject == lpScriptContext->GetThisObject() ||
308       (lpScriptContext->GetType() == CXFA_Script::Type::Javascript &&
309        !lpScriptContext->IsStrictScopeInJavaScript())) {
310     bRet = lpScriptContext->QueryNodeByFlag(
311         ToNode(pObject), wsPropName.AsStringView(), pReturnValue,
312         XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings, false);
313   }
314   if (bRet)
315     return;
316 
317   CXFA_Object* pScriptObject =
318       lpScriptContext->GetVariablesThis(pOriginalObject, true);
319   if (pScriptObject) {
320     bRet = lpScriptContext->QueryVariableValue(ToNode(pScriptObject),
321                                                szPropName, pReturnValue, true);
322   }
323   if (!bRet)
324     pReturnValue->SetUndefined();
325 }
326 
NormalPropertySetter(CFXJSE_Value * pOriginalValue,const ByteStringView & szPropName,CFXJSE_Value * pReturnValue)327 void CFXJSE_Engine::NormalPropertySetter(CFXJSE_Value* pOriginalValue,
328                                          const ByteStringView& szPropName,
329                                          CFXJSE_Value* pReturnValue) {
330   CXFA_Object* pOriginalObject = ToObject(pOriginalValue, nullptr);
331   if (!pOriginalObject)
332     return;
333 
334   CFXJSE_Engine* lpScriptContext =
335       pOriginalObject->GetDocument()->GetScriptContext();
336   CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOriginalObject);
337   WideString wsPropName = WideString::FromUTF8(szPropName);
338   const XFA_SCRIPTATTRIBUTEINFO* lpAttributeInfo = XFA_GetScriptAttributeByName(
339       pObject->GetElementType(), wsPropName.AsStringView());
340   if (lpAttributeInfo) {
341     CJX_Object* jsObject = pObject->JSObject();
342     (jsObject->*(lpAttributeInfo->callback))(pReturnValue, true,
343                                              lpAttributeInfo->attribute);
344     return;
345   }
346 
347   if (pObject->IsNode()) {
348     if (wsPropName[0] == '#')
349       wsPropName = wsPropName.Right(wsPropName.GetLength() - 1);
350 
351     CXFA_Node* pNode = ToNode(pObject);
352     CXFA_Node* pPropOrChild = nullptr;
353     XFA_Element eType = CXFA_Node::NameToElement(wsPropName);
354     if (eType != XFA_Element::Unknown) {
355       pPropOrChild =
356           pNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eType);
357     } else {
358       pPropOrChild = pNode->GetFirstChildByName(wsPropName.AsStringView());
359     }
360 
361     if (pPropOrChild) {
362       const XFA_SCRIPTATTRIBUTEINFO* lpAttrInfo = XFA_GetScriptAttributeByName(
363           pPropOrChild->GetElementType(), L"{default}");
364       if (lpAttrInfo) {
365         pPropOrChild->JSObject()->Script_Som_DefaultValue(
366             pReturnValue, true, XFA_Attribute::Unknown);
367         return;
368       }
369     }
370   }
371 
372   CXFA_Object* pScriptObject =
373       lpScriptContext->GetVariablesThis(pOriginalObject, true);
374   if (pScriptObject) {
375     lpScriptContext->QueryVariableValue(ToNode(pScriptObject), szPropName,
376                                         pReturnValue, false);
377   }
378 }
379 
NormalPropTypeGetter(CFXJSE_Value * pOriginalValue,const ByteStringView & szPropName,bool bQueryIn)380 int32_t CFXJSE_Engine::NormalPropTypeGetter(CFXJSE_Value* pOriginalValue,
381                                             const ByteStringView& szPropName,
382                                             bool bQueryIn) {
383   CXFA_Object* pObject = ToObject(pOriginalValue, nullptr);
384   if (!pObject)
385     return FXJSE_ClassPropType_None;
386 
387   CFXJSE_Engine* lpScriptContext = pObject->GetDocument()->GetScriptContext();
388   pObject = lpScriptContext->GetVariablesThis(pObject);
389   XFA_Element eType = pObject->GetElementType();
390   WideString wsPropName = WideString::FromUTF8(szPropName);
391   if (pObject->JSObject()->HasMethod(wsPropName))
392     return FXJSE_ClassPropType_Method;
393 
394   if (bQueryIn &&
395       !XFA_GetScriptAttributeByName(eType, wsPropName.AsStringView())) {
396     return FXJSE_ClassPropType_None;
397   }
398   return FXJSE_ClassPropType_Property;
399 }
400 
NormalMethodCall(const v8::FunctionCallbackInfo<v8::Value> & info,const WideString & functionName)401 CJS_Return CFXJSE_Engine::NormalMethodCall(
402     const v8::FunctionCallbackInfo<v8::Value>& info,
403     const WideString& functionName) {
404   CXFA_Object* pObject = ToObject(info);
405   if (!pObject)
406     return CJS_Return(false);
407 
408   CFXJSE_Engine* lpScriptContext = pObject->GetDocument()->GetScriptContext();
409   pObject = lpScriptContext->GetVariablesThis(pObject);
410 
411   std::vector<v8::Local<v8::Value>> parameters;
412   for (unsigned int i = 0; i < (unsigned int)info.Length(); i++)
413     parameters.push_back(info[i]);
414 
415   return pObject->JSObject()->RunMethod(functionName, parameters);
416 }
417 
IsStrictScopeInJavaScript()418 bool CFXJSE_Engine::IsStrictScopeInJavaScript() {
419   return m_pDocument->HasFlag(XFA_DOCFLAG_StrictScoping);
420 }
421 
GetType()422 CXFA_Script::Type CFXJSE_Engine::GetType() {
423   return m_eScriptType;
424 }
425 
CreateVariablesContext(CXFA_Node * pScriptNode,CXFA_Node * pSubform)426 CFXJSE_Context* CFXJSE_Engine::CreateVariablesContext(CXFA_Node* pScriptNode,
427                                                       CXFA_Node* pSubform) {
428   if (!pScriptNode || !pSubform)
429     return nullptr;
430 
431   auto pNewContext =
432       CFXJSE_Context::Create(GetIsolate(), &VariablesClassDescriptor,
433                              new CXFA_ThisProxy(pSubform, pScriptNode));
434   RemoveBuiltInObjs(pNewContext.get());
435   pNewContext->EnableCompatibleMode();
436   CFXJSE_Context* pResult = pNewContext.get();
437   m_mapVariableToContext[pScriptNode] = std::move(pNewContext);
438   return pResult;
439 }
440 
GetVariablesThis(CXFA_Object * pObject,bool bScriptNode)441 CXFA_Object* CFXJSE_Engine::GetVariablesThis(CXFA_Object* pObject,
442                                              bool bScriptNode) {
443   if (!pObject->IsVariablesThis())
444     return pObject;
445 
446   CXFA_ThisProxy* pProxy = static_cast<CXFA_ThisProxy*>(pObject);
447   return bScriptNode ? pProxy->GetScriptNode() : pProxy->GetThisNode();
448 }
449 
RunVariablesScript(CXFA_Node * pScriptNode)450 bool CFXJSE_Engine::RunVariablesScript(CXFA_Node* pScriptNode) {
451   if (!pScriptNode)
452     return false;
453 
454   if (pScriptNode->GetElementType() != XFA_Element::Script)
455     return true;
456 
457   CXFA_Node* pParent = pScriptNode->GetParent();
458   if (!pParent || pParent->GetElementType() != XFA_Element::Variables)
459     return false;
460 
461   auto it = m_mapVariableToContext.find(pScriptNode);
462   if (it != m_mapVariableToContext.end() && it->second)
463     return true;
464 
465   CXFA_Node* pTextNode = pScriptNode->GetFirstChild();
466   if (!pTextNode)
467     return false;
468 
469   Optional<WideString> wsScript =
470       pTextNode->JSObject()->TryCData(XFA_Attribute::Value, true);
471   if (!wsScript)
472     return false;
473 
474   ByteString btScript = wsScript->UTF8Encode();
475   auto hRetValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
476   CXFA_Node* pThisObject = pParent->GetParent();
477   CFXJSE_Context* pVariablesContext =
478       CreateVariablesContext(pScriptNode, pThisObject);
479   AutoRestorer<CXFA_Object*> nodeRestorer(&m_pThisObject);
480   m_pThisObject = pThisObject;
481   return pVariablesContext->ExecuteScript(btScript.c_str(), hRetValue.get());
482 }
483 
QueryVariableValue(CXFA_Node * pScriptNode,const ByteStringView & szPropName,CFXJSE_Value * pValue,bool bGetter)484 bool CFXJSE_Engine::QueryVariableValue(CXFA_Node* pScriptNode,
485                                        const ByteStringView& szPropName,
486                                        CFXJSE_Value* pValue,
487                                        bool bGetter) {
488   if (!pScriptNode || pScriptNode->GetElementType() != XFA_Element::Script)
489     return false;
490 
491   CXFA_Node* variablesNode = pScriptNode->GetParent();
492   if (!variablesNode ||
493       variablesNode->GetElementType() != XFA_Element::Variables)
494     return false;
495 
496   auto it = m_mapVariableToContext.find(pScriptNode);
497   if (it == m_mapVariableToContext.end() || !it->second)
498     return false;
499 
500   CFXJSE_Context* pVariableContext = it->second.get();
501   std::unique_ptr<CFXJSE_Value> pObject = pVariableContext->GetGlobalObject();
502   auto hVariableValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
503   if (!bGetter) {
504     pObject->SetObjectOwnProperty(szPropName, pValue);
505     return true;
506   }
507   if (pObject->HasObjectOwnProperty(szPropName, false)) {
508     pObject->GetObjectProperty(szPropName, hVariableValue.get());
509     if (hVariableValue->IsFunction())
510       pValue->SetFunctionBind(hVariableValue.get(), pObject.get());
511     else if (bGetter)
512       pValue->Assign(hVariableValue.get());
513     else
514       hVariableValue.get()->Assign(pValue);
515     return true;
516   }
517   return false;
518 }
519 
RemoveBuiltInObjs(CFXJSE_Context * pContext) const520 void CFXJSE_Engine::RemoveBuiltInObjs(CFXJSE_Context* pContext) const {
521   static const ByteStringView OBJ_NAME[2] = {"Number", "Date"};
522   std::unique_ptr<CFXJSE_Value> pObject = pContext->GetGlobalObject();
523   auto hProp = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
524   for (int i = 0; i < 2; ++i) {
525     if (pObject->GetObjectProperty(OBJ_NAME[i], hProp.get()))
526       pObject->DeleteObjectProperty(OBJ_NAME[i]);
527   }
528 }
529 
GetJseNormalClass()530 CFXJSE_Class* CFXJSE_Engine::GetJseNormalClass() {
531   return m_pJsClass;
532 }
533 
ResolveObjects(CXFA_Object * refObject,const WideStringView & wsExpression,XFA_RESOLVENODE_RS * resolveNodeRS,uint32_t dwStyles,CXFA_Node * bindNode)534 bool CFXJSE_Engine::ResolveObjects(CXFA_Object* refObject,
535                                    const WideStringView& wsExpression,
536                                    XFA_RESOLVENODE_RS* resolveNodeRS,
537                                    uint32_t dwStyles,
538                                    CXFA_Node* bindNode) {
539   if (wsExpression.IsEmpty())
540     return false;
541 
542   if (m_eScriptType != CXFA_Script::Type::Formcalc ||
543       (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) {
544     m_upObjectArray.clear();
545   }
546   if (refObject && refObject->IsNode() &&
547       (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) {
548     m_upObjectArray.push_back(refObject->AsNode());
549   }
550 
551   bool bNextCreate = false;
552   if (dwStyles & XFA_RESOLVENODE_CreateNode)
553     m_ResolveProcessor->GetNodeHelper()->SetCreateNodeType(bindNode);
554 
555   m_ResolveProcessor->GetNodeHelper()->m_pCreateParent = nullptr;
556   m_ResolveProcessor->GetNodeHelper()->m_iCurAllStart = -1;
557 
558   CFXJSE_ResolveNodeData rndFind(this);
559   int32_t nStart = 0;
560   int32_t nLevel = 0;
561 
562   std::vector<CXFA_Object*> findObjects;
563   findObjects.push_back(refObject ? refObject : m_pDocument->GetRoot());
564   int32_t nNodes = 0;
565   while (true) {
566     nNodes = pdfium::CollectionSize<int32_t>(findObjects);
567     int32_t i = 0;
568     rndFind.m_dwStyles = dwStyles;
569     m_ResolveProcessor->SetCurStart(nStart);
570     nStart = m_ResolveProcessor->GetFilter(wsExpression, nStart, rndFind);
571     if (nStart < 1) {
572       if ((dwStyles & XFA_RESOLVENODE_CreateNode) && !bNextCreate) {
573         CXFA_Node* pDataNode = nullptr;
574         nStart = m_ResolveProcessor->GetNodeHelper()->m_iCurAllStart;
575         if (nStart != -1) {
576           pDataNode = m_pDocument->GetNotBindNode(findObjects);
577           if (pDataNode) {
578             findObjects.clear();
579             findObjects.push_back(pDataNode);
580             break;
581           }
582         } else {
583           pDataNode = findObjects.front()->AsNode();
584           findObjects.clear();
585           findObjects.push_back(pDataNode);
586           break;
587         }
588         dwStyles |= XFA_RESOLVENODE_Bind;
589         findObjects.clear();
590         findObjects.push_back(
591             m_ResolveProcessor->GetNodeHelper()->m_pAllStartParent);
592         continue;
593       }
594       break;
595     }
596     if (bNextCreate) {
597       bool bCreate =
598           m_ResolveProcessor->GetNodeHelper()->ResolveNodes_CreateNode(
599               rndFind.m_wsName, rndFind.m_wsCondition,
600               nStart ==
601                   pdfium::base::checked_cast<int32_t>(wsExpression.GetLength()),
602               this);
603       if (bCreate)
604         continue;
605 
606       break;
607     }
608 
609     std::vector<CXFA_Object*> retObjects;
610     while (i < nNodes) {
611       bool bDataBind = false;
612       if (((dwStyles & XFA_RESOLVENODE_Bind) ||
613            (dwStyles & XFA_RESOLVENODE_CreateNode)) &&
614           nNodes > 1) {
615         CFXJSE_ResolveNodeData rndBind(nullptr);
616         m_ResolveProcessor->GetFilter(wsExpression, nStart, rndBind);
617         m_ResolveProcessor->SetIndexDataBind(rndBind.m_wsCondition, i, nNodes);
618         bDataBind = true;
619       }
620       rndFind.m_CurObject = findObjects[i++];
621       rndFind.m_nLevel = nLevel;
622       rndFind.m_dwFlag = XFA_ResolveNode_RSType_Nodes;
623       if (!m_ResolveProcessor->Resolve(rndFind))
624         continue;
625 
626       if (rndFind.m_dwFlag == XFA_ResolveNode_RSType_Attribute &&
627           rndFind.m_pScriptAttribute &&
628           nStart <
629               pdfium::base::checked_cast<int32_t>(wsExpression.GetLength())) {
630         auto pValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
631         CJX_Object* jsObject = rndFind.m_Objects.front()->JSObject();
632         (jsObject->*(rndFind.m_pScriptAttribute->callback))(
633             pValue.get(), false, rndFind.m_pScriptAttribute->attribute);
634         rndFind.m_Objects.front() = ToObject(pValue.get(), nullptr);
635       }
636       if (!m_upObjectArray.empty())
637         m_upObjectArray.pop_back();
638       retObjects.insert(retObjects.end(), rndFind.m_Objects.begin(),
639                         rndFind.m_Objects.end());
640       rndFind.m_Objects.clear();
641       if (bDataBind)
642         break;
643     }
644     findObjects.clear();
645 
646     nNodes = pdfium::CollectionSize<int32_t>(retObjects);
647     if (nNodes < 1) {
648       if (dwStyles & XFA_RESOLVENODE_CreateNode) {
649         bNextCreate = true;
650         if (!m_ResolveProcessor->GetNodeHelper()->m_pCreateParent) {
651           m_ResolveProcessor->GetNodeHelper()->m_pCreateParent =
652               ToNode(rndFind.m_CurObject);
653           m_ResolveProcessor->GetNodeHelper()->m_iCreateCount = 1;
654         }
655         bool bCreate =
656             m_ResolveProcessor->GetNodeHelper()->ResolveNodes_CreateNode(
657                 rndFind.m_wsName, rndFind.m_wsCondition,
658                 nStart == pdfium::base::checked_cast<int32_t>(
659                               wsExpression.GetLength()),
660                 this);
661         if (bCreate)
662           continue;
663       }
664       break;
665     }
666 
667     findObjects =
668         std::vector<CXFA_Object*>(retObjects.begin(), retObjects.end());
669     rndFind.m_Objects.clear();
670     if (nLevel == 0)
671       dwStyles &= ~(XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
672 
673     nLevel++;
674   }
675 
676   if (!bNextCreate) {
677     resolveNodeRS->dwFlags = rndFind.m_dwFlag;
678     if (nNodes > 0) {
679       resolveNodeRS->objects.insert(resolveNodeRS->objects.end(),
680                                     findObjects.begin(), findObjects.end());
681     }
682     if (rndFind.m_dwFlag == XFA_ResolveNode_RSType_Attribute) {
683       resolveNodeRS->pScriptAttribute = rndFind.m_pScriptAttribute;
684       return 1;
685     }
686   }
687   if (dwStyles & (XFA_RESOLVENODE_CreateNode | XFA_RESOLVENODE_Bind |
688                   XFA_RESOLVENODE_BindNew)) {
689     CXFA_NodeHelper* helper = m_ResolveProcessor->GetNodeHelper();
690     if (helper->m_pCreateParent)
691       resolveNodeRS->objects.push_back(helper->m_pCreateParent);
692     else
693       helper->CreateNode_ForCondition(rndFind.m_wsCondition);
694 
695     resolveNodeRS->dwFlags = helper->m_iCreateFlag;
696     if (resolveNodeRS->dwFlags == XFA_ResolveNode_RSType_CreateNodeOne) {
697       if (helper->m_iCurAllStart != -1)
698         resolveNodeRS->dwFlags = XFA_ResolveNode_RSType_CreateNodeMidAll;
699     }
700 
701     if (!bNextCreate && (dwStyles & XFA_RESOLVENODE_CreateNode))
702       resolveNodeRS->dwFlags = XFA_ResolveNode_RSType_ExistNodes;
703 
704     return !resolveNodeRS->objects.empty();
705   }
706   return nNodes > 0;
707 }
708 
AddToCacheList(std::unique_ptr<CXFA_List> pList)709 void CFXJSE_Engine::AddToCacheList(std::unique_ptr<CXFA_List> pList) {
710   m_CacheList.push_back(std::move(pList));
711 }
712 
GetJSValueFromMap(CXFA_Object * pObject)713 CFXJSE_Value* CFXJSE_Engine::GetJSValueFromMap(CXFA_Object* pObject) {
714   if (!pObject)
715     return nullptr;
716   if (pObject->IsNode())
717     RunVariablesScript(pObject->AsNode());
718 
719   auto iter = m_mapObjectToValue.find(pObject);
720   if (iter != m_mapObjectToValue.end())
721     return iter->second.get();
722 
723   auto jsValue = pdfium::MakeUnique<CFXJSE_Value>(GetIsolate());
724   jsValue->SetObject(pObject, m_pJsClass);
725 
726   CFXJSE_Value* pValue = jsValue.get();
727   m_mapObjectToValue.insert(std::make_pair(pObject, std::move(jsValue)));
728   return pValue;
729 }
730 
GetIndexByName(CXFA_Node * refNode)731 int32_t CFXJSE_Engine::GetIndexByName(CXFA_Node* refNode) {
732   CXFA_NodeHelper* lpNodeHelper = m_ResolveProcessor->GetNodeHelper();
733   return lpNodeHelper->GetIndex(refNode, XFA_LOGIC_Transparent,
734                                 lpNodeHelper->NodeIsProperty(refNode), false);
735 }
736 
GetIndexByClassName(CXFA_Node * refNode)737 int32_t CFXJSE_Engine::GetIndexByClassName(CXFA_Node* refNode) {
738   CXFA_NodeHelper* lpNodeHelper = m_ResolveProcessor->GetNodeHelper();
739   return lpNodeHelper->GetIndex(refNode, XFA_LOGIC_Transparent,
740                                 lpNodeHelper->NodeIsProperty(refNode), true);
741 }
742 
GetSomExpression(CXFA_Node * refNode)743 WideString CFXJSE_Engine::GetSomExpression(CXFA_Node* refNode) {
744   CXFA_NodeHelper* lpNodeHelper = m_ResolveProcessor->GetNodeHelper();
745   return lpNodeHelper->GetNameExpression(refNode, true, XFA_LOGIC_Transparent);
746 }
747 
SetNodesOfRunScript(std::vector<CXFA_Node * > * pArray)748 void CFXJSE_Engine::SetNodesOfRunScript(std::vector<CXFA_Node*>* pArray) {
749   m_pScriptNodeArray = pArray;
750 }
751 
AddNodesOfRunScript(CXFA_Node * pNode)752 void CFXJSE_Engine::AddNodesOfRunScript(CXFA_Node* pNode) {
753   if (m_pScriptNodeArray && !pdfium::ContainsValue(*m_pScriptNodeArray, pNode))
754     m_pScriptNodeArray->push_back(pNode);
755 }
756