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