📄 jsicontext.cpp
字号:
VXIjsiResult JsiContext::CreateVar (const VXIchar *name, const VXIchar *expr){ if (( name == NULL ) || ( name[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; // If this is a fully qualified name, just do a SetVar( ) as that // handles explicitly scoped variables and this doesn't. No // functional effect to doing so, the only difference is that // CreateVar( ) masks vars of the same name from prior scopes when // SetVar( ) just sets the old one, having an explicit scope makes // that irrelevant since then JS knows exactly what to do. if ( wcschr (name, L'.') ) return SetVar (name, expr); if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Evaluate the expression, need to eval before setting so we can // deal with things like "1; 2;" which can't be handled if we just // make a temporary script VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; JsiProtectedJsval val (context); if (( expr != NULL ) && ( expr[0] != 0 )) rc = EvaluateScript (expr, &val); // Set the variable in the current scope directly, ensures we mask // any var of the same name from earlier scopes if ( rc == VXIjsi_RESULT_SUCCESS ) { GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name); if ( ! JS_DefineUCProperty (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, val.Get( ), NULL, NULL, JSPROP_ENUMERATE) ) rc = VXIjsi_RESULT_OUT_OF_MEMORY; } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Create a script variable relative to the current scopeVXIjsiResult JsiContext::CreateVar (const VXIchar *name, const VXIValue *value){ if (( name == NULL ) || ( name[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; // If this is a fully qualified name, just do a SetVar( ) as that // handles explicitly scoped variables and this doesn't. No // functional effect to doing so, the only difference is that // CreateVar( ) masks vars of the same name from prior scopes when // SetVar( ) just sets the old one, having an explicit scope makes // that irrelevant since then JS knows exactly what to do. if ( wcschr (name, L'.') ) return SetVar (name, value); if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Convert the value to a JavaScript variable VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; JsiProtectedJsval val (context); if ( value ) rc = VXIValueToJsval (context, value, &val); // Set the variable in the current scope directly, ensures we mask // any var of the same name from earlier scopes if ( rc == VXIjsi_RESULT_SUCCESS ) { GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name); if ( ! JS_DefineUCProperty (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, val.Get( ), NULL, NULL, JSPROP_ENUMERATE) ) rc = VXIjsi_RESULT_OUT_OF_MEMORY; } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Set a script variable relative to the current scopeVXIjsiResult JsiContext::SetVar (const VXIchar *name, const VXIchar *expr){ if (( name == NULL ) || ( name[0] == 0 ) || ( expr == NULL ) || ( expr[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Evaluate the expression, need to eval before setting so we can // deal with things like "1; 2;" which can't be handled if we just // make a temporary script JsiProtectedJsval val (context); VXIjsiResult rc = EvaluateScript (expr, &val); // What we'd like to do is lookup the variable, then set it to the // jsval we got above. (The lookup is complex because it could be // a partially or fully qualified name, with potential scope // chain/prototype chain lookups.) However, that isn't possible in // SpiderMonkey. So instead we set a temporary variable in the // global scope, then assign the specified object to that, then // destroy the temporary. if ( rc == VXIjsi_RESULT_SUCCESS ) { if ( JS_DefineProperty (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, val.Get( ), NULL, NULL, 0) ) { // Do the copy using a temporary script SBinetString script (name); script += L"="; script += GLOBAL_TEMP_VAR_W; rc = EvaluateScript (script.c_str( ), NULL); // Destroy the temporary variable jsval ignored = JSVAL_VOID; if ( ! JS_DeleteProperty2 (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, &ignored) ) rc = VXIjsi_RESULT_FATAL_ERROR; } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Set a script variable relative to the current scopeVXIjsiResult JsiContext::SetVar (const VXIchar *name, const VXIValue *value){ if (( name == NULL ) || ( name[0] == 0 ) || ( value == NULL )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Convert the value to a JavaScript variable JsiProtectedJsval val (context); VXIjsiResult rc = VXIValueToJsval (context, value, &val); // What we'd like to do is lookup the variable, then set it to the // jsval we got above. (The lookup is complex because it could be // a partially or fully qualified name, with potential scope // chain/prototype chain lookups.) However, that isn't possible in // SpiderMonkey. So instead we set a temporary variable in the // global scope, then assign the specified object to that, then // destroy the temporary. if ( rc == VXIjsi_RESULT_SUCCESS ) { if ( JS_DefineProperty (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, val.Get( ), NULL, NULL, 0) ) { // Do the copy using a temporary script SBinetString script (name); script += L"="; script += GLOBAL_TEMP_VAR_W; rc = EvaluateScript (script.c_str( ), NULL); // Destroy the temporary variable jsval ignored = JSVAL_VOID; if ( ! JS_DeleteProperty2 (context, currentScope->GetJsobj( ), GLOBAL_TEMP_VAR, &ignored) ) rc = VXIjsi_RESULT_FATAL_ERROR; } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } } // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Get the value of a variableVXIjsiResult JsiContext::GetVar (const VXIchar *name, VXIValue **value) const{ if (( name == NULL ) || ( name[0] == 0 ) || ( value == NULL )) return VXIjsi_RESULT_INVALID_ARGUMENT; *value = NULL; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Get the variable, we need to evaluate instead of just calling // JS_GetUCProperty( ) in order to have it automatically look back // through the scope chain, as well as to permit explicit scope // references like "myscope.myvar" JsiProtectedJsval val (context); VXIjsiResult rc = EvaluateScript (name, &val); if ( rc == VXIjsi_RESULT_SUCCESS ) rc = JsvalToVXIValue (context, val.Get( ), value); else if (( rc == VXIjsi_RESULT_SYNTAX_ERROR ) || ( rc == VXIjsi_RESULT_SCRIPT_EXCEPTION )) rc = VXIjsi_RESULT_NON_FATAL_ERROR; // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Check whether a variable is defined (not void, could be NULL)VXIjsiResult JsiContext::CheckVar (const VXIchar *name) const{ if (( name == NULL ) || ( name[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Get the variable, we need to evaluate instead of just calling // JS_GetUCProperty( ) in order to have it automatically look back // through the scope chain, as well as to permit explicit scope // references like "myscope.myvar". We disable logging because // we don't want JavaScript error reports about this var being // undefined. JsiProtectedJsval val (context); VXIjsiResult rc = EvaluateScript (name, &val, false); if (( rc == VXIjsi_RESULT_SYNTAX_ERROR ) || ( rc == VXIjsi_RESULT_SCRIPT_EXCEPTION ) || ( rc == VXIjsi_RESULT_NON_FATAL_ERROR ) || (( rc == VXIjsi_RESULT_SUCCESS ) && ( JSVAL_IS_VOID (val.Get( )) ))) // JavaScript undefined rc = VXIjsi_RESULT_FAILURE; // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Execute a script, optionally returning any execution resultVXIjsiResult JsiContext::Eval (const VXIchar *expr, VXIValue **result){ if (( expr == NULL ) || ( expr[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( result ) *result = NULL; // Execute the script if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; JsiProtectedJsval val (context); VXIjsiResult rc = EvaluateScript (expr, &val); if (( result ) && ( rc == VXIjsi_RESULT_SUCCESS ) && ( val.Get( ) != JSVAL_VOID )) rc = JsvalToVXIValue (context, val.Get( ), result); // Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Push a new context onto the scope chain (add a nested scope)VXIjsiResult JsiContext::PushScope (const VXIchar *name){ if (( ! name ) || ( ! name[0] )) return VXIjsi_RESULT_INVALID_ARGUMENT; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; // Create an object for the scope, the current scope is its parent VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; JSObject *scope = JS_NewObject (context, &SCOPE_CLASS, NULL, currentScope->GetJsobj( )); if ( ! scope ) { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } else { Diag (SBJSI_LOG_SCOPE, L"JsiContext::PushScope", L"scope %s (0x%p), context 0x%p", name, scope, context); // The scope chain node object locks it to protect this from // garbage collection in case someone (possibly a malicious // script) destroys the data member pointing at this in the global // scope JsiScopeChainNode *newScope = new JsiScopeChainNode (context, currentScope, name); if ( newScope ) { rc = newScope->Create (scope); if (( rc == VXIjsi_RESULT_SUCCESS ) && ( ! JS_SetPrivate (context, scope, newScope) )) rc = VXIjsi_RESULT_FATAL_ERROR; } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } // Set this scope as a property of the parent scope if ( rc == VXIjsi_RESULT_SUCCESS ) { GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, name); if ( JS_DefineUCProperty (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, newScope->GetJsval( ), NULL, NULL, JSPROP_ENUMERATE) ) { // Add it to the scope chain and set it as the current scope currentScope->SetChild (newScope); currentScope = newScope; } else { rc = VXIjsi_RESULT_FATAL_ERROR; } } } if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Pop a context from the scope chain (remove a nested scope)VXIjsiResult JsiContext::PopScope( ){ // Don't pop up past the global scope if ( currentScope == scopeChain ) return VXIjsi_RESULT_NON_FATAL_ERROR; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; Diag (SBJSI_LOG_SCOPE, L"JsiContext::PopScope", L"scope %s (0x%p), context 0x%p", currentScope->GetName( ).c_str( ), currentScope->GetJsobj( ), context); // Revert to the parent scope JsiScopeChainNode *oldScope = currentScope; currentScope = currentScope->GetParent( ); currentScope->SetChild (NULL); // Release the old scope variable within the parent scope to permit // it to be garbage collected VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; jsval rval; GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, oldScope->GetName( ).c_str( )); if ( ! JS_DeleteUCProperty2 (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, &rval) ) rc = VXIjsi_RESULT_FATAL_ERROR; // Now finish releasing the old scope, the actual wrapper object is // freed by the scope finalize method when garbage collection occurs rc = oldScope->Release( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Reset the scope chain to the global scope (pop all nested scopes)VXIjsiResult JsiContext::ClearScopes( ){ // See if there is anything to do if ( currentScope == scopeChain ) return VXIjsi_RESULT_SUCCESS; if ( AccessBegin( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; Diag (SBJSI_LOG_SCOPE, L"JsiContext::ClearScopes", L"context 0x%p", context); // Revert to the global scope JsiScopeChainNode *oldScope = scopeChain->GetChild( ); currentScope = scopeChain; currentScope->SetChild (NULL); // Release the old child scope variable within the global scope to // permit it and all its descendants to be garbage collected VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; jsval rval; GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, oldScope->GetName( ).c_str( )); if ( ! JS_DeleteUCProperty2 (context, currentScope->GetJsobj( ), tmpname, tmpnamelen, &rval) ) rc = VXIjsi_RESULT_FATAL_ERROR; // Now finish releasing the old scope, the actual wrapper object is // freed by the scope finalize method when garbage collection occurs rc = oldScope->Release( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc;}// Script evaluationVXIjsiResult JsiContext::EvaluateScript (const VXIchar *script, JsiProtectedJsval *retval, bool loggingEnabled) const
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -