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/src/foxitlib.h"
8#include "xfa/src/fxfa/src/common/xfa_utils.h"
9#include "xfa/src/fxfa/src/common/xfa_object.h"
10#include "xfa/src/fxfa/src/common/xfa_document.h"
11#include "xfa/src/fxfa/src/common/xfa_parser.h"
12#include "xfa/src/fxfa/src/common/xfa_script.h"
13#include "xfa/src/fxfa/src/common/xfa_docdata.h"
14#include "xfa/src/fxfa/src/common/xfa_doclayout.h"
15#include "xfa/src/fxfa/src/common/xfa_localemgr.h"
16#include "xfa/src/fxfa/src/common/xfa_fm2jsapi.h"
17#include "xfa_script_imp.h"
18#include "xfa_script_resolveprocessor.h"
19#include "xfa_script_nodehelper.h"
20CXFA_ScriptContext::CXFA_ScriptContext(CXFA_Document* pDocument)
21    : m_pDocument(pDocument),
22      m_hJsContext(nullptr),
23      m_hJsRuntime(nullptr),
24      m_hJsClass(nullptr),
25      m_eScriptType(XFA_SCRIPTLANGTYPE_Unkown),
26      m_pEventParam(nullptr),
27      m_pScriptNodeArray(nullptr),
28      m_pResolveProcessor(nullptr),
29      m_hFM2JSContext(nullptr),
30      m_pThisObject(nullptr),
31      m_dwBuiltInInFlags(0),
32      m_eRunAtType(XFA_ATTRIBUTEENUM_Client) {
33  FX_memset(&m_JsGlobalClass, 0, sizeof(FXJSE_CLASS));
34  FX_memset(&m_JsNormalClass, 0, sizeof(FXJSE_CLASS));
35}
36CXFA_ScriptContext::~CXFA_ScriptContext() {
37  FX_POSITION ps = m_mapXFAToHValue.GetStartPosition();
38  while (ps) {
39    CXFA_Object* pXFAObj;
40    FXJSE_HVALUE pValue;
41    m_mapXFAToHValue.GetNextAssoc(ps, pXFAObj, pValue);
42    FXJSE_Value_Release(pValue);
43  }
44  m_mapXFAToHValue.RemoveAll();
45  ReleaseVariablesMap();
46  if (m_hFM2JSContext) {
47    XFA_FM2JS_ContextRelease(m_hFM2JSContext);
48    m_hFM2JSContext = NULL;
49  }
50  if (m_hJsContext) {
51    FXJSE_Context_Release(m_hJsContext);
52    m_hJsContext = NULL;
53  }
54  if (m_pResolveProcessor) {
55    delete m_pResolveProcessor;
56    m_pResolveProcessor = NULL;
57  }
58  m_upObjectArray.RemoveAll();
59  for (int32_t i = 0; i < m_CacheListArray.GetSize(); i++) {
60    delete ((CXFA_NodeList*)m_CacheListArray[i]);
61  }
62  m_CacheListArray.RemoveAll();
63  if (m_dwBuiltInInFlags & XFA_JSBUILTIN_HasCount) {
64    FX_POSITION ps = m_JSBuiltInObjects.GetStartPosition();
65    while (ps) {
66      CFX_ByteString bsKey;
67      void* pValue = NULL;
68      m_JSBuiltInObjects.GetNextAssoc(ps, bsKey, pValue);
69      if (pValue) {
70        FXJSE_Value_Release((FXJSE_HVALUE)pValue);
71      }
72    }
73    m_JSBuiltInObjects.RemoveAll();
74  }
75}
76void CXFA_ScriptContext::Initialize(FXJSE_HRUNTIME hRuntime) {
77  m_hJsRuntime = hRuntime;
78  DefineJsContext();
79  DefineJsClass();
80  m_pResolveProcessor = new CXFA_ResolveProcessor;
81}
82void CXFA_ScriptContext::Release() {
83  delete this;
84}
85FX_BOOL CXFA_ScriptContext::RunScript(XFA_SCRIPTLANGTYPE eScriptType,
86                                      const CFX_WideStringC& wsScript,
87                                      FXJSE_HVALUE hRetValue,
88                                      CXFA_Object* pThisObject) {
89  CFX_ByteString btScript;
90  XFA_SCRIPTLANGTYPE eSaveType = m_eScriptType;
91  m_eScriptType = eScriptType;
92  if (eScriptType == XFA_SCRIPTLANGTYPE_Formcalc) {
93    if (!m_hFM2JSContext) {
94      m_hFM2JSContext = XFA_FM2JS_ContextCreate();
95      XFA_FM2JS_ContextInitialize(m_hFM2JSContext, m_hJsRuntime, m_hJsContext,
96                                  m_pDocument);
97    }
98    CFX_WideTextBuf wsJavaScript;
99    CFX_WideString wsErrorInfo;
100    int32_t iFlags = XFA_FM2JS_Translate(wsScript, wsJavaScript, wsErrorInfo);
101    if (iFlags) {
102      FXJSE_Value_SetUndefined(hRetValue);
103      return FALSE;
104    }
105    btScript =
106        FX_UTF8Encode(wsJavaScript.GetBuffer(), wsJavaScript.GetLength());
107  } else {
108    if ((m_dwBuiltInInFlags & XFA_JSBUILTIN_Initialized) == 0) {
109      m_dwBuiltInInFlags = XFA_JSBUILTIN_Initialized;
110      FX_POSITION ps = m_JSBuiltInObjects.GetStartPosition();
111      if (ps) {
112        FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(m_hJsContext);
113        while (ps) {
114          CFX_ByteString bsKey;
115          void* pValue;
116          m_JSBuiltInObjects.GetNextAssoc(ps, bsKey, pValue);
117          FXJSE_HVALUE hProp = FXJSE_Value_Create(m_hJsRuntime);
118          if (FXJSE_Value_GetObjectProp(hObject, bsKey, hProp)) {
119            m_JSBuiltInObjects.SetAt(bsKey, hProp);
120            FXJSE_Value_DeleteObjectProp(hObject, bsKey);
121            m_dwBuiltInInFlags |= XFA_JSBUILTIN_HasCount;
122          } else {
123            m_JSBuiltInObjects.RemoveKey(bsKey);
124            FXJSE_Value_Release(hProp);
125          }
126        }
127        FXJSE_Value_Release(hObject);
128      }
129    }
130    btScript = FX_UTF8Encode(wsScript.GetPtr(), wsScript.GetLength());
131  }
132  CXFA_Object* pOriginalObject = m_pThisObject;
133  m_pThisObject = pThisObject;
134  FXJSE_HVALUE pValue = pThisObject ? GetJSValueFromMap(pThisObject) : NULL;
135  FX_BOOL bRet = FXJSE_ExecuteScript(m_hJsContext, btScript, hRetValue, pValue);
136  m_pThisObject = pOriginalObject;
137  m_eScriptType = eSaveType;
138  return bRet;
139}
140void CXFA_ScriptContext::GlobalPropertySetter(FXJSE_HOBJECT hObject,
141                                              const CFX_ByteStringC& szPropName,
142                                              FXJSE_HVALUE hValue) {
143  CXFA_Object* lpOrginalNode =
144      (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
145  CXFA_Document* pDoc = lpOrginalNode->GetDocument();
146  CXFA_ScriptContext* lpScriptContext =
147      (CXFA_ScriptContext*)pDoc->GetScriptContext();
148  CXFA_Object* lpCurNode = lpScriptContext->GetVariablesThis(lpOrginalNode);
149  CFX_WideString wsPropName = CFX_WideString::FromUTF8(
150      (const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength());
151  FX_DWORD dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings |
152                    XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
153                    XFA_RESOLVENODE_Attributes;
154  CXFA_Node* pRefNode = (CXFA_Node*)lpScriptContext->GetThisObject();
155  if (lpOrginalNode->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {
156    pRefNode = (CXFA_Node*)lpCurNode;
157  }
158  if (lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag,
159                                       TRUE)) {
160    return;
161  }
162  if (lpOrginalNode->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {
163    if (FXJSE_Value_IsUndefined(hValue)) {
164      FXJSE_Value_SetObjectOwnProp(hObject, szPropName, hValue);
165      return;
166    }
167  }
168  IXFA_Notify* pNotify = pDoc->GetNotify();
169  if (!pNotify) {
170    return;
171  }
172  pNotify->GetDocProvider()->SetGlobalProperty(pNotify->GetHDOC(), szPropName,
173                                               hValue);
174}
175FX_BOOL CXFA_ScriptContext::QueryNodeByFlag(CXFA_Node* refNode,
176                                            const CFX_WideStringC& propname,
177                                            FXJSE_HVALUE hValue,
178                                            FX_DWORD dwFlag,
179                                            FX_BOOL bSetting) {
180  XFA_RESOLVENODE_RS resolveRs;
181  int32_t iRet = ResolveObjects(refNode, propname, resolveRs, dwFlag);
182  FX_BOOL bResult = FALSE;
183  if (iRet > 0) {
184    bResult = TRUE;
185    if (resolveRs.dwFlags == XFA_RESOVENODE_RSTYPE_Nodes) {
186      FXJSE_HVALUE pValue = GetJSValueFromMap(resolveRs.nodes[0]);
187      FXJSE_Value_Set(hValue, pValue);
188    } else if (resolveRs.dwFlags == XFA_RESOVENODE_RSTYPE_Attribute) {
189      XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = resolveRs.pScriptAttribute;
190      if (lpAttributeInfo) {
191        (resolveRs.nodes[0]->*(lpAttributeInfo->lpfnCallback))(
192            hValue, bSetting, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute);
193      }
194    }
195  }
196  return bResult;
197}
198void CXFA_ScriptContext::GlobalPropertyGetter(FXJSE_HOBJECT hObject,
199                                              const CFX_ByteStringC& szPropName,
200                                              FXJSE_HVALUE hValue) {
201  CXFA_Object* pOrginalObject =
202      (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
203  CXFA_Document* pDoc = pOrginalObject->GetDocument();
204  CXFA_ScriptContext* lpScriptContext =
205      (CXFA_ScriptContext*)pDoc->GetScriptContext();
206  CXFA_Object* lpCurNode = lpScriptContext->GetVariablesThis(pOrginalObject);
207  CFX_WideString wsPropName = CFX_WideString::FromUTF8(
208      (const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength());
209  if (lpScriptContext->GetType() == XFA_SCRIPTLANGTYPE_Formcalc) {
210    if (szPropName == FOXIT_XFA_FM2JS_FORMCALC_RUNTIME) {
211      XFA_FM2JS_GlobalPropertyGetter(lpScriptContext->m_hFM2JSContext, hValue);
212      return;
213    }
214    uint32_t uHashCode =
215        FX_HashCode_String_GetW(wsPropName, wsPropName.GetLength());
216    if (uHashCode != XFA_HASHCODE_Layout) {
217      CXFA_Object* pObject =
218          lpScriptContext->GetDocument()->GetXFANode(uHashCode);
219      if (pObject) {
220        FXJSE_Value_Set(hValue, lpScriptContext->GetJSValueFromMap(pObject));
221        return;
222      }
223    }
224  }
225  FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
226                    XFA_RESOLVENODE_Attributes;
227  CXFA_Node* pRefNode = (CXFA_Node*)lpScriptContext->GetThisObject();
228  if (pOrginalObject->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {
229    pRefNode = (CXFA_Node*)lpCurNode;
230  }
231  if (lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag,
232                                       FALSE)) {
233    return;
234  }
235  dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings;
236  if (lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag,
237                                       FALSE)) {
238    return;
239  }
240  CXFA_Object* pScriptObject =
241      lpScriptContext->GetVariablesThis(pOrginalObject, TRUE);
242  if (pScriptObject &&
243      lpScriptContext->QueryVariableHValue((CXFA_Node*)pScriptObject,
244                                           szPropName, hValue, TRUE)) {
245    return;
246  }
247  if (lpScriptContext->QueryBuiltinHValue(szPropName, hValue)) {
248    return;
249  }
250  IXFA_Notify* pNotify = pDoc->GetNotify();
251  if (!pNotify) {
252    return;
253  }
254  pNotify->GetDocProvider()->GetGlobalProperty(pNotify->GetHDOC(), szPropName,
255                                               hValue);
256}
257void CXFA_ScriptContext::NormalPropertyGetter(FXJSE_HOBJECT hObject,
258                                              const CFX_ByteStringC& szPropName,
259                                              FXJSE_HVALUE hValue) {
260  CXFA_Object* pOrginalObject =
261      (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
262  if (pOrginalObject == NULL) {
263    FXJSE_Value_SetUndefined(hValue);
264    return;
265  }
266  CFX_WideString wsPropName = CFX_WideString::FromUTF8(
267      (const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength());
268  CXFA_ScriptContext* lpScriptContext =
269      (CXFA_ScriptContext*)pOrginalObject->GetDocument()->GetScriptContext();
270  CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOrginalObject);
271  if (wsPropName == FX_WSTRC(L"xfa")) {
272    FXJSE_HVALUE pValue = lpScriptContext->GetJSValueFromMap(
273        lpScriptContext->GetDocument()->GetRoot());
274    FXJSE_Value_Set(hValue, pValue);
275    return;
276  }
277  FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
278                    XFA_RESOLVENODE_Attributes;
279  FX_BOOL bRet = lpScriptContext->QueryNodeByFlag(
280      (CXFA_Node*)pObject, wsPropName, hValue, dwFlag, FALSE);
281  if (bRet) {
282    return;
283  }
284  if (pObject == lpScriptContext->GetThisObject() ||
285      (lpScriptContext->GetType() == XFA_SCRIPTLANGTYPE_Javascript &&
286       !lpScriptContext->IsStrictScopeInJavaScript())) {
287    dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings;
288    bRet = lpScriptContext->QueryNodeByFlag((CXFA_Node*)pObject, wsPropName,
289                                            hValue, dwFlag, FALSE);
290  }
291  if (bRet) {
292    return;
293  }
294  CXFA_Object* pScriptObject =
295      lpScriptContext->GetVariablesThis(pOrginalObject, TRUE);
296  if (pScriptObject) {
297    bRet = lpScriptContext->QueryVariableHValue((CXFA_Node*)pScriptObject,
298                                                szPropName, hValue, TRUE);
299  }
300  if (!bRet) {
301    FXJSE_Value_SetUndefined(hValue);
302  }
303}
304void CXFA_ScriptContext::NormalPropertySetter(FXJSE_HOBJECT hObject,
305                                              const CFX_ByteStringC& szPropName,
306                                              FXJSE_HVALUE hValue) {
307  CXFA_Object* pOrginalObject =
308      (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
309  if (pOrginalObject == NULL) {
310    return;
311  }
312  CXFA_ScriptContext* lpScriptContext =
313      (CXFA_ScriptContext*)pOrginalObject->GetDocument()->GetScriptContext();
314  CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOrginalObject);
315  CFX_WideString wsPropName = CFX_WideString::FromUTF8(
316      (const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength());
317  XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo =
318      XFA_GetScriptAttributeByName(pObject->GetClassID(), wsPropName);
319  if (lpAttributeInfo) {
320    (pObject->*(lpAttributeInfo->lpfnCallback))(
321        hValue, TRUE, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute);
322  } else {
323    if (pObject->IsNode()) {
324      if (wsPropName.GetAt(0) == '#') {
325        wsPropName = wsPropName.Right(wsPropName.GetLength() - 1);
326      }
327      CXFA_Node* pNode = (CXFA_Node*)pObject;
328      CXFA_Node* pPropOrChild = NULL;
329      XFA_LPCELEMENTINFO lpElementInfo = XFA_GetElementByName(wsPropName);
330      if (lpElementInfo) {
331        pPropOrChild = pNode->GetProperty(0, lpElementInfo->eName);
332      } else {
333        pPropOrChild = pNode->GetFirstChildByName(wsPropName);
334      }
335      if (pPropOrChild) {
336        CFX_WideString wsDefaultName = FX_WSTRC(L"{default}");
337        XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo =
338            XFA_GetScriptAttributeByName(pPropOrChild->GetClassID(),
339                                         wsDefaultName);
340        if (lpAttributeInfo) {
341          (pPropOrChild->*(lpAttributeInfo->lpfnCallback))(
342              hValue, TRUE, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute);
343          return;
344        }
345      }
346    }
347    CXFA_Object* pScriptObject =
348        lpScriptContext->GetVariablesThis(pOrginalObject, TRUE);
349    if (pScriptObject) {
350      lpScriptContext->QueryVariableHValue((CXFA_Node*)pScriptObject,
351                                           szPropName, hValue, FALSE);
352    }
353  }
354}
355int32_t CXFA_ScriptContext::NormalPropTypeGetter(
356    FXJSE_HOBJECT hObject,
357    const CFX_ByteStringC& szPropName,
358    FX_BOOL bQueryIn) {
359  CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
360  if (pObject == NULL) {
361    return FXJSE_ClassPropType_None;
362  }
363  CXFA_ScriptContext* lpScriptContext =
364      (CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext();
365  pObject = lpScriptContext->GetVariablesThis(pObject);
366  XFA_ELEMENT objElement = pObject->GetClassID();
367  CFX_WideString wsPropName = CFX_WideString::FromUTF8(
368      (const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength());
369  if (XFA_GetMethodByName(objElement, wsPropName)) {
370    return FXJSE_ClassPropType_Method;
371  }
372  if (bQueryIn && !XFA_GetScriptAttributeByName(objElement, wsPropName)) {
373    return FXJSE_ClassPropType_None;
374  }
375  return FXJSE_ClassPropType_Property;
376}
377int32_t CXFA_ScriptContext::GlobalPropTypeGetter(
378    FXJSE_HOBJECT hObject,
379    const CFX_ByteStringC& szPropName,
380    FX_BOOL bQueryIn) {
381  CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
382  if (pObject == NULL) {
383    return FXJSE_ClassPropType_None;
384  }
385  CXFA_ScriptContext* lpScriptContext =
386      (CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext();
387  pObject = lpScriptContext->GetVariablesThis(pObject);
388  XFA_ELEMENT objElement = pObject->GetClassID();
389  CFX_WideString wsPropName = CFX_WideString::FromUTF8(
390      (const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength());
391  if (XFA_GetMethodByName(objElement, wsPropName)) {
392    return FXJSE_ClassPropType_Method;
393  }
394  return FXJSE_ClassPropType_Property;
395}
396void CXFA_ScriptContext::NormalMethodCall(FXJSE_HOBJECT hThis,
397                                          const CFX_ByteStringC& szFuncName,
398                                          CFXJSE_Arguments& args) {
399  CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hThis, NULL);
400  if (pObject == NULL) {
401    return;
402  }
403  CXFA_ScriptContext* lpScriptContext =
404      (CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext();
405  pObject = lpScriptContext->GetVariablesThis(pObject);
406  CFX_WideString wsFunName = CFX_WideString::FromUTF8(
407      (const FX_CHAR*)szFuncName.GetPtr(), szFuncName.GetLength());
408  XFA_LPCMETHODINFO lpMethodInfo =
409      XFA_GetMethodByName(pObject->GetClassID(), wsFunName);
410  if (NULL == lpMethodInfo) {
411    return;
412  }
413  (pObject->*(lpMethodInfo->lpfnCallback))(&args);
414}
415FX_BOOL CXFA_ScriptContext::IsStrictScopeInJavaScript() {
416  return m_pDocument->HasFlag(XFA_DOCFLAG_StrictScoping);
417}
418XFA_SCRIPTLANGTYPE CXFA_ScriptContext::GetType() {
419  return m_eScriptType;
420}
421void CXFA_ScriptContext::DefineJsContext() {
422  m_JsGlobalClass.constructor = NULL;
423  m_JsGlobalClass.name = "Root";
424  m_JsGlobalClass.propNum = 0;
425  m_JsGlobalClass.properties = NULL;
426  m_JsGlobalClass.methNum = 0;
427  m_JsGlobalClass.methods = NULL;
428  m_JsGlobalClass.dynPropGetter = CXFA_ScriptContext::GlobalPropertyGetter;
429  m_JsGlobalClass.dynPropSetter = CXFA_ScriptContext::GlobalPropertySetter;
430  m_JsGlobalClass.dynPropTypeGetter = CXFA_ScriptContext::GlobalPropTypeGetter;
431  m_JsGlobalClass.dynPropDeleter = NULL;
432  m_JsGlobalClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall;
433  m_hJsContext = FXJSE_Context_Create(m_hJsRuntime, &m_JsGlobalClass,
434                                      m_pDocument->GetRoot());
435  FXJSE_Context_EnableCompatibleMode(
436      m_hJsContext, FXJSE_COMPATIBLEMODEFLAG_CONSTRUCTOREXTRAMETHODS);
437}
438FXJSE_HCONTEXT CXFA_ScriptContext::CreateVariablesContext(
439    CXFA_Node* pScriptNode,
440    CXFA_Node* pSubform) {
441  if (pScriptNode == NULL || pSubform == NULL) {
442    return NULL;
443  }
444  if (m_mapVariableToHValue.GetCount() == 0) {
445    m_JsGlobalVariablesClass.constructor = NULL;
446    m_JsGlobalVariablesClass.name = "XFAScriptObject";
447    m_JsGlobalVariablesClass.propNum = 0;
448    m_JsGlobalVariablesClass.properties = NULL;
449    m_JsGlobalVariablesClass.methNum = 0;
450    m_JsGlobalVariablesClass.methods = NULL;
451    m_JsGlobalVariablesClass.dynPropGetter =
452        CXFA_ScriptContext::GlobalPropertyGetter;
453    m_JsGlobalVariablesClass.dynPropSetter =
454        CXFA_ScriptContext::GlobalPropertySetter;
455    m_JsGlobalVariablesClass.dynPropTypeGetter =
456        CXFA_ScriptContext::NormalPropTypeGetter;
457    m_JsGlobalVariablesClass.dynPropDeleter = NULL;
458    m_JsGlobalVariablesClass.dynMethodCall =
459        CXFA_ScriptContext::NormalMethodCall;
460  }
461  CXFA_ThisProxy* lpVariableNode = new CXFA_ThisProxy(pSubform, pScriptNode);
462  FXJSE_HCONTEXT hVariablesContext = FXJSE_Context_Create(
463      m_hJsRuntime, &m_JsGlobalVariablesClass, (CXFA_Object*)lpVariableNode);
464  FXJSE_Context_EnableCompatibleMode(
465      hVariablesContext, FXJSE_COMPATIBLEMODEFLAG_CONSTRUCTOREXTRAMETHODS);
466  m_mapVariableToHValue.SetAt(pScriptNode, hVariablesContext);
467  return hVariablesContext;
468}
469CXFA_Object* CXFA_ScriptContext::GetVariablesThis(CXFA_Object* pObject,
470                                                  FX_BOOL bScriptNode) {
471  if (pObject->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) {
472    return bScriptNode ? ((CXFA_ThisProxy*)pObject)->GetScriptNode()
473                       : ((CXFA_ThisProxy*)pObject)->GetThisNode();
474  }
475  return pObject;
476}
477FX_BOOL CXFA_ScriptContext::RunVariablesScript(CXFA_Node* pScriptNode) {
478  if (pScriptNode == NULL) {
479    return FALSE;
480  }
481  if (pScriptNode->GetClassID() == XFA_ELEMENT_Script) {
482    CXFA_Node* pParent = pScriptNode->GetNodeItem(XFA_NODEITEM_Parent);
483    if (!pParent || pParent->GetClassID() != XFA_ELEMENT_Variables) {
484      return FALSE;
485    }
486    if (m_mapVariableToHValue.GetValueAt(pScriptNode)) {
487      return TRUE;
488    }
489    CXFA_Node* pTextNode = pScriptNode->GetNodeItem(XFA_NODEITEM_FirstChild);
490    if (!pTextNode) {
491      return FALSE;
492    }
493    CFX_WideStringC wsScript;
494    if (!pTextNode->TryCData(XFA_ATTRIBUTE_Value, wsScript)) {
495      return FALSE;
496    }
497    CFX_ByteString btScript =
498        FX_UTF8Encode(wsScript.GetPtr(), wsScript.GetLength());
499    FXJSE_HVALUE hRetValue = FXJSE_Value_Create(m_hJsRuntime);
500    CXFA_Node* pThisObject = pParent->GetNodeItem(XFA_NODEITEM_Parent);
501    FXJSE_HCONTEXT hVariablesContext =
502        CreateVariablesContext(pScriptNode, pThisObject);
503    CXFA_Object* pOriginalObject = m_pThisObject;
504    m_pThisObject = pThisObject;
505    FX_BOOL bRet = FXJSE_ExecuteScript(hVariablesContext, btScript, hRetValue);
506    m_pThisObject = pOriginalObject;
507    FXJSE_Value_Release(hRetValue);
508    return bRet;
509  }
510  return TRUE;
511}
512FX_BOOL CXFA_ScriptContext::QueryVariableHValue(
513    CXFA_Node* pScriptNode,
514    const CFX_ByteStringC& szPropName,
515    FXJSE_HVALUE hValue,
516    FX_BOOL bGetter) {
517  if (pScriptNode->GetClassID() != XFA_ELEMENT_Script) {
518    return FALSE;
519  }
520  CXFA_Node* variablesNode = pScriptNode->GetNodeItem(XFA_NODEITEM_Parent);
521  if (!variablesNode || variablesNode->GetClassID() != XFA_ELEMENT_Variables) {
522    return FALSE;
523  }
524  FX_BOOL bRes = FALSE;
525  void* lpVariables = m_mapVariableToHValue.GetValueAt(pScriptNode);
526  if (lpVariables) {
527    FXJSE_HCONTEXT hVariableContext = (FXJSE_HCONTEXT)lpVariables;
528    FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(hVariableContext);
529    FXJSE_HVALUE hVariableValue = FXJSE_Value_Create(m_hJsRuntime);
530    if (!bGetter) {
531      FXJSE_Value_SetObjectOwnProp(hObject, szPropName, hValue);
532      bRes = TRUE;
533    } else if (FXJSE_Value_ObjectHasOwnProp(hObject, szPropName, FALSE)) {
534      FXJSE_Value_GetObjectProp(hObject, szPropName, hVariableValue);
535      if (FXJSE_Value_IsFunction(hVariableValue)) {
536        FXJSE_Value_SetFunctionBind(hValue, hVariableValue, hObject);
537      } else if (bGetter) {
538        FXJSE_Value_Set(hValue, hVariableValue);
539      } else {
540        FXJSE_Value_Set(hVariableValue, hValue);
541      }
542      bRes = TRUE;
543    }
544    FXJSE_Value_Release(hVariableValue);
545    FXJSE_Value_Release(hObject);
546  }
547  return bRes;
548}
549FX_BOOL CXFA_ScriptContext::QueryBuiltinHValue(
550    const CFX_ByteStringC& szPropName,
551    FXJSE_HVALUE hValue) {
552  void* pBuiltin = NULL;
553  if ((m_dwBuiltInInFlags & XFA_JSBUILTIN_HasCount) &&
554      m_JSBuiltInObjects.Lookup(szPropName, pBuiltin)) {
555    FXJSE_Value_Set(hValue, (FXJSE_HVALUE)pBuiltin);
556    return TRUE;
557  }
558  return FALSE;
559}
560void CXFA_ScriptContext::ReleaseVariablesMap() {
561  FX_POSITION ps = m_mapVariableToHValue.GetStartPosition();
562  while (ps) {
563    CXFA_Object* pScriptNode;
564    FXJSE_HCONTEXT hVariableContext;
565    m_mapVariableToHValue.GetNextAssoc(ps, pScriptNode, hVariableContext);
566    FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(hVariableContext);
567    CXFA_Object* lpCurNode = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL);
568    if (lpCurNode) {
569      delete (CXFA_ThisProxy*)lpCurNode;
570      lpCurNode = NULL;
571    }
572    FXJSE_Value_Release(hObject);
573    FXJSE_Context_Release(hVariableContext);
574    hVariableContext = NULL;
575  }
576  m_mapVariableToHValue.RemoveAll();
577}
578void CXFA_ScriptContext::DefineJsClass() {
579  m_JsNormalClass.constructor = NULL;
580  m_JsNormalClass.name = "XFAObject";
581  m_JsNormalClass.propNum = 0;
582  m_JsNormalClass.properties = NULL;
583  m_JsNormalClass.methNum = 0;
584  m_JsNormalClass.methods = NULL;
585  m_JsNormalClass.dynPropGetter = CXFA_ScriptContext::NormalPropertyGetter;
586  m_JsNormalClass.dynPropSetter = CXFA_ScriptContext::NormalPropertySetter;
587  m_JsNormalClass.dynPropTypeGetter = CXFA_ScriptContext::NormalPropTypeGetter;
588  m_JsNormalClass.dynPropDeleter = NULL;
589  m_JsNormalClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall;
590  m_hJsClass = FXJSE_DefineClass(m_hJsContext, &m_JsNormalClass);
591}
592FXJSE_HCLASS CXFA_ScriptContext::GetJseNormalClass() {
593  return m_hJsClass;
594}
595void CXFA_ScriptContext::AddJSBuiltinObject(
596    XFA_LPCJSBUILTININFO pBuitinObject) {
597  if (m_dwBuiltInInFlags & XFA_JSBUILTIN_Initialized) {
598    return;
599  }
600  m_JSBuiltInObjects.SetAt(pBuitinObject->pName, (void*)pBuitinObject);
601}
602int32_t CXFA_ScriptContext::ResolveObjects(CXFA_Object* refNode,
603                                           const CFX_WideStringC& wsExpression,
604                                           XFA_RESOLVENODE_RS& resolveNodeRS,
605                                           FX_DWORD dwStyles,
606                                           CXFA_Node* bindNode) {
607  if (wsExpression.IsEmpty()) {
608    return 0;
609  }
610  if (m_eScriptType != XFA_SCRIPTLANGTYPE_Formcalc ||
611      (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) {
612    m_upObjectArray.RemoveAll();
613  }
614  if (refNode &&
615      (dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings)) &&
616      refNode->IsNode()) {
617    m_upObjectArray.Add((CXFA_Node*)refNode);
618  }
619  FX_BOOL bNextCreate = FALSE;
620  if (dwStyles & XFA_RESOLVENODE_CreateNode) {
621    m_pResolveProcessor->GetNodeHelper()->XFA_SetCreateNodeType(bindNode);
622  }
623  m_pResolveProcessor->GetNodeHelper()->m_pCreateParent = NULL;
624  m_pResolveProcessor->GetNodeHelper()->m_iCurAllStart = -1;
625  CXFA_ResolveNodesData rndFind;
626  int32_t nStart = 0;
627  int32_t nLevel = 0;
628  int32_t nRet = -1;
629  rndFind.m_pSC = this;
630  CXFA_ObjArray findNodes;
631  if (refNode != NULL) {
632    findNodes.Add(refNode);
633  } else {
634    findNodes.Add(m_pDocument->GetRoot());
635  }
636  int32_t nNodes = 0;
637  while (TRUE) {
638    nNodes = findNodes.GetSize();
639    int32_t i = 0;
640    rndFind.m_dwStyles = dwStyles;
641    m_pResolveProcessor->m_iCurStart = nStart;
642    nStart = m_pResolveProcessor->XFA_ResolveNodes_GetFilter(wsExpression,
643                                                             nStart, rndFind);
644    if (nStart < 1) {
645      if ((dwStyles & XFA_RESOLVENODE_CreateNode) && !bNextCreate) {
646        CXFA_Node* pDataNode = NULL;
647        nStart = m_pResolveProcessor->GetNodeHelper()->m_iCurAllStart;
648        if (nStart != -1) {
649          pDataNode = m_pDocument->GetNotBindNode(findNodes);
650          if (pDataNode) {
651            findNodes.RemoveAll();
652            findNodes.Add(pDataNode);
653            break;
654          }
655        } else {
656          pDataNode = (CXFA_Node*)findNodes[0];
657          findNodes.RemoveAll();
658          findNodes.Add(pDataNode);
659          break;
660        }
661        dwStyles |= XFA_RESOLVENODE_Bind;
662        findNodes.RemoveAll();
663        findNodes.Add(m_pResolveProcessor->GetNodeHelper()->m_pAllStartParent);
664        continue;
665      } else {
666        break;
667      }
668    }
669    if (bNextCreate) {
670      FX_BOOL bCreate =
671          m_pResolveProcessor->GetNodeHelper()->XFA_ResolveNodes_CreateNode(
672              rndFind.m_wsName, rndFind.m_wsCondition,
673              nStart == wsExpression.GetLength(), this);
674      if (bCreate) {
675        continue;
676      } else {
677        break;
678      }
679    }
680    CXFA_ObjArray retNodes;
681    while (i < nNodes) {
682      FX_BOOL bDataBind = FALSE;
683      if (((dwStyles & XFA_RESOLVENODE_Bind) ||
684           (dwStyles & XFA_RESOLVENODE_CreateNode)) &&
685          nNodes > 1) {
686        CXFA_ResolveNodesData rndBind;
687        m_pResolveProcessor->XFA_ResolveNodes_GetFilter(wsExpression, nStart,
688                                                        rndBind);
689        m_pResolveProcessor->XFA_ResolveNode_SetIndexDataBind(
690            rndBind.m_wsCondition, i, nNodes);
691        bDataBind = TRUE;
692      }
693      rndFind.m_CurNode = findNodes[i++];
694      rndFind.m_nLevel = nLevel;
695      rndFind.m_dwFlag = XFA_RESOVENODE_RSTYPE_Nodes;
696      nRet = m_pResolveProcessor->XFA_ResolveNodes(rndFind);
697      if (nRet < 1) {
698        continue;
699      }
700      if (rndFind.m_dwFlag == XFA_RESOVENODE_RSTYPE_Attribute &&
701          rndFind.m_pScriptAttribute && nStart < wsExpression.GetLength()) {
702        FXJSE_HVALUE hValue = FXJSE_Value_Create(m_hJsRuntime);
703        (rndFind.m_Nodes[0]->*(rndFind.m_pScriptAttribute->lpfnCallback))(
704            hValue, FALSE,
705            (XFA_ATTRIBUTE)rndFind.m_pScriptAttribute->eAttribute);
706        rndFind.m_Nodes.SetAt(0,
707                              (CXFA_Object*)FXJSE_Value_ToObject(hValue, NULL));
708        FXJSE_Value_Release(hValue);
709      }
710      int32_t iSize = m_upObjectArray.GetSize();
711      if (iSize) {
712        m_upObjectArray.RemoveAt(iSize - 1);
713      }
714      retNodes.Append(rndFind.m_Nodes);
715      rndFind.m_Nodes.RemoveAll();
716      if (bDataBind) {
717        break;
718      }
719    }
720    findNodes.RemoveAll();
721    nNodes = retNodes.GetSize();
722    if (nNodes < 1) {
723      if (dwStyles & XFA_RESOLVENODE_CreateNode) {
724        bNextCreate = TRUE;
725        if (m_pResolveProcessor->GetNodeHelper()->m_pCreateParent == NULL) {
726          m_pResolveProcessor->GetNodeHelper()->m_pCreateParent =
727              (CXFA_Node*)rndFind.m_CurNode;
728          m_pResolveProcessor->GetNodeHelper()->m_iCreateCount = 1;
729        }
730        FX_BOOL bCreate =
731            m_pResolveProcessor->GetNodeHelper()->XFA_ResolveNodes_CreateNode(
732                rndFind.m_wsName, rndFind.m_wsCondition,
733                nStart == wsExpression.GetLength(), this);
734        if (bCreate) {
735          continue;
736        } else {
737          break;
738        }
739      } else {
740        break;
741      }
742    }
743    findNodes.Copy(retNodes);
744    rndFind.m_Nodes.RemoveAll();
745    if (nLevel == 0) {
746      dwStyles &= ~(XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
747    }
748    nLevel++;
749  }
750  if (!bNextCreate) {
751    resolveNodeRS.dwFlags = rndFind.m_dwFlag;
752    if (nNodes > 0) {
753      resolveNodeRS.nodes.Append(findNodes);
754    }
755    if (rndFind.m_dwFlag == XFA_RESOVENODE_RSTYPE_Attribute) {
756      resolveNodeRS.pScriptAttribute = rndFind.m_pScriptAttribute;
757      return 1;
758    }
759  }
760  if (dwStyles & (XFA_RESOLVENODE_CreateNode | XFA_RESOLVENODE_Bind |
761                  XFA_RESOLVENODE_BindNew)) {
762    m_pResolveProcessor->XFA_ResolveNode_SetResultCreateNode(
763        resolveNodeRS, rndFind.m_wsCondition);
764    if (!bNextCreate && (dwStyles & XFA_RESOLVENODE_CreateNode)) {
765      resolveNodeRS.dwFlags = XFA_RESOVENODE_RSTYPE_ExistNodes;
766    }
767    return resolveNodeRS.nodes.GetSize();
768  }
769  return nNodes;
770}
771FXJSE_HVALUE CXFA_ScriptContext::GetJSValueFromMap(CXFA_Object* pObject) {
772  if (!pObject) {
773    return NULL;
774  }
775  if (pObject->IsNode()) {
776    RunVariablesScript((CXFA_Node*)pObject);
777  }
778  void* pValue = m_mapXFAToHValue.GetValueAt(pObject);
779  if (pValue == NULL) {
780    FXJSE_HVALUE jsHvalue = FXJSE_Value_Create(m_hJsRuntime);
781    FXJSE_Value_SetObject(jsHvalue, pObject, m_hJsClass);
782    m_mapXFAToHValue.SetAt(pObject, jsHvalue);
783    pValue = jsHvalue;
784  }
785  return (FXJSE_HVALUE)pValue;
786}
787int32_t CXFA_ScriptContext::GetIndexByName(CXFA_Node* refNode) {
788  CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper();
789  return lpNodeHelper->XFA_GetIndex(refNode, XFA_LOGIC_Transparent,
790                                    lpNodeHelper->XFA_NodeIsProperty(refNode),
791                                    FALSE);
792}
793int32_t CXFA_ScriptContext::GetIndexByClassName(CXFA_Node* refNode) {
794  CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper();
795  return lpNodeHelper->XFA_GetIndex(refNode, XFA_LOGIC_Transparent,
796                                    lpNodeHelper->XFA_NodeIsProperty(refNode),
797                                    TRUE);
798}
799void CXFA_ScriptContext::GetSomExpression(CXFA_Node* refNode,
800                                          CFX_WideString& wsExpression) {
801  CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper();
802  lpNodeHelper->XFA_GetNameExpression(refNode, wsExpression, TRUE,
803                                      XFA_LOGIC_Transparent);
804}
805void CXFA_ScriptContext::SetNodesOfRunScript(CXFA_NodeArray* pArray) {
806  m_pScriptNodeArray = pArray;
807}
808void CXFA_ScriptContext::AddNodesOfRunScript(const CXFA_NodeArray& nodes) {
809  if (!m_pScriptNodeArray) {
810    return;
811  }
812  if (nodes.GetSize() > 0) {
813    m_pScriptNodeArray->Copy(nodes);
814  }
815}
816void CXFA_ScriptContext::AddNodesOfRunScript(CXFA_Node* pNode) {
817  if (!m_pScriptNodeArray) {
818    return;
819  }
820  if (m_pScriptNodeArray->Find(pNode) == -1) {
821    m_pScriptNodeArray->Add(pNode);
822  }
823}
824IXFA_ScriptContext* XFA_ScriptContext_Create(CXFA_Document* pDocument) {
825  return new CXFA_ScriptContext(pDocument);
826}
827static const XFA_JSBUILTININFO gs_JSBUILTINData[] = {
828    {0x8108b9a9, "Number"},
829    {0xe07e3fbe, "Date"},
830};
831const int32_t g_iJSBuiltinCount =
832    sizeof(XFA_JSBUILTININFO) / sizeof(XFA_JSBUILTININFO);
833XFA_LPCJSBUILTININFO XFA_GetJSBuiltinByHash(uint32_t uHashCode) {
834  int32_t iStart = 0, iEnd = g_iJSBuiltinCount - 1, iMid;
835  do {
836    iMid = (iStart + iEnd) / 2;
837    XFA_LPCJSBUILTININFO pInfo = gs_JSBUILTINData + iMid;
838    if (uHashCode == pInfo->uUnicodeHash) {
839      return pInfo;
840    } else if (uHashCode < pInfo->uUnicodeHash) {
841      iEnd = iMid - 1;
842    } else {
843      iStart = iMid + 1;
844    }
845  } while (iStart <= iEnd);
846  return NULL;
847}
848