mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-01-15 15:31:08 +00:00
174 lines
5.4 KiB
Objective-C
174 lines
5.4 KiB
Objective-C
#import "EJConvert.h"
|
|
|
|
NSString *JSValueToNSString( JSContextRef ctx, JSValueRef v ) {
|
|
JSStringRef jsString = JSValueToStringCopy( ctx, v, NULL );
|
|
if( !jsString ) return nil;
|
|
|
|
NSString *string = (NSString *)JSStringCopyCFString( kCFAllocatorDefault, jsString );
|
|
[string autorelease];
|
|
JSStringRelease( jsString );
|
|
|
|
return string;
|
|
}
|
|
|
|
JSValueRef NSStringToJSValue( JSContextRef ctx, NSString *string ) {
|
|
JSStringRef jstr = JSStringCreateWithCFString((CFStringRef)string);
|
|
JSValueRef ret = JSValueMakeString(ctx, jstr);
|
|
JSStringRelease(jstr);
|
|
return ret;
|
|
}
|
|
|
|
|
|
// JSValueToNumberFast blindly assumes that the given JSValueRef is a
|
|
// a number. Everything else will be silently converted to 0.
|
|
// This functions comes in a 64bit and 32bit flavor, since the NaN-Boxing
|
|
// in JSC works a bit differently on each platforms. For an explanation
|
|
// of the taggging refer to JSC/runtime/JSCJSValue.h
|
|
// The 32bit version just calls the normal JSValueToNumber() function
|
|
// and is thus a lot slower.
|
|
|
|
double JSValueToNumberFast(JSContextRef ctx, JSValueRef v) {
|
|
#if __LP64__ // arm64 version
|
|
union {
|
|
int64_t asInt64;
|
|
double asDouble;
|
|
struct { int32_t asInt; int32_t tag; } asBits;
|
|
} taggedValue = { .asInt64 = (int64_t)v };
|
|
|
|
#define DoubleEncodeOffset 0x1000000000000ll
|
|
#define TagTypeNumber 0xffff0000
|
|
#define ValueTrue 0x7
|
|
|
|
if( (taggedValue.asBits.tag & TagTypeNumber) == TagTypeNumber ) {
|
|
return taggedValue.asBits.asInt;
|
|
}
|
|
else if( taggedValue.asBits.tag & TagTypeNumber ) {
|
|
taggedValue.asInt64 -= DoubleEncodeOffset;
|
|
return taggedValue.asDouble;
|
|
}
|
|
else if( taggedValue.asBits.asInt == ValueTrue ) {
|
|
return 1.0;
|
|
}
|
|
else {
|
|
return 0; // false, undefined, null, object
|
|
}
|
|
#else // armv7 version
|
|
return JSValueToNumber(ctx, v, NULL);
|
|
#endif
|
|
}
|
|
|
|
void JSValueUnprotectSafe( JSContextRef ctx, JSValueRef v ) {
|
|
if( ctx && v ) {
|
|
JSValueUnprotect(ctx, v);
|
|
}
|
|
}
|
|
|
|
JSValueRef NSObjectToJSValue( JSContextRef ctx, NSObject *obj ) {
|
|
JSValueRef ret = NULL;
|
|
|
|
// String
|
|
if( [obj isKindOfClass:NSString.class] ) {
|
|
ret = NSStringToJSValue(ctx, (NSString *)obj);
|
|
}
|
|
|
|
// Number or Bool
|
|
else if( [obj isKindOfClass:NSNumber.class] ) {
|
|
NSNumber *number = (NSNumber *)obj;
|
|
if( strcmp(number.objCType, @encode(BOOL)) == 0 ) {
|
|
ret = JSValueMakeBoolean(ctx, number.boolValue);
|
|
}
|
|
else {
|
|
ret = JSValueMakeNumber(ctx, number.doubleValue);
|
|
}
|
|
}
|
|
|
|
// Date
|
|
else if( [obj isKindOfClass:NSDate.class] ) {
|
|
NSDate *date = (NSDate *)obj;
|
|
JSValueRef timestamp = JSValueMakeNumber(ctx, date.timeIntervalSince1970 * 1000.0);
|
|
ret = JSObjectMakeDate(ctx, 1, ×tamp, NULL);
|
|
}
|
|
|
|
// Array
|
|
else if( [obj isKindOfClass:NSArray.class] ) {
|
|
NSArray *array = (NSArray *)obj;
|
|
JSValueRef *args = malloc(array.count * sizeof(JSValueRef));
|
|
for( int i = 0; i < array.count; i++ ) {
|
|
args[i] = NSObjectToJSValue(ctx, array[i] );
|
|
}
|
|
ret = JSObjectMakeArray(ctx, array.count, args, NULL);
|
|
free(args);
|
|
}
|
|
|
|
// Dictionary
|
|
else if( [obj isKindOfClass:NSDictionary.class] ) {
|
|
NSDictionary *dict = (NSDictionary *)obj;
|
|
ret = JSObjectMake(ctx, NULL, NULL);
|
|
for( NSString *key in dict ) {
|
|
JSStringRef jsKey = JSStringCreateWithUTF8CString(key.UTF8String);
|
|
JSValueRef value = NSObjectToJSValue(ctx, dict[key]);
|
|
JSObjectSetProperty(ctx, (JSObjectRef)ret, jsKey, value, NULL, NULL);
|
|
JSStringRelease(jsKey);
|
|
}
|
|
}
|
|
|
|
return ret ? ret : JSValueMakeNull(ctx);
|
|
}
|
|
|
|
NSObject *JSValueToNSObject( JSContextRef ctx, JSValueRef value ) {
|
|
JSType type = JSValueGetType(ctx, value);
|
|
|
|
switch( type ) {
|
|
case kJSTypeString: return JSValueToNSString(ctx, value);
|
|
case kJSTypeBoolean: return [NSNumber numberWithBool:JSValueToBoolean(ctx, value)];
|
|
case kJSTypeNumber: return [NSNumber numberWithDouble:JSValueToNumberFast(ctx, value)];
|
|
case kJSTypeNull: return nil;
|
|
case kJSTypeUndefined: return nil;
|
|
case kJSTypeObject: break;
|
|
}
|
|
|
|
if( type == kJSTypeObject ) {
|
|
JSObjectRef jsObj = (JSObjectRef)value;
|
|
|
|
// Get the Array constructor to check if this Object is an Array
|
|
JSStringRef arrayName = JSStringCreateWithUTF8CString("Array");
|
|
JSObjectRef arrayConstructor = (JSObjectRef)JSObjectGetProperty(ctx, JSContextGetGlobalObject(ctx), arrayName, NULL);
|
|
JSStringRelease(arrayName);
|
|
|
|
if( JSValueIsInstanceOfConstructor(ctx, jsObj, arrayConstructor, NULL) ) {
|
|
// Array
|
|
JSStringRef lengthName = JSStringCreateWithUTF8CString("length");
|
|
int count = JSValueToNumberFast(ctx, JSObjectGetProperty(ctx, jsObj, lengthName, NULL));
|
|
JSStringRelease(lengthName);
|
|
|
|
NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
|
|
for( int i = 0; i < count; i++ ) {
|
|
NSObject *obj = JSValueToNSObject(ctx, JSObjectGetPropertyAtIndex(ctx, jsObj, i, NULL));
|
|
[array addObject:(obj ? obj : NSNull.null)];
|
|
}
|
|
return array;
|
|
}
|
|
else {
|
|
// Plain Object
|
|
JSPropertyNameArrayRef properties = JSObjectCopyPropertyNames(ctx, jsObj);
|
|
size_t count = JSPropertyNameArrayGetCount(properties);
|
|
|
|
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:count];
|
|
for( size_t i = 0; i < count; i++ ) {
|
|
JSStringRef jsName = JSPropertyNameArrayGetNameAtIndex(properties, i);
|
|
NSObject *obj = JSValueToNSObject(ctx, JSObjectGetProperty(ctx, jsObj, jsName, NULL));
|
|
|
|
NSString *name = (NSString *)JSStringCopyCFString( kCFAllocatorDefault, jsName );
|
|
dict[name] = obj ? obj : NSNull.null;
|
|
[name release];
|
|
}
|
|
|
|
JSPropertyNameArrayRelease(properties);
|
|
return dict;
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|