📄 jsicontext.cpp
字号:
// Must unroot before unlocking val.Clear( ); if ( AccessEnd( ) == false ) rc = VXIjsi_RESULT_SYSTEM_ERROR; return rc; } // Get the value of a variable VXIjsiResult 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_NON_FATAL_ERROR; else if (( 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 result VXIjsiResult 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, const VXIjsiScopeAttr attr) { 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; if( attr == VXIjsi_NATIVE_SCOPE ) { 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; } } } } else if( attr == VXIjsi_ALIAS_SCOPE ) { JSObject *aliasScope = JS_NewObject (context, &SCOPE_CLASS, NULL, currentScope->GetJsobj( )); if ( ! aliasScope ) { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } else { Diag (SBJSI_LOG_SCOPE, L"JsiContext::PushScope", L"alias scope %s (0x%p), context 0x%p", name, aliasScope, 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 *newAliasScope = new JsiScopeChainNode (context, currentScope->GetParent(), name); if ( newAliasScope ) { rc = newAliasScope->Create (aliasScope); if (( rc == VXIjsi_RESULT_SUCCESS ) && ( ! JS_SetPrivate (context, aliasScope, newAliasScope) )) 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, newAliasScope->GetJsval( ), NULL, NULL, JSPROP_ENUMERATE) ) { // set the alias scope to current scope by evaluating a javascript SBjsiString aliasScript(name); aliasScript += " = "; aliasScript += currentScope->GetName().c_str(); currentScope->SetAliasScopeFlag(); rc = EvaluateScript (aliasScript.c_str( ), NULL); currentScope->ResetAliasScopeFlag(); // Add it to the scope chain and set it as the current scope if( rc == VXIjsi_RESULT_SUCCESS ) rc = currentScope->PushAlias(newAliasScope); } else { rc = VXIjsi_RESULT_FATAL_ERROR; } } } } else rc = VXIjsi_RESULT_INVALID_ARGUMENT; 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; // make sure we retrieve correct native scope name and alias const VXIchar* scopeName = (currentScope->HasAlias() ? currentScope->GetAliasName().c_str() : currentScope->GetName().c_str()); Diag (SBJSI_LOG_SCOPE, L"JsiContext::PopScope", L"scope %s (0x%p), context 0x%p", scopeName, currentScope->GetJsobj( ), context); VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; // if the current scope is an alias, we pop the alias then unlock and return if( currentScope->HasAlias() ) { JsiScopeChainNode *oldAlias = currentScope->PopAlias(); // Release the old scope variable within the parent scope to permit // it to be garbage collected rc = (oldAlias == NULL ? VXIjsi_RESULT_FAILURE : rc); if( rc == VXIjsi_RESULT_SUCCESS ) { jsval rval; GET_JSCHAR_FROM_VXICHAR(tmpname, tmpnamelen, oldAlias->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 = oldAlias->Release( ); } if ( AccessEnd( ) == false ) return VXIjsi_RESULT_SYSTEM_ERROR; return rc; } // 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 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 evaluation VXIjsiResult JsiContext::EvaluateScript (const VXIchar *script, JsiProtectedJsval *retval, bool loggingEnabled) const { if (( script == NULL ) || ( script[0] == 0 )) return VXIjsi_RESULT_INVALID_ARGUMENT; // Reset our private data for evaluation callbacks EvaluatePrepare (loggingEnabled); if ( retval ) retval->Clear( ); // Compile the script VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; GET_JSCHAR_FROM_VXICHAR(tmpscript, tmpscriptlen, script); JSScript *jsScript = JS_CompileUCScript (context, currentScope->GetJsobj( ), tmpscript, tmpscriptlen, NULL, 1); if ( ! jsScript ) rc = VXIjsi_RESULT_SYNTAX_ERROR; else { // Create a script object and root it to protect the script from // garbage collection, note that once this object exists it owns // the jsScript and thus we must not free it ourselves JSObject *jsScriptObj = JS_NewScriptObject (context, jsScript); if (( ! jsScriptObj ) || ( ! JS_AddNamedRoot (context, &jsScriptObj, SCRIPT_OBJECT_NAME) )) { JS_DestroyScript (context, jsScript); rc = VXIjsi_RESULT_OUT_OF_MEMORY; } else { // Evaluate the script jsval val = JSVAL_VOID; if ( JS_ExecuteScript (context, currentScope->GetJsobj( ), jsScript, &val) ) { if ( retval ) rc = retval->Set (val); } else if ( exception ) { rc = VXIjsi_RESULT_SCRIPT_EXCEPTION; } else if ( numBranches > maxBranches ) { rc = VXIjsi_RESULT_SECURITY_VIOLATION; } else { rc = VXIjsi_RESULT_NON_FATAL_ERROR; } // Release the script object if ( ! JS_RemoveRoot (context, &jsScriptObj) ) rc = VXIjsi_RESULT_FATAL_ERROR; } } return rc; } // Convert JS values to VXIValue types VXIjsiResult JsiContext::JsvalToVXIValue (JSContext *context, const jsval val, VXIValue **value) { if ( value == NULL ) return VXIjsi_RESULT_INVALID_ARGUMENT; *value = NULL; VXIjsiResult rc = VXIjsi_RESULT_SUCCESS; if ( JSVAL_IS_STRING (val) ) { GET_VXICHAR_FROM_JSCHAR(tmpval, JS_GetStringChars (JSVAL_TO_STRING (val))); *value = (VXIValue *) VXIStringCreate(tmpval); } else if ( JSVAL_IS_INT (val) ) *value = (VXIValue *) VXIIntegerCreate (JSVAL_TO_INT (val)); else if ( JSVAL_IS_DOUBLE (val) ) *value = (VXIValue *) VXIFloatCreate ((VXIflt32) *JSVAL_TO_DOUBLE (val)); else if ( JSVAL_IS_BOOLEAN (val) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -