/* JSGlue.cpp */ #include "JavaScriptGlue.h" #include "JSUtils.h" #include "JSBase.h" #include "JSObject.h" #include "JSRun.h" static CFTypeRef sJSCFNullRef = NULL; static void CFJSObjectDispose(void* data); static JSObjectRef CFJSObjectCopyProperty(void* data, CFStringRef propertyName); static void CFJSObjectSetProperty(void* data, CFStringRef propertyName, JSObjectRef jsValue); static CFTypeRef CFJSObjectCopyCFValue(void* data); static UInt8 CFJSObjectEqual(void* data1, void* data2); static CFArrayRef CFJSObjectCopyPropertyNames(void* data); void* JSCFRetain(CFAllocatorRef allocator, const void *value); void JSCFRelease(CFAllocatorRef allocator, const void *value); void JSSetCFNull(CFTypeRef nullRef) { ReleaseCFType(sJSCFNullRef); sJSCFNullRef = RetainCFType(nullRef); } CFTypeRef JSGetCFNull(void) { return sJSCFNullRef; } /* JSRetain */ JSTypeRef JSRetain(JSTypeRef ref) { if (ref) { JSBase* ptr = (JSBase*)ref; ptr->Retain(); } return ref; } /* JSRelease */ void JSRelease(JSTypeRef ref) { if (ref) { JSBase* ptr = (JSBase*)ref; ptr->Release(); } } /* JSCopyDescription */ CFStringRef JSCopyDescription(JSTypeRef ref) { CFStringRef result = NULL; if (ref) { JSBase* ptr = (JSBase*)ref; ptr->CopyDescription(); } return result; } /* JSEqual */ UInt8 JSEqual(JSTypeRef ref1, JSTypeRef ref2) { UInt8 result = false; if (ref1 && ref2) { JSBase* ptr = (JSBase*)ref1; result = ptr->Equal((JSBase*)ref2); } return result; } /* JSGetTypeID */ JSTypeID JSGetTypeID(JSTypeRef ref) { JSTypeID result = kJSInvalidTypeID; if (ref) { JSBase* ptr = (JSBase*)ref; result = ptr->GetTypeID(); } return result; } /* JSGetRetainCount */ CFIndex JSGetRetainCount(JSTypeRef ref) { CFIndex result = -1; if (ref) { JSBase* ptr = (JSBase*)ref; result = ptr->RetainCount(); } return result; } /* JSObjectCreate */ JSObjectRef JSObjectCreate(void* data, JSObjectCallBacksPtr callBacks) { JSObjectRef result = JSObjectCreateInternal(data, callBacks, NULL, kJSUserObjectDataTypeUnknown); return result; } /* JSObjectCreateInternal */ JSObjectRef JSObjectCreateInternal(void* data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int type) { JSObjectRef result = NULL; JSUserObject* ptr = new JSUserObject(callBacks, markProc, data, type); result = (JSObjectRef)ptr; return result; } /* JSObjectCopyCFValue */ CFTypeRef JSObjectCopyCFValue(JSObjectRef ref) { CFTypeRef result = NULL; JSUserObject* ptr = (JSUserObject*)ref; if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) { result = ptr->CopyCFValue(); } return result; } /* JSObjectGetData */ void* JSObjectGetData(JSObjectRef ref) { void* result = NULL; JSUserObject* ptr = (JSUserObject*)ref; if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) { result = ptr->GetData(); } return result; } /* JSObjectCopyProperty */ JSObjectRef JSObjectCopyProperty(JSObjectRef ref, CFStringRef propertyName) { JSObjectRef result = NULL; JSUserObject* ptr = (JSUserObject*)ref; if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) { result = (JSObjectRef)ptr->CopyProperty(propertyName); } return result; } /* JSObjectSetProperty */ void JSObjectSetProperty(JSObjectRef ref, CFStringRef propertyName, JSObjectRef value) { JSUserObject* ptr = (JSUserObject*)ref; if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) { ptr->SetProperty(propertyName, (JSUserObject*)value); } } /* JSObjectCallFunction */ JSObjectRef JSObjectCallFunction(JSObjectRef ref, JSObjectRef thisObj, CFArrayRef args) { JSObjectRef result = NULL; JSUserObject* ptr = (JSUserObject*)ref; if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) { result = (JSObjectRef)ptr->CallFunction((JSUserObject*)thisObj, args); } return result; } /* JSRunCreate */ JSRunRef JSRunCreate(CFStringRef jsSource, JSFlags inFlags) { JSRunRef result = NULL; if (jsSource) { result = (JSRunRef) new JSRun(jsSource, inFlags); } return result; } /* JSRunCopySource */ CFStringRef JSRunCopySource(JSRunRef ref) { CFStringRef result = NULL; JSRun* ptr = (JSRun*)ref; if (ptr) { result = UStringToCFString(ptr->GetSource()); } return result; } /* JSRunCopyGlobalObject */ JSObjectRef JSRunCopyGlobalObject(JSRunRef ref) { JSObjectRef result = NULL; JSRun* ptr = (JSRun*)ref; if (ptr) { Object globalObject = ptr->GlobalObject(); result = (JSObjectRef)KJSValueToJSObject(globalObject, ptr->GetInterpreter()->globalExec()); } return result; } /* JSRunEvaluate */ JSObjectRef JSRunEvaluate(JSRunRef ref) { JSObjectRef result = NULL; JSRun* ptr = (JSRun*)ref; if (ptr) { Completion completion = ptr->Evaluate(); #if JAG_PINK_OR_LATER if (completion.isValueCompletion()) { result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GetInterpreter()->globalExec()); } if (completion.complType() == Throw) { JSFlags flags = ptr->Flags(); if (flags & kJSFlagDebug) { CFTypeRef error = JSObjectCopyCFValue(result); if (error) { CFShow(error); CFRelease(error); } } } #else result = (JSObjectRef)KJSValueToJSObject(completion, ptr->GetInterpreter()->globalExec()); #endif } return result; } /* JSRunCheckSyntax Return true if no syntax error */ bool JSRunCheckSyntax(JSRunRef ref) { #if JAG_PINK_OR_LATER bool result = false; JSRun* ptr = (JSRun*)ref; if (ptr) { JSLockInterpreter(); result = ptr->CheckSyntax(); JSUnlockInterpreter(); } return result; #else return true; #endif } /* JSCollect - trigger garbage collection */ void JSCollect(void) { #if JAG_PINK_OR_LATER InterpreterLock lock; Collector::collect(); #endif } /* JSTypeGetCFArrayCallBacks */ void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks) { if (outCallBacks) { outCallBacks->version = 1; outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain; outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease; outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription; outCallBacks->equal = (CFArrayEqualCallBack)JSEqual; } } /* JSCFRetain */ void* JSCFRetain(CFAllocatorRef allocator, const void *value) { JSRetain((JSTypeRef)value); return (void*)value; } /* JSCFRelease */ void JSCFRelease(CFAllocatorRef allocator, const void *value) { JSRelease((JSTypeRef)value); } /* JSObjectCreateWithCFType */ JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef) { JSObjectCallBacks callBacks; JSObjectRef cfJSObject = nil; if (inRef) { callBacks.dispose = CFJSObjectDispose; callBacks.equal = CFJSObjectEqual; callBacks.copyCFValue = CFJSObjectCopyCFValue; callBacks.copyProperty = CFJSObjectCopyProperty; callBacks.setProperty = CFJSObjectSetProperty; callBacks.callFunction = NULL; callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames; cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, NULL, kJSUserObjectDataTypeCFType ); } return cfJSObject; } /* CFJSObjectDispose */ void CFJSObjectDispose(void* data) { if (data) { CFRelease((JSTypeRef)data); } } CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref) { CFArrayRef result = NULL; JSUserObject* ptr = (JSUserObject*)ref; if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) { result = ptr->CopyPropertyNames(); } return result; } /* CFJSObjectCopyProperty */ JSObjectRef CFJSObjectCopyProperty(void* data, CFStringRef propertyName) { JSObjectRef result = NULL; if (data && propertyName) { CFTypeRef cfResult = NULL; if (CFGetTypeID(data) == CFDictionaryGetTypeID()) { if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo) { int len = CFDictionaryGetCount((CFDictionaryRef)data); cfResult = CFNumberCreate(NULL, kCFNumberIntType, &len); } else { cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName)); } } else if (CFGetTypeID(data) == CFArrayGetTypeID()) { if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo) { int len = CFArrayGetCount((CFArrayRef)data); cfResult = CFNumberCreate(NULL, kCFNumberIntType, &len); } else { SInt32 index = CFStringGetIntValue(propertyName); CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data); if (index >= 0 && index < arrayCount) { cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index)); } } } else if (CFGetTypeID(data) == CFStringGetTypeID()) { if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo) { int len = CFStringGetLength((CFStringRef)data); cfResult = CFNumberCreate(NULL, kCFNumberIntType, &len); } } if (cfResult) { result = JSObjectCreateWithCFType(cfResult); CFRelease(cfResult); } } return result; } /* CFJSObjectSetProperty */ void CFJSObjectSetProperty(void* data, CFStringRef propertyName, JSObjectRef jsValue) { if (data && propertyName) { CFTypeRef cfValue = JSObjectCopyCFValue(jsValue); if (cfValue) { if (CFGetTypeID(data) == CFDictionaryGetTypeID()) { CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue); } else if (CFGetTypeID(data) == CFArrayGetTypeID()) { SInt32 index = CFStringGetIntValue(propertyName); CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data); if (index >= 0) { for (; arrayCount < index; arrayCount++) { CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull()); } CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue); } } CFRelease(cfValue); } else { if (CFGetTypeID(data) == CFDictionaryGetTypeID()) { CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName); } else if (CFGetTypeID(data) == CFArrayGetTypeID()) { SInt32 index = CFStringGetIntValue(propertyName); CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data); if (index >= 0) { for (; arrayCount < index; arrayCount++) { CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull()); } CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull()); } } } } } /* CFJSObjectCopyCFValue */ CFTypeRef CFJSObjectCopyCFValue(void* data) { CFTypeRef result = NULL; if (data) { result = (CFTypeRef)CFRetain(data); } return result; } /* CFJSObjectCopyCFValue */ UInt8 CFJSObjectEqual(void* data1, void* data2) { UInt8 result = false; if (data1 && data2) { CFEqual((CFTypeRef)data1, (CFTypeRef)data2); } return result; } /* CFJSObjectCopyPropertyNames */ CFArrayRef CFJSObjectCopyPropertyNames(void* data) { CFMutableArrayRef result = NULL; if (data) { CFTypeID cfType = CFGetTypeID(data); if (cfType == CFDictionaryGetTypeID()) { CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data); if (count) { CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count); if (keys) { int i; CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, NULL); for (i = 0; i < count; i++) { CFStringRef key = (CFStringRef)keys[i]; if (CFGetTypeID(key) != CFStringGetTypeID()) continue; if (!result) result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (!result) continue; CFArrayAppendValue(result, key); } free(keys); } } } } return result; } CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array) { CFIndex count = array ? CFArrayGetCount(array) : 0; CFMutableArrayRef cfArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFIndex i; for (i = 0; cfArray && i < count; i++) { JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i); CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue); if (cfvalue) { CFArrayAppendValue(cfArray, cfvalue); CFRelease(cfvalue); } else { CFArrayAppendValue(cfArray, GetCFNull()); } } return cfArray; } CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array) { CFIndex count = array ? CFArrayGetCount(array) : 0; CFArrayCallBacks arrayCallbacks; CFMutableArrayRef jsArray; CFIndex i; JSTypeGetCFArrayCallBacks(&arrayCallbacks); jsArray = CFArrayCreateMutable(NULL, 0, &arrayCallbacks); for (i = 0; array && i < count; i++) { CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i); JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue); if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull()); if (jsValue) { CFArrayAppendValue(jsArray, jsValue); JSRelease(jsValue); } } return jsArray; } void JSLockInterpreter() { #if JAG_PINK_OR_LATER Interpreter::lock(); #endif } void JSUnlockInterpreter() { #if JAG_PINK_OR_LATER Interpreter::unlock(); #endif }