• 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 "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 
27 namespace {
28 
29 const 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 
43 const 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 
57 const 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 
71 const char kFormCalcRuntime[] = "foxit_xfa_formcalc_runtime";
72 
ToThisProxy(CFXJSE_Value * pValue,CFXJSE_Class * pClass)73 CXFA_ThisProxy* ToThisProxy(CFXJSE_Value* pValue, CFXJSE_Class* pClass) {
74   return static_cast<CXFA_ThisProxy*>(pValue->ToHostObject(pClass));
75 }
76 
GetMethodByName(XFA_Element eElement,const CFX_WideStringC & wsMethodName)77 const 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.
ToObject(CFXJSE_Value * pValue,CFXJSE_Class * pClass)112 CXFA_Object* CXFA_ScriptContext::ToObject(CFXJSE_Value* pValue,
113                                           CFXJSE_Class* pClass) {
114   return static_cast<CXFA_Object*>(pValue->ToHostObject(pClass));
115 }
116 
CXFA_ScriptContext(CXFA_Document * pDocument)117 CXFA_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 
~CXFA_ScriptContext()127 CXFA_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 
Initialize(v8::Isolate * pIsolate)137 void CXFA_ScriptContext::Initialize(v8::Isolate* pIsolate) {
138   m_pIsolate = pIsolate;
139   DefineJsContext();
140   DefineJsClass();
141   m_ResolveProcessor = pdfium::MakeUnique<CXFA_ResolveProcessor>();
142 }
143 
RunScript(XFA_SCRIPTLANGTYPE eScriptType,const CFX_WideStringC & wsScript,CFXJSE_Value * hRetValue,CXFA_Object * pThisObject)144 bool 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 }
GlobalPropertySetter(CFXJSE_Value * pObject,const CFX_ByteStringC & szPropName,CFXJSE_Value * pValue)176 void 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 }
QueryNodeByFlag(CXFA_Node * refNode,const CFX_WideStringC & propname,CFXJSE_Value * pValue,uint32_t dwFlag,bool bSetting)207 bool 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 }
GlobalPropertyGetter(CFXJSE_Value * pObject,const CFX_ByteStringC & szPropName,CFXJSE_Value * pValue)230 void 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 }
NormalPropertyGetter(CFXJSE_Value * pOriginalValue,const CFX_ByteStringC & szPropName,CFXJSE_Value * pReturnValue)283 void 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 }
NormalPropertySetter(CFXJSE_Value * pOriginalValue,const CFX_ByteStringC & szPropName,CFXJSE_Value * pReturnValue)328 void 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 }
NormalPropTypeGetter(CFXJSE_Value * pOriginalValue,const CFX_ByteStringC & szPropName,bool bQueryIn)377 int32_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 }
GlobalPropTypeGetter(CFXJSE_Value * pOriginalValue,const CFX_ByteStringC & szPropName,bool bQueryIn)399 int32_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 }
NormalMethodCall(CFXJSE_Value * pThis,const CFX_ByteStringC & szFuncName,CFXJSE_Arguments & args)417 void 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 }
IsStrictScopeInJavaScript()435 bool CXFA_ScriptContext::IsStrictScopeInJavaScript() {
436   return m_pDocument->HasFlag(XFA_DOCFLAG_StrictScoping);
437 }
GetType()438 XFA_SCRIPTLANGTYPE CXFA_ScriptContext::GetType() {
439   return m_eScriptType;
440 }
DefineJsContext()441 void 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 }
CreateVariablesContext(CXFA_Node * pScriptNode,CXFA_Node * pSubform)447 CFXJSE_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 }
GetVariablesThis(CXFA_Object * pObject,bool bScriptNode)461 CXFA_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 
RunVariablesScript(CXFA_Node * pScriptNode)470 bool 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 
QueryVariableValue(CXFA_Node * pScriptNode,const CFX_ByteStringC & szPropName,CFXJSE_Value * pValue,bool bGetter)506 bool 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 
DefineJsClass()543 void CXFA_ScriptContext::DefineJsClass() {
544   m_pJsClass = CFXJSE_Class::Create(m_JsContext.get(), &NormalClassDescriptor);
545 }
546 
RemoveBuiltInObjs(CFXJSE_Context * pContext) const547 void 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 }
GetJseNormalClass()556 CFXJSE_Class* CXFA_ScriptContext::GetJseNormalClass() {
557   return m_pJsClass;
558 }
ResolveObjects(CXFA_Object * refNode,const CFX_WideStringC & wsExpression,XFA_RESOLVENODE_RS & resolveNodeRS,uint32_t dwStyles,CXFA_Node * bindNode)559 int32_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 
AddToCacheList(std::unique_ptr<CXFA_NodeList> pList)719 void CXFA_ScriptContext::AddToCacheList(std::unique_ptr<CXFA_NodeList> pList) {
720   m_CacheList.push_back(std::move(pList));
721 }
722 
GetJSValueFromMap(CXFA_Object * pObject)723 CFXJSE_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 }
GetIndexByName(CXFA_Node * refNode)739 int32_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 }
GetIndexByClassName(CXFA_Node * refNode)744 int32_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 }
GetSomExpression(CXFA_Node * refNode,CFX_WideString & wsExpression)749 void 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 }
SetNodesOfRunScript(CXFA_NodeArray * pArray)755 void CXFA_ScriptContext::SetNodesOfRunScript(CXFA_NodeArray* pArray) {
756   m_pScriptNodeArray = pArray;
757 }
AddNodesOfRunScript(const CXFA_NodeArray & nodes)758 void CXFA_ScriptContext::AddNodesOfRunScript(const CXFA_NodeArray& nodes) {
759   if (!m_pScriptNodeArray)
760     return;
761   if (nodes.GetSize() > 0)
762     m_pScriptNodeArray->Copy(nodes);
763 }
AddNodesOfRunScript(CXFA_Node * pNode)764 void 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