// Copyright 2014 PDFium Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
#include "xfa/src/foxitlib.h" | |
#include "xfa/src/fxfa/src/common/xfa_utils.h" | |
#include "xfa/src/fxfa/src/common/xfa_object.h" | |
#include "xfa/src/fxfa/src/common/xfa_document.h" | |
#include "xfa/src/fxfa/src/common/xfa_parser.h" | |
#include "xfa/src/fxfa/src/common/xfa_script.h" | |
#include "xfa/src/fxfa/src/common/xfa_docdata.h" | |
#include "xfa/src/fxfa/src/common/xfa_doclayout.h" | |
#include "xfa/src/fxfa/src/common/xfa_localemgr.h" | |
#include "xfa/src/fxfa/src/common/xfa_fm2jsapi.h" | |
#include "xfa_script_imp.h" | |
#include "xfa_script_resolveprocessor.h" | |
#include "xfa_script_nodehelper.h" | |
CXFA_ScriptContext::CXFA_ScriptContext(CXFA_Document* pDocument) | |
: m_pDocument(pDocument), | |
m_hJsContext(nullptr), | |
m_hJsRuntime(nullptr), | |
m_hJsClass(nullptr), | |
m_eScriptType(XFA_SCRIPTLANGTYPE_Unkown), | |
m_pEventParam(nullptr), | |
m_pScriptNodeArray(nullptr), | |
m_pResolveProcessor(nullptr), | |
m_hFM2JSContext(nullptr), | |
m_pThisObject(nullptr), | |
m_dwBuiltInInFlags(0), | |
m_eRunAtType(XFA_ATTRIBUTEENUM_Client) { | |
FX_memset(&m_JsGlobalClass, 0, sizeof(FXJSE_CLASS)); | |
FX_memset(&m_JsNormalClass, 0, sizeof(FXJSE_CLASS)); | |
} | |
CXFA_ScriptContext::~CXFA_ScriptContext() { | |
FX_POSITION ps = m_mapXFAToHValue.GetStartPosition(); | |
while (ps) { | |
CXFA_Object* pXFAObj; | |
FXJSE_HVALUE pValue; | |
m_mapXFAToHValue.GetNextAssoc(ps, pXFAObj, pValue); | |
FXJSE_Value_Release(pValue); | |
} | |
m_mapXFAToHValue.RemoveAll(); | |
ReleaseVariablesMap(); | |
if (m_hFM2JSContext) { | |
XFA_FM2JS_ContextRelease(m_hFM2JSContext); | |
m_hFM2JSContext = NULL; | |
} | |
if (m_hJsContext) { | |
FXJSE_Context_Release(m_hJsContext); | |
m_hJsContext = NULL; | |
} | |
if (m_pResolveProcessor) { | |
delete m_pResolveProcessor; | |
m_pResolveProcessor = NULL; | |
} | |
m_upObjectArray.RemoveAll(); | |
for (int32_t i = 0; i < m_CacheListArray.GetSize(); i++) { | |
delete ((CXFA_NodeList*)m_CacheListArray[i]); | |
} | |
m_CacheListArray.RemoveAll(); | |
} | |
void CXFA_ScriptContext::Initialize(FXJSE_HRUNTIME hRuntime) { | |
m_hJsRuntime = hRuntime; | |
DefineJsContext(); | |
DefineJsClass(); | |
m_pResolveProcessor = new CXFA_ResolveProcessor; | |
} | |
void CXFA_ScriptContext::Release() { | |
delete this; | |
} | |
FX_BOOL CXFA_ScriptContext::RunScript(XFA_SCRIPTLANGTYPE eScriptType, | |
const CFX_WideStringC& wsScript, | |
FXJSE_HVALUE hRetValue, | |
CXFA_Object* pThisObject) { | |
CFX_ByteString btScript; | |
XFA_SCRIPTLANGTYPE eSaveType = m_eScriptType; | |
m_eScriptType = eScriptType; | |
if (eScriptType == XFA_SCRIPTLANGTYPE_Formcalc) { | |
if (!m_hFM2JSContext) { | |
m_hFM2JSContext = XFA_FM2JS_ContextCreate(); | |
XFA_FM2JS_ContextInitialize(m_hFM2JSContext, m_hJsRuntime, m_hJsContext, | |
m_pDocument); | |
} | |
CFX_WideTextBuf wsJavaScript; | |
CFX_WideString wsErrorInfo; | |
int32_t iFlags = XFA_FM2JS_Translate(wsScript, wsJavaScript, wsErrorInfo); | |
if (iFlags) { | |
FXJSE_Value_SetUndefined(hRetValue); | |
return FALSE; | |
} | |
btScript = | |
FX_UTF8Encode(wsJavaScript.GetBuffer(), wsJavaScript.GetLength()); | |
} else { | |
btScript = FX_UTF8Encode(wsScript.GetPtr(), wsScript.GetLength()); | |
} | |
CXFA_Object* pOriginalObject = m_pThisObject; | |
m_pThisObject = pThisObject; | |
FXJSE_HVALUE pValue = pThisObject ? GetJSValueFromMap(pThisObject) : NULL; | |
FX_BOOL bRet = FXJSE_ExecuteScript(m_hJsContext, btScript, hRetValue, pValue); | |
m_pThisObject = pOriginalObject; | |
m_eScriptType = eSaveType; | |
return bRet; | |
} | |
void CXFA_ScriptContext::GlobalPropertySetter(FXJSE_HOBJECT hObject, | |
const CFX_ByteStringC& szPropName, | |
FXJSE_HVALUE hValue) { | |
CXFA_Object* lpOrginalNode = | |
(CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
CXFA_Document* pDoc = lpOrginalNode->GetDocument(); | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pDoc->GetScriptContext(); | |
CXFA_Object* lpCurNode = lpScriptContext->GetVariablesThis(lpOrginalNode); | |
CFX_WideString wsPropName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength()); | |
FX_DWORD dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings | | |
XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | | |
XFA_RESOLVENODE_Attributes; | |
CXFA_Node* pRefNode = (CXFA_Node*)lpScriptContext->GetThisObject(); | |
if (lpOrginalNode->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) { | |
pRefNode = (CXFA_Node*)lpCurNode; | |
} | |
if (lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag, | |
TRUE)) { | |
return; | |
} | |
if (lpOrginalNode->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) { | |
if (FXJSE_Value_IsUndefined(hValue)) { | |
FXJSE_Value_SetObjectOwnProp(hObject, szPropName, hValue); | |
return; | |
} | |
} | |
IXFA_Notify* pNotify = pDoc->GetNotify(); | |
if (!pNotify) { | |
return; | |
} | |
pNotify->GetDocProvider()->SetGlobalProperty(pNotify->GetHDOC(), szPropName, | |
hValue); | |
} | |
FX_BOOL CXFA_ScriptContext::QueryNodeByFlag(CXFA_Node* refNode, | |
const CFX_WideStringC& propname, | |
FXJSE_HVALUE hValue, | |
FX_DWORD dwFlag, | |
FX_BOOL bSetting) { | |
XFA_RESOLVENODE_RS resolveRs; | |
int32_t iRet = ResolveObjects(refNode, propname, resolveRs, dwFlag); | |
FX_BOOL bResult = FALSE; | |
if (iRet > 0) { | |
bResult = TRUE; | |
if (resolveRs.dwFlags == XFA_RESOVENODE_RSTYPE_Nodes) { | |
FXJSE_HVALUE pValue = GetJSValueFromMap(resolveRs.nodes[0]); | |
FXJSE_Value_Set(hValue, pValue); | |
} else if (resolveRs.dwFlags == XFA_RESOVENODE_RSTYPE_Attribute) { | |
XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = resolveRs.pScriptAttribute; | |
if (lpAttributeInfo) { | |
(resolveRs.nodes[0]->*(lpAttributeInfo->lpfnCallback))( | |
hValue, bSetting, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute); | |
} | |
} | |
} | |
return bResult; | |
} | |
void CXFA_ScriptContext::GlobalPropertyGetter(FXJSE_HOBJECT hObject, | |
const CFX_ByteStringC& szPropName, | |
FXJSE_HVALUE hValue) { | |
CXFA_Object* pOrginalObject = | |
(CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
CXFA_Document* pDoc = pOrginalObject->GetDocument(); | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pDoc->GetScriptContext(); | |
CXFA_Object* lpCurNode = lpScriptContext->GetVariablesThis(pOrginalObject); | |
CFX_WideString wsPropName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength()); | |
if (lpScriptContext->GetType() == XFA_SCRIPTLANGTYPE_Formcalc) { | |
if (szPropName == FOXIT_XFA_FM2JS_FORMCALC_RUNTIME) { | |
XFA_FM2JS_GlobalPropertyGetter(lpScriptContext->m_hFM2JSContext, hValue); | |
return; | |
} | |
uint32_t uHashCode = | |
FX_HashCode_String_GetW(wsPropName, wsPropName.GetLength()); | |
if (uHashCode != XFA_HASHCODE_Layout) { | |
CXFA_Object* pObject = | |
lpScriptContext->GetDocument()->GetXFANode(uHashCode); | |
if (pObject) { | |
FXJSE_Value_Set(hValue, lpScriptContext->GetJSValueFromMap(pObject)); | |
return; | |
} | |
} | |
} | |
FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | | |
XFA_RESOLVENODE_Attributes; | |
CXFA_Node* pRefNode = (CXFA_Node*)lpScriptContext->GetThisObject(); | |
if (pOrginalObject->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) { | |
pRefNode = (CXFA_Node*)lpCurNode; | |
} | |
if (lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag, | |
FALSE)) { | |
return; | |
} | |
dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings; | |
if (lpScriptContext->QueryNodeByFlag(pRefNode, wsPropName, hValue, dwFlag, | |
FALSE)) { | |
return; | |
} | |
CXFA_Object* pScriptObject = | |
lpScriptContext->GetVariablesThis(pOrginalObject, TRUE); | |
if (pScriptObject && | |
lpScriptContext->QueryVariableHValue((CXFA_Node*)pScriptObject, | |
szPropName, hValue, TRUE)) { | |
return; | |
} | |
IXFA_Notify* pNotify = pDoc->GetNotify(); | |
if (!pNotify) { | |
return; | |
} | |
pNotify->GetDocProvider()->GetGlobalProperty(pNotify->GetHDOC(), szPropName, | |
hValue); | |
} | |
void CXFA_ScriptContext::NormalPropertyGetter(FXJSE_HOBJECT hObject, | |
const CFX_ByteStringC& szPropName, | |
FXJSE_HVALUE hValue) { | |
CXFA_Object* pOrginalObject = | |
(CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
if (pOrginalObject == NULL) { | |
FXJSE_Value_SetUndefined(hValue); | |
return; | |
} | |
CFX_WideString wsPropName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength()); | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pOrginalObject->GetDocument()->GetScriptContext(); | |
CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOrginalObject); | |
if (wsPropName == FX_WSTRC(L"xfa")) { | |
FXJSE_HVALUE pValue = lpScriptContext->GetJSValueFromMap( | |
lpScriptContext->GetDocument()->GetRoot()); | |
FXJSE_Value_Set(hValue, pValue); | |
return; | |
} | |
FX_DWORD dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | | |
XFA_RESOLVENODE_Attributes; | |
FX_BOOL bRet = lpScriptContext->QueryNodeByFlag( | |
(CXFA_Node*)pObject, wsPropName, hValue, dwFlag, FALSE); | |
if (bRet) { | |
return; | |
} | |
if (pObject == lpScriptContext->GetThisObject() || | |
(lpScriptContext->GetType() == XFA_SCRIPTLANGTYPE_Javascript && | |
!lpScriptContext->IsStrictScopeInJavaScript())) { | |
dwFlag = XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings; | |
bRet = lpScriptContext->QueryNodeByFlag((CXFA_Node*)pObject, wsPropName, | |
hValue, dwFlag, FALSE); | |
} | |
if (bRet) { | |
return; | |
} | |
CXFA_Object* pScriptObject = | |
lpScriptContext->GetVariablesThis(pOrginalObject, TRUE); | |
if (pScriptObject) { | |
bRet = lpScriptContext->QueryVariableHValue((CXFA_Node*)pScriptObject, | |
szPropName, hValue, TRUE); | |
} | |
if (!bRet) { | |
FXJSE_Value_SetUndefined(hValue); | |
} | |
} | |
void CXFA_ScriptContext::NormalPropertySetter(FXJSE_HOBJECT hObject, | |
const CFX_ByteStringC& szPropName, | |
FXJSE_HVALUE hValue) { | |
CXFA_Object* pOrginalObject = | |
(CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
if (pOrginalObject == NULL) { | |
return; | |
} | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pOrginalObject->GetDocument()->GetScriptContext(); | |
CXFA_Object* pObject = lpScriptContext->GetVariablesThis(pOrginalObject); | |
CFX_WideString wsPropName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength()); | |
XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = | |
XFA_GetScriptAttributeByName(pObject->GetClassID(), wsPropName); | |
if (lpAttributeInfo) { | |
(pObject->*(lpAttributeInfo->lpfnCallback))( | |
hValue, TRUE, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute); | |
} else { | |
if (pObject->IsNode()) { | |
if (wsPropName.GetAt(0) == '#') { | |
wsPropName = wsPropName.Right(wsPropName.GetLength() - 1); | |
} | |
CXFA_Node* pNode = (CXFA_Node*)pObject; | |
CXFA_Node* pPropOrChild = NULL; | |
XFA_LPCELEMENTINFO lpElementInfo = XFA_GetElementByName(wsPropName); | |
if (lpElementInfo) { | |
pPropOrChild = pNode->GetProperty(0, lpElementInfo->eName); | |
} else { | |
pPropOrChild = pNode->GetFirstChildByName(wsPropName); | |
} | |
if (pPropOrChild) { | |
CFX_WideString wsDefaultName = FX_WSTRC(L"{default}"); | |
XFA_LPCSCRIPTATTRIBUTEINFO lpAttributeInfo = | |
XFA_GetScriptAttributeByName(pPropOrChild->GetClassID(), | |
wsDefaultName); | |
if (lpAttributeInfo) { | |
(pPropOrChild->*(lpAttributeInfo->lpfnCallback))( | |
hValue, TRUE, (XFA_ATTRIBUTE)lpAttributeInfo->eAttribute); | |
return; | |
} | |
} | |
} | |
CXFA_Object* pScriptObject = | |
lpScriptContext->GetVariablesThis(pOrginalObject, TRUE); | |
if (pScriptObject) { | |
lpScriptContext->QueryVariableHValue((CXFA_Node*)pScriptObject, | |
szPropName, hValue, FALSE); | |
} | |
} | |
} | |
int32_t CXFA_ScriptContext::NormalPropTypeGetter( | |
FXJSE_HOBJECT hObject, | |
const CFX_ByteStringC& szPropName, | |
FX_BOOL bQueryIn) { | |
CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
if (pObject == NULL) { | |
return FXJSE_ClassPropType_None; | |
} | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext(); | |
pObject = lpScriptContext->GetVariablesThis(pObject); | |
XFA_ELEMENT objElement = pObject->GetClassID(); | |
CFX_WideString wsPropName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength()); | |
if (XFA_GetMethodByName(objElement, wsPropName)) { | |
return FXJSE_ClassPropType_Method; | |
} | |
if (bQueryIn && !XFA_GetScriptAttributeByName(objElement, wsPropName)) { | |
return FXJSE_ClassPropType_None; | |
} | |
return FXJSE_ClassPropType_Property; | |
} | |
int32_t CXFA_ScriptContext::GlobalPropTypeGetter( | |
FXJSE_HOBJECT hObject, | |
const CFX_ByteStringC& szPropName, | |
FX_BOOL bQueryIn) { | |
CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
if (pObject == NULL) { | |
return FXJSE_ClassPropType_None; | |
} | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext(); | |
pObject = lpScriptContext->GetVariablesThis(pObject); | |
XFA_ELEMENT objElement = pObject->GetClassID(); | |
CFX_WideString wsPropName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szPropName.GetPtr(), szPropName.GetLength()); | |
if (XFA_GetMethodByName(objElement, wsPropName)) { | |
return FXJSE_ClassPropType_Method; | |
} | |
return FXJSE_ClassPropType_Property; | |
} | |
void CXFA_ScriptContext::NormalMethodCall(FXJSE_HOBJECT hThis, | |
const CFX_ByteStringC& szFuncName, | |
CFXJSE_Arguments& args) { | |
CXFA_Object* pObject = (CXFA_Object*)FXJSE_Value_ToObject(hThis, NULL); | |
if (pObject == NULL) { | |
return; | |
} | |
CXFA_ScriptContext* lpScriptContext = | |
(CXFA_ScriptContext*)pObject->GetDocument()->GetScriptContext(); | |
pObject = lpScriptContext->GetVariablesThis(pObject); | |
CFX_WideString wsFunName = CFX_WideString::FromUTF8( | |
(const FX_CHAR*)szFuncName.GetPtr(), szFuncName.GetLength()); | |
XFA_LPCMETHODINFO lpMethodInfo = | |
XFA_GetMethodByName(pObject->GetClassID(), wsFunName); | |
if (NULL == lpMethodInfo) { | |
return; | |
} | |
(pObject->*(lpMethodInfo->lpfnCallback))(&args); | |
} | |
FX_BOOL CXFA_ScriptContext::IsStrictScopeInJavaScript() { | |
return m_pDocument->HasFlag(XFA_DOCFLAG_StrictScoping); | |
} | |
XFA_SCRIPTLANGTYPE CXFA_ScriptContext::GetType() { | |
return m_eScriptType; | |
} | |
void CXFA_ScriptContext::DefineJsContext() { | |
m_JsGlobalClass.constructor = NULL; | |
m_JsGlobalClass.name = "Root"; | |
m_JsGlobalClass.propNum = 0; | |
m_JsGlobalClass.properties = NULL; | |
m_JsGlobalClass.methNum = 0; | |
m_JsGlobalClass.methods = NULL; | |
m_JsGlobalClass.dynPropGetter = CXFA_ScriptContext::GlobalPropertyGetter; | |
m_JsGlobalClass.dynPropSetter = CXFA_ScriptContext::GlobalPropertySetter; | |
m_JsGlobalClass.dynPropTypeGetter = CXFA_ScriptContext::GlobalPropTypeGetter; | |
m_JsGlobalClass.dynPropDeleter = NULL; | |
m_JsGlobalClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall; | |
m_hJsContext = FXJSE_Context_Create(m_hJsRuntime, &m_JsGlobalClass, | |
m_pDocument->GetRoot()); | |
RemoveBuiltInObjs(m_hJsContext); | |
FXJSE_Context_EnableCompatibleMode( | |
m_hJsContext, FXJSE_COMPATIBLEMODEFLAG_CONSTRUCTOREXTRAMETHODS); | |
} | |
FXJSE_HCONTEXT CXFA_ScriptContext::CreateVariablesContext( | |
CXFA_Node* pScriptNode, | |
CXFA_Node* pSubform) { | |
if (pScriptNode == NULL || pSubform == NULL) { | |
return NULL; | |
} | |
if (m_mapVariableToHValue.GetCount() == 0) { | |
m_JsGlobalVariablesClass.constructor = NULL; | |
m_JsGlobalVariablesClass.name = "XFAScriptObject"; | |
m_JsGlobalVariablesClass.propNum = 0; | |
m_JsGlobalVariablesClass.properties = NULL; | |
m_JsGlobalVariablesClass.methNum = 0; | |
m_JsGlobalVariablesClass.methods = NULL; | |
m_JsGlobalVariablesClass.dynPropGetter = | |
CXFA_ScriptContext::GlobalPropertyGetter; | |
m_JsGlobalVariablesClass.dynPropSetter = | |
CXFA_ScriptContext::GlobalPropertySetter; | |
m_JsGlobalVariablesClass.dynPropTypeGetter = | |
CXFA_ScriptContext::NormalPropTypeGetter; | |
m_JsGlobalVariablesClass.dynPropDeleter = NULL; | |
m_JsGlobalVariablesClass.dynMethodCall = | |
CXFA_ScriptContext::NormalMethodCall; | |
} | |
CXFA_ThisProxy* lpVariableNode = new CXFA_ThisProxy(pSubform, pScriptNode); | |
FXJSE_HCONTEXT hVariablesContext = FXJSE_Context_Create( | |
m_hJsRuntime, &m_JsGlobalVariablesClass, (CXFA_Object*)lpVariableNode); | |
RemoveBuiltInObjs(hVariablesContext); | |
FXJSE_Context_EnableCompatibleMode( | |
hVariablesContext, FXJSE_COMPATIBLEMODEFLAG_CONSTRUCTOREXTRAMETHODS); | |
m_mapVariableToHValue.SetAt(pScriptNode, hVariablesContext); | |
return hVariablesContext; | |
} | |
CXFA_Object* CXFA_ScriptContext::GetVariablesThis(CXFA_Object* pObject, | |
FX_BOOL bScriptNode) { | |
if (pObject->GetObjectType() == XFA_OBJECTTYPE_VariablesThis) { | |
return bScriptNode ? ((CXFA_ThisProxy*)pObject)->GetScriptNode() | |
: ((CXFA_ThisProxy*)pObject)->GetThisNode(); | |
} | |
return pObject; | |
} | |
FX_BOOL CXFA_ScriptContext::RunVariablesScript(CXFA_Node* pScriptNode) { | |
if (pScriptNode == NULL) { | |
return FALSE; | |
} | |
if (pScriptNode->GetClassID() == XFA_ELEMENT_Script) { | |
CXFA_Node* pParent = pScriptNode->GetNodeItem(XFA_NODEITEM_Parent); | |
if (!pParent || pParent->GetClassID() != XFA_ELEMENT_Variables) { | |
return FALSE; | |
} | |
if (m_mapVariableToHValue.GetValueAt(pScriptNode)) { | |
return TRUE; | |
} | |
CXFA_Node* pTextNode = pScriptNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
if (!pTextNode) { | |
return FALSE; | |
} | |
CFX_WideStringC wsScript; | |
if (!pTextNode->TryCData(XFA_ATTRIBUTE_Value, wsScript)) { | |
return FALSE; | |
} | |
CFX_ByteString btScript = | |
FX_UTF8Encode(wsScript.GetPtr(), wsScript.GetLength()); | |
FXJSE_HVALUE hRetValue = FXJSE_Value_Create(m_hJsRuntime); | |
CXFA_Node* pThisObject = pParent->GetNodeItem(XFA_NODEITEM_Parent); | |
FXJSE_HCONTEXT hVariablesContext = | |
CreateVariablesContext(pScriptNode, pThisObject); | |
CXFA_Object* pOriginalObject = m_pThisObject; | |
m_pThisObject = pThisObject; | |
FX_BOOL bRet = FXJSE_ExecuteScript(hVariablesContext, btScript, hRetValue); | |
m_pThisObject = pOriginalObject; | |
FXJSE_Value_Release(hRetValue); | |
return bRet; | |
} | |
return TRUE; | |
} | |
FX_BOOL CXFA_ScriptContext::QueryVariableHValue( | |
CXFA_Node* pScriptNode, | |
const CFX_ByteStringC& szPropName, | |
FXJSE_HVALUE hValue, | |
FX_BOOL bGetter) { | |
if (pScriptNode->GetClassID() != XFA_ELEMENT_Script) { | |
return FALSE; | |
} | |
CXFA_Node* variablesNode = pScriptNode->GetNodeItem(XFA_NODEITEM_Parent); | |
if (!variablesNode || variablesNode->GetClassID() != XFA_ELEMENT_Variables) { | |
return FALSE; | |
} | |
FX_BOOL bRes = FALSE; | |
void* lpVariables = m_mapVariableToHValue.GetValueAt(pScriptNode); | |
if (lpVariables) { | |
FXJSE_HCONTEXT hVariableContext = (FXJSE_HCONTEXT)lpVariables; | |
FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(hVariableContext); | |
FXJSE_HVALUE hVariableValue = FXJSE_Value_Create(m_hJsRuntime); | |
if (!bGetter) { | |
FXJSE_Value_SetObjectOwnProp(hObject, szPropName, hValue); | |
bRes = TRUE; | |
} else if (FXJSE_Value_ObjectHasOwnProp(hObject, szPropName, FALSE)) { | |
FXJSE_Value_GetObjectProp(hObject, szPropName, hVariableValue); | |
if (FXJSE_Value_IsFunction(hVariableValue)) { | |
FXJSE_Value_SetFunctionBind(hValue, hVariableValue, hObject); | |
} else if (bGetter) { | |
FXJSE_Value_Set(hValue, hVariableValue); | |
} else { | |
FXJSE_Value_Set(hVariableValue, hValue); | |
} | |
bRes = TRUE; | |
} | |
FXJSE_Value_Release(hVariableValue); | |
FXJSE_Value_Release(hObject); | |
} | |
return bRes; | |
} | |
void CXFA_ScriptContext::ReleaseVariablesMap() { | |
FX_POSITION ps = m_mapVariableToHValue.GetStartPosition(); | |
while (ps) { | |
CXFA_Object* pScriptNode; | |
FXJSE_HCONTEXT hVariableContext; | |
m_mapVariableToHValue.GetNextAssoc(ps, pScriptNode, hVariableContext); | |
FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(hVariableContext); | |
CXFA_Object* lpCurNode = (CXFA_Object*)FXJSE_Value_ToObject(hObject, NULL); | |
if (lpCurNode) { | |
delete (CXFA_ThisProxy*)lpCurNode; | |
lpCurNode = NULL; | |
} | |
FXJSE_Value_Release(hObject); | |
FXJSE_Context_Release(hVariableContext); | |
hVariableContext = NULL; | |
} | |
m_mapVariableToHValue.RemoveAll(); | |
} | |
void CXFA_ScriptContext::DefineJsClass() { | |
m_JsNormalClass.constructor = NULL; | |
m_JsNormalClass.name = "XFAObject"; | |
m_JsNormalClass.propNum = 0; | |
m_JsNormalClass.properties = NULL; | |
m_JsNormalClass.methNum = 0; | |
m_JsNormalClass.methods = NULL; | |
m_JsNormalClass.dynPropGetter = CXFA_ScriptContext::NormalPropertyGetter; | |
m_JsNormalClass.dynPropSetter = CXFA_ScriptContext::NormalPropertySetter; | |
m_JsNormalClass.dynPropTypeGetter = CXFA_ScriptContext::NormalPropTypeGetter; | |
m_JsNormalClass.dynPropDeleter = NULL; | |
m_JsNormalClass.dynMethodCall = CXFA_ScriptContext::NormalMethodCall; | |
m_hJsClass = FXJSE_DefineClass(m_hJsContext, &m_JsNormalClass); | |
} | |
void CXFA_ScriptContext::RemoveBuiltInObjs(FXJSE_HCONTEXT jsContext) const { | |
static const CFX_ByteStringC OBJ_NAME[2] = {"Number", "Date"}; | |
FXJSE_HVALUE hObject = FXJSE_Context_GetGlobalObject(jsContext); | |
FXJSE_HVALUE hProp = FXJSE_Value_Create(m_hJsRuntime); | |
for (int i = 0; i < 2; ++i) { | |
if (FXJSE_Value_GetObjectProp(hObject, OBJ_NAME[i], hProp)) | |
FXJSE_Value_DeleteObjectProp(hObject, OBJ_NAME[i]); | |
} | |
FXJSE_Value_Release(hProp); | |
FXJSE_Value_Release(hObject); | |
} | |
FXJSE_HCLASS CXFA_ScriptContext::GetJseNormalClass() { | |
return m_hJsClass; | |
} | |
int32_t CXFA_ScriptContext::ResolveObjects(CXFA_Object* refNode, | |
const CFX_WideStringC& wsExpression, | |
XFA_RESOLVENODE_RS& resolveNodeRS, | |
FX_DWORD dwStyles, | |
CXFA_Node* bindNode) { | |
if (wsExpression.IsEmpty()) { | |
return 0; | |
} | |
if (m_eScriptType != XFA_SCRIPTLANGTYPE_Formcalc || | |
(dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings))) { | |
m_upObjectArray.RemoveAll(); | |
} | |
if (refNode && | |
(dwStyles & (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings)) && | |
refNode->IsNode()) { | |
m_upObjectArray.Add((CXFA_Node*)refNode); | |
} | |
FX_BOOL bNextCreate = FALSE; | |
if (dwStyles & XFA_RESOLVENODE_CreateNode) { | |
m_pResolveProcessor->GetNodeHelper()->XFA_SetCreateNodeType(bindNode); | |
} | |
m_pResolveProcessor->GetNodeHelper()->m_pCreateParent = NULL; | |
m_pResolveProcessor->GetNodeHelper()->m_iCurAllStart = -1; | |
CXFA_ResolveNodesData rndFind; | |
int32_t nStart = 0; | |
int32_t nLevel = 0; | |
int32_t nRet = -1; | |
rndFind.m_pSC = this; | |
CXFA_ObjArray findNodes; | |
if (refNode != NULL) { | |
findNodes.Add(refNode); | |
} else { | |
findNodes.Add(m_pDocument->GetRoot()); | |
} | |
int32_t nNodes = 0; | |
while (TRUE) { | |
nNodes = findNodes.GetSize(); | |
int32_t i = 0; | |
rndFind.m_dwStyles = dwStyles; | |
m_pResolveProcessor->m_iCurStart = nStart; | |
nStart = m_pResolveProcessor->XFA_ResolveNodes_GetFilter(wsExpression, | |
nStart, rndFind); | |
if (nStart < 1) { | |
if ((dwStyles & XFA_RESOLVENODE_CreateNode) && !bNextCreate) { | |
CXFA_Node* pDataNode = NULL; | |
nStart = m_pResolveProcessor->GetNodeHelper()->m_iCurAllStart; | |
if (nStart != -1) { | |
pDataNode = m_pDocument->GetNotBindNode(findNodes); | |
if (pDataNode) { | |
findNodes.RemoveAll(); | |
findNodes.Add(pDataNode); | |
break; | |
} | |
} else { | |
pDataNode = (CXFA_Node*)findNodes[0]; | |
findNodes.RemoveAll(); | |
findNodes.Add(pDataNode); | |
break; | |
} | |
dwStyles |= XFA_RESOLVENODE_Bind; | |
findNodes.RemoveAll(); | |
findNodes.Add(m_pResolveProcessor->GetNodeHelper()->m_pAllStartParent); | |
continue; | |
} else { | |
break; | |
} | |
} | |
if (bNextCreate) { | |
FX_BOOL bCreate = | |
m_pResolveProcessor->GetNodeHelper()->XFA_ResolveNodes_CreateNode( | |
rndFind.m_wsName, rndFind.m_wsCondition, | |
nStart == wsExpression.GetLength(), this); | |
if (bCreate) { | |
continue; | |
} else { | |
break; | |
} | |
} | |
CXFA_ObjArray retNodes; | |
while (i < nNodes) { | |
FX_BOOL bDataBind = FALSE; | |
if (((dwStyles & XFA_RESOLVENODE_Bind) || | |
(dwStyles & XFA_RESOLVENODE_CreateNode)) && | |
nNodes > 1) { | |
CXFA_ResolveNodesData rndBind; | |
m_pResolveProcessor->XFA_ResolveNodes_GetFilter(wsExpression, nStart, | |
rndBind); | |
m_pResolveProcessor->XFA_ResolveNode_SetIndexDataBind( | |
rndBind.m_wsCondition, i, nNodes); | |
bDataBind = TRUE; | |
} | |
rndFind.m_CurNode = findNodes[i++]; | |
rndFind.m_nLevel = nLevel; | |
rndFind.m_dwFlag = XFA_RESOVENODE_RSTYPE_Nodes; | |
nRet = m_pResolveProcessor->XFA_ResolveNodes(rndFind); | |
if (nRet < 1) { | |
continue; | |
} | |
if (rndFind.m_dwFlag == XFA_RESOVENODE_RSTYPE_Attribute && | |
rndFind.m_pScriptAttribute && nStart < wsExpression.GetLength()) { | |
FXJSE_HVALUE hValue = FXJSE_Value_Create(m_hJsRuntime); | |
(rndFind.m_Nodes[0]->*(rndFind.m_pScriptAttribute->lpfnCallback))( | |
hValue, FALSE, | |
(XFA_ATTRIBUTE)rndFind.m_pScriptAttribute->eAttribute); | |
rndFind.m_Nodes.SetAt(0, | |
(CXFA_Object*)FXJSE_Value_ToObject(hValue, NULL)); | |
FXJSE_Value_Release(hValue); | |
} | |
int32_t iSize = m_upObjectArray.GetSize(); | |
if (iSize) { | |
m_upObjectArray.RemoveAt(iSize - 1); | |
} | |
retNodes.Append(rndFind.m_Nodes); | |
rndFind.m_Nodes.RemoveAll(); | |
if (bDataBind) { | |
break; | |
} | |
} | |
findNodes.RemoveAll(); | |
nNodes = retNodes.GetSize(); | |
if (nNodes < 1) { | |
if (dwStyles & XFA_RESOLVENODE_CreateNode) { | |
bNextCreate = TRUE; | |
if (m_pResolveProcessor->GetNodeHelper()->m_pCreateParent == NULL) { | |
m_pResolveProcessor->GetNodeHelper()->m_pCreateParent = | |
(CXFA_Node*)rndFind.m_CurNode; | |
m_pResolveProcessor->GetNodeHelper()->m_iCreateCount = 1; | |
} | |
FX_BOOL bCreate = | |
m_pResolveProcessor->GetNodeHelper()->XFA_ResolveNodes_CreateNode( | |
rndFind.m_wsName, rndFind.m_wsCondition, | |
nStart == wsExpression.GetLength(), this); | |
if (bCreate) { | |
continue; | |
} else { | |
break; | |
} | |
} else { | |
break; | |
} | |
} | |
findNodes.Copy(retNodes); | |
rndFind.m_Nodes.RemoveAll(); | |
if (nLevel == 0) { | |
dwStyles &= ~(XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings); | |
} | |
nLevel++; | |
} | |
if (!bNextCreate) { | |
resolveNodeRS.dwFlags = rndFind.m_dwFlag; | |
if (nNodes > 0) { | |
resolveNodeRS.nodes.Append(findNodes); | |
} | |
if (rndFind.m_dwFlag == XFA_RESOVENODE_RSTYPE_Attribute) { | |
resolveNodeRS.pScriptAttribute = rndFind.m_pScriptAttribute; | |
return 1; | |
} | |
} | |
if (dwStyles & (XFA_RESOLVENODE_CreateNode | XFA_RESOLVENODE_Bind | | |
XFA_RESOLVENODE_BindNew)) { | |
m_pResolveProcessor->XFA_ResolveNode_SetResultCreateNode( | |
resolveNodeRS, rndFind.m_wsCondition); | |
if (!bNextCreate && (dwStyles & XFA_RESOLVENODE_CreateNode)) { | |
resolveNodeRS.dwFlags = XFA_RESOVENODE_RSTYPE_ExistNodes; | |
} | |
return resolveNodeRS.nodes.GetSize(); | |
} | |
return nNodes; | |
} | |
FXJSE_HVALUE CXFA_ScriptContext::GetJSValueFromMap(CXFA_Object* pObject) { | |
if (!pObject) { | |
return NULL; | |
} | |
if (pObject->IsNode()) { | |
RunVariablesScript((CXFA_Node*)pObject); | |
} | |
void* pValue = m_mapXFAToHValue.GetValueAt(pObject); | |
if (pValue == NULL) { | |
FXJSE_HVALUE jsHvalue = FXJSE_Value_Create(m_hJsRuntime); | |
FXJSE_Value_SetObject(jsHvalue, pObject, m_hJsClass); | |
m_mapXFAToHValue.SetAt(pObject, jsHvalue); | |
pValue = jsHvalue; | |
} | |
return (FXJSE_HVALUE)pValue; | |
} | |
int32_t CXFA_ScriptContext::GetIndexByName(CXFA_Node* refNode) { | |
CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper(); | |
return lpNodeHelper->XFA_GetIndex(refNode, XFA_LOGIC_Transparent, | |
lpNodeHelper->XFA_NodeIsProperty(refNode), | |
FALSE); | |
} | |
int32_t CXFA_ScriptContext::GetIndexByClassName(CXFA_Node* refNode) { | |
CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper(); | |
return lpNodeHelper->XFA_GetIndex(refNode, XFA_LOGIC_Transparent, | |
lpNodeHelper->XFA_NodeIsProperty(refNode), | |
TRUE); | |
} | |
void CXFA_ScriptContext::GetSomExpression(CXFA_Node* refNode, | |
CFX_WideString& wsExpression) { | |
CXFA_NodeHelper* lpNodeHelper = m_pResolveProcessor->GetNodeHelper(); | |
lpNodeHelper->XFA_GetNameExpression(refNode, wsExpression, TRUE, | |
XFA_LOGIC_Transparent); | |
} | |
void CXFA_ScriptContext::SetNodesOfRunScript(CXFA_NodeArray* pArray) { | |
m_pScriptNodeArray = pArray; | |
} | |
void CXFA_ScriptContext::AddNodesOfRunScript(const CXFA_NodeArray& nodes) { | |
if (!m_pScriptNodeArray) { | |
return; | |
} | |
if (nodes.GetSize() > 0) { | |
m_pScriptNodeArray->Copy(nodes); | |
} | |
} | |
void CXFA_ScriptContext::AddNodesOfRunScript(CXFA_Node* pNode) { | |
if (!m_pScriptNodeArray) { | |
return; | |
} | |
if (m_pScriptNodeArray->Find(pNode) == -1) { | |
m_pScriptNodeArray->Add(pNode); | |
} | |
} | |
IXFA_ScriptContext* XFA_ScriptContext_Create(CXFA_Document* pDocument) { | |
return new CXFA_ScriptContext(pDocument); | |
} |