📄 jsicontext.cpp
字号:
else if ( JSVAL_IS_NULL (val) ) // JavaScript null
rc = VXIjsi_RESULT_FAILURE;
else if ( JSVAL_IS_OBJECT (val) ) {
JSObject *obj = JSVAL_TO_OBJECT(val);
if ( JS_IsArrayObject (context, obj) ) {
// Array, create a VXIVector
jsuint elements = 0;
VXIVector *vec = NULL;
if ( ! JS_GetArrayLength (context, obj, &elements) ) {
rc = VXIjsi_RESULT_FATAL_ERROR;
}
else if ( (vec = VXIVectorCreate( )) == NULL ) {
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
}
else {
// Traverse through the elements in the vector (could be empty,
// in which case we want to return an empty VXIVector)
for (jsuint i = 0;
(( rc == VXIjsi_RESULT_SUCCESS ) && ( i < elements )); i++) {
// Convert the element to a VXIValue, then insert
jsval elVal = JSVAL_VOID;
if ( JS_GetElement (context, obj, i, &elVal) ) {
VXIValue *elValue;
rc = JsvalToVXIValue (context, elVal, &elValue);
if (( rc == VXIjsi_RESULT_SUCCESS ) &&
( VXIVectorAddElement (vec, elValue) !=
VXIvalue_RESULT_SUCCESS )) {
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
VXIValueDestroy (&elValue);
}
} else {
rc = VXIjsi_RESULT_FATAL_ERROR;
}
}
if ( rc == VXIjsi_RESULT_SUCCESS )
*value = (VXIValue *) vec;
else
VXIVectorDestroy (&vec);
}
}
else if ( JS_InstanceOf (context, obj, &CONTENT_CLASS, NULL) ) {
// Content object, retrieve the VXIContent
*value = (VXIValue *) JS_GetPrivate (context, obj);
if ( *value == NULL )
rc = VXIjsi_RESULT_FATAL_ERROR;
else
*value = VXIValueClone (*value);
} else {
// Regular object, create a VXIMap
JSIdArray *props = JS_Enumerate (context, obj);
VXIMap *vmap = NULL;
if ( ! props ) {
rc = VXIjsi_RESULT_FATAL_ERROR;
} else if ( (vmap = VXIMapCreate( )) == NULL ) {
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
} else {
// Traverse through the properties in the object (could be empty,
// in which case we want to return an empty VXIMap)
jsint i = 0;
for (i = 0;
(( rc == VXIjsi_RESULT_SUCCESS ) && ( i < props->length )); i++) {
// Get the property name, looks funky but this was
// recommended by one of the SpiderMonkey contributors in a
// newsgroup thread
jsval prName = JSVAL_VOID, prVal = JSVAL_VOID;
if ( JS_IdToValue (context, props->vector[i], &prName) ) {
const jschar *name = NULL;
size_t namelen = 0;
if ( JSVAL_IS_STRING (prName) ) {
name = JS_GetStringChars (JSVAL_TO_STRING (prName));
namelen = JS_GetStringLength (JSVAL_TO_STRING (prName));
} else if ( JSVAL_IS_INT (prName) ) {
JSString *str = JS_ValueToString (context, prName);
name = JS_GetStringChars (str);
namelen = JS_GetStringLength (str);
}
// Lookup the property, convert to a value, then add to the map
if (( name ) &&
( JS_GetUCProperty (context, obj, name, namelen, &prVal) )) {
VXIValue *prValue = NULL;
GET_VXICHAR_FROM_JSCHAR(tmpname, name);
rc = JsvalToVXIValue (context, prVal, &prValue);
if (( rc == VXIjsi_RESULT_SUCCESS ) &&
( VXIMapSetProperty (vmap, tmpname, prValue)
!= VXIvalue_RESULT_SUCCESS )) {
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
VXIValueDestroy (&prValue);
}
if( rc == VXIjsi_RESULT_NON_FATAL_ERROR )
rc = VXIjsi_RESULT_SUCCESS;
} else {
rc = VXIjsi_RESULT_FATAL_ERROR;
}
} else {
rc = VXIjsi_RESULT_FATAL_ERROR;
}
}
if ( rc == VXIjsi_RESULT_SUCCESS )
*value = (VXIValue *) vmap;
else
VXIMapDestroy (&vmap);
}
// Free the ID array
if ( props )
JS_DestroyIdArray (context, props);
}
}
else // JavaScript undefined (VOID)
rc = VXIjsi_RESULT_NON_FATAL_ERROR;
// Check for out of memory during VXIValue type create
if (( rc == VXIjsi_RESULT_SUCCESS ) && ( *value == NULL ))
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
return rc;
}
// Convert VXIValue types to JS values
VXIjsiResult JsiContext::VXIValueToJsval (JSContext *context,
const VXIValue *value,
JsiProtectedJsval *val)
{
VXIjsiResult rc = VXIjsi_RESULT_SUCCESS;
if (( value == NULL ) || ( val == NULL ))
return VXIjsi_RESULT_INVALID_ARGUMENT;
switch ( VXIValueGetType (value) ) {
case VALUE_BOOLEAN: {
VXIbool i = VXIBooleanValue ((const VXIBoolean *) value);
rc = val->Set (BOOLEAN_TO_JSVAL(i));
} break;
case VALUE_INTEGER: {
VXIint32 i = VXIIntegerValue ((const VXIInteger *) value);
if ( INT_FITS_IN_JSVAL(i) )
rc = val->Set (INT_TO_JSVAL(i));
else
rc = VXIjsi_RESULT_NON_FATAL_ERROR;
} break;
case VALUE_FLOAT: {
jsdouble *d = JS_NewDouble (context,
(double) VXIFloatValue ((const VXIFloat *) value));
if ( d )
rc = val->Set (DOUBLE_TO_JSVAL(d));
else
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
} break;
case VALUE_STRING: {
GET_JSCHAR_FROM_VXICHAR(tmpvalue, tmpvaluelen,
VXIStringCStr ((const VXIString *) value));
tmpvaluelen;
JSString *s = JS_NewUCStringCopyZ (context, tmpvalue);
if ( s )
rc = val->Set (STRING_TO_JSVAL(s));
else
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
} break;
case VALUE_PTR:
// Not supported in JavaScript
rc = VXIjsi_RESULT_NON_FATAL_ERROR;
break;
case VALUE_CONTENT: {
// Create an object for the content, attach the passed content as
// private data. We set the return value prior to setting the
// private data to avoid getting garbage collected in the
// meantime.
VXIValue *c = NULL;
JSObject *content = JS_NewObject (context, &CONTENT_CLASS, NULL, NULL);
if (( ! content ) ||
( val->Set (OBJECT_TO_JSVAL(content)) != VXIjsi_RESULT_SUCCESS ) ||
( (c = VXIValueClone (value)) == NULL )) {
val->Clear( );
rc = VXIjsi_RESULT_OUT_OF_MEMORY; // JS object gets garbage collected
} else if ( ! JS_SetPrivate (context, content, c) ) {
val->Clear( );
rc = VXIjsi_RESULT_FATAL_ERROR;
}
} break;
case VALUE_MAP: {
// Create an object for the map, temporarily root it so the data
// added underneath is not garbage collected on us
JSObject *mapObj = JS_NewObject (context, &MAP_CLASS, NULL, NULL);
if ( ! mapObj ) {
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
} else if ( (rc = val->Set (OBJECT_TO_JSVAL (mapObj))) ==
VXIjsi_RESULT_SUCCESS ) {
// Walk the map and add object properties, the map may be empty
const VXIchar *prop;
const VXIValue *propValue;
VXIMapIterator *it = VXIMapGetFirstProperty ((const VXIMap *) value,
&prop, &propValue);
while (( it ) && ( rc == VXIjsi_RESULT_SUCCESS )) {
JsiProtectedJsval propVal (context);
rc = VXIValueToJsval (context, propValue, &propVal);
if ( rc == VXIjsi_RESULT_SUCCESS ) {
GET_JSCHAR_FROM_VXICHAR(tmpprop, tmpproplen, prop);
if ( ! JS_DefineUCProperty (context, mapObj, tmpprop, tmpproplen,
propVal.Get( ), NULL, NULL,
JSPROP_ENUMERATE) )
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
}
if ( VXIMapGetNextProperty (it, &prop, &propValue) !=
VXIvalue_RESULT_SUCCESS ) {
VXIMapIteratorDestroy (&it);
it = NULL;
}
}
if ( it )
VXIMapIteratorDestroy (&it);
}
} break;
case VALUE_VECTOR: {
// Create a vector for the map, temporarily root it so the data
// added underneath is not garbage collected on us
JSObject *vecObj = JS_NewArrayObject (context, 0, NULL);
if ( ! vecObj ) {
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
} else if ( (rc = val->Set (OBJECT_TO_JSVAL (vecObj))) ==
VXIjsi_RESULT_SUCCESS ) {
// Walk the map and add object properties, the map may be empty
const VXIVector *vec = (const VXIVector *) value;
VXIunsigned i = 0;
const VXIValue *elValue;
while (( rc == VXIjsi_RESULT_SUCCESS ) &&
( (elValue = VXIVectorGetElement (vec, i)) != NULL )) {
JsiProtectedJsval elVal (context);
rc = VXIValueToJsval (context, elValue, &elVal);
if (( rc == VXIjsi_RESULT_SUCCESS ) &&
( ! JS_DefineElement (context, vecObj, i, elVal.Get( ), NULL,
NULL, JSPROP_ENUMERATE) ))
rc = VXIjsi_RESULT_OUT_OF_MEMORY;
i++;
}
}
} break;
default:
rc = VXIjsi_RESULT_UNSUPPORTED;
}
if ( rc != VXIjsi_RESULT_SUCCESS )
val->Clear( );
return rc;
}
// Static callback for finalizing scopes
void JS_DLL_CALLBACK
JsiContext::ScopeFinalize (JSContext *context, JSObject *obj)
{
// Get this for logging the destruction
JsiContext *pThis = (JsiContext *) JS_GetContextPrivate (context);
// Get the scope node from the private data and delete it
JsiScopeChainNode *scopeNode =
(JsiScopeChainNode *) JS_GetPrivate (context, obj);
if ( scopeNode ) {
if ( pThis )
pThis->Diag (SBJSI_LOG_SCOPE, L"JsiContext::ScopeFinalize",
L"scope garbage collected %s (0x%p), context 0x%p",
scopeNode->GetName( ).c_str( ), obj, context);
delete scopeNode;
}
}
// Static callback for finalizing content objects
void JS_DLL_CALLBACK JsiContext::ContentFinalize (JSContext *cx, JSObject *obj)
{
// Get the scope name from the private data and delete it
VXIContent *content = (VXIContent *) JS_GetPrivate (cx, obj);
if ( content ) {
VXIValue *tmp = (VXIValue *) content;
VXIValueDestroy (&tmp);
}
}
// Static callback for enforcing maxBranches
JSBool JS_DLL_CALLBACK
JsiContext::BranchCallback (JSContext *context, JSScript *script)
{
if ( ! context )
return JS_FALSE;
// Get ourself from our private data
JsiContext *pThis = (JsiContext *) JS_GetContextPrivate (context);
if ( ! pThis ) {
// Severe error
return JS_FALSE;
}
pThis->numBranches++;
JSBool rc = JS_TRUE;
if ( pThis->numBranches > pThis->maxBranches ) {
rc = JS_FALSE;
pThis->Error (JSI_WARN_MAX_BRANCHES_EXCEEDED, L"%s%ld",
L"maxBranches", pThis->maxBranches);
}
return rc;
}
// Static callback for reporting JavaScript errors
void JS_DLL_CALLBACK JsiContext::ErrorReporter (JSContext *context,
const char *message,
JSErrorReport *report)
{
if ( ! context )
return;
// Get ourself from our private data
JsiContext *pThis = (JsiContext *) JS_GetContextPrivate (context);
if ( ! pThis )
return; // Severe error
// Save exception information, ownership of the value is passed
jsval ex = JSVAL_VOID;
VXIValue *exception = NULL;
if (( JS_IsExceptionPending (context) ) &&
( JS_GetPendingException (context, &ex) ) &&
( JsvalToVXIValue (context, ex, &exception) == VXIjsi_RESULT_SUCCESS )) {
if ( pThis->exception )
VXIValueDestroy (&pThis->exception);
pThis->exception = exception;
}
if ( pThis->logEnabled ) {
// Convert the ASCII string to wide characters
wchar_t wmessage[1024];
size_t len = strlen (message);
if ( len > 1023 )
len = 1023;
for (size_t i = 0; i < len; i++)
wmessage[i] = (wchar_t) message[i];
wmessage[len] = 0;
// Determine the error number to log
unsigned int errNum;
if ( JSREPORT_IS_WARNING (report->flags) )
errNum = JSI_WARN_SM_SCRIPT_WARNING;
else if ( JSREPORT_IS_EXCEPTION (report->flags) )
errNum = JSI_ERROR_SM_SCRIPT_EXCEPTION;
else if ( JSREPORT_IS_STRICT (report->flags) )
errNum = JSI_WARN_SM_SCRIPT_STRICT;
else
errNum = JSI_ERROR_SM_SCRIPT_ERROR;
// Log the error
GET_VXICHAR_FROM_JSCHAR(tmpuclinebuf, report->uclinebuf);
GET_VXICHAR_FROM_JSCHAR(tmpuctokenptr, report->uctokenptr);
pThis->Error (errNum, L"%s%s%s%ld%s%s%s%s", L"errmsg", wmessage,
L"line", report->lineno,
L"linetxt", (tmpuclinebuf ? tmpuclinebuf : L""),
L"tokentxt", (tmpuctokenptr ? tmpuctokenptr : L""));
}
}
// Check if the variable name is valid at declaration
bool JsiContext::IsValidVarName(JSContext *context, JSObject *obj, const VXIchar* vname)
{
bool ret = true;
SBjsiString tscript(L"var ");
tscript += vname;
GET_JSCHAR_FROM_VXICHAR(tmpscript, tmpscriptlen, tscript.c_str());
// check if the variable name is valid
JSScript *jsScript = JS_CompileUCScript (context, obj,
tmpscript, tmpscriptlen, NULL, 1);
if( !jsScript )
ret = false;
else
JS_DestroyScript (context, jsScript);
return ret;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -