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