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