// // JSCocoaLib.m // JSCocoa // // Created by Patrick Geiller on 21/12/08. // Copyright 2008 __MyCompanyName__. All rights reserved. // #import "JSCocoaLib.h" // // Handles out arguments of functions and methods. // eg NSOpenGLGetVersion(int*, int*) asks for two pointers to int. // JSCocoaOutArgument will alloc the memory through JSCocoaFFIArgument and get the result back to Javascript (check out value in JSCocoaController) // @implementation JSCocoaOutArgument - (id)init { self = [super init]; arg = nil; buffer = nil; return self; } - (void)cleanUp { [arg release]; [buffer release]; } - (void)dealloc { [self cleanUp]; [super dealloc]; } - (void)finalize { [self cleanUp]; [super finalize]; } // // convert the out value to a JSValue // - (JSValueRef)outJSValueRefInContext:(JSContextRef)ctx { JSValueRef jsValue = NULL; [arg toJSValueRef:&jsValue inContext:ctx]; return jsValue; } // Called from Javascript to extract the resulting value as an object (valueOfCallback returns a string) - (JSValueRefAndContextRef)outValue { JSValueRefAndContextRef r; id jsc = nil; object_getInstanceVariable(self, "__jsCocoaController", (void**)&jsc); if (!jsc) return r; r.ctx = [jsc ctx]; r.value = [self outJSValueRefInContext:r.ctx]; return r; } // // JSCocoaOutArgument holds a JSCocoaFFIArgument around. // it stays alive after ffi_call and can be queried by Javascript for type modifier values. // - (BOOL)mateWithJSCocoaFFIArgument:(JSCocoaFFIArgument*)_arg { // If holding a memory buffer, use its pointer if (buffer) { arg = _arg; [arg retain]; void* ptr = [buffer pointerForIndex:bufferIndex]; if (!ptr) return NO; [arg setTypeEncoding:[arg typeEncoding] withCustomStorage:ptr]; return YES; } // Standard pointer void* p = [_arg allocatePointerStorage]; if (!p) return NO; // Zero out storage *(void**)p = NULL; arg = _arg; [arg retain]; return YES; } - (BOOL)mateWithMemoryBuffer:(id)b atIndex:(int)idx { if (!b || ![b isKindOfClass:[JSCocoaMemoryBuffer class]]) return NSLog(@"mateWithMemoryBuffer called without a memory buffer (%@)", b), NO; buffer = b; [buffer retain]; bufferIndex = idx; return YES; } @end // // Instead of malloc(sizeof(float)*4), JSCocoaMemoryBuffer expects 'ffff' as an init string. // The buffer can be manipulated like an array (buffer[2] = 0.5) // * it can be filled, calling methods to copy data in it // - (NSBezierPathElement)elementAtIndex:(NSInteger)index associatedPoints:(NSPointArray)points; // * it can be used as data source, calling methods to copy data from it // - (void)setAssociatedPoints:(NSPointArray)points atIndex:(NSInteger)index; // @implementation JSCocoaMemoryBuffer + (id)bufferWithTypes:(id)types { return [[[JSCocoaMemoryBuffer alloc] initWithTypes:types] autorelease]; } - (id)initWithTypes:(id)_types { self = [super init]; buffer = NULL; // Copy types string typeString = [NSString stringWithString:_types]; [typeString retain]; // Compute buffer size const char* types = [typeString UTF8String]; NSUInteger l = [typeString length]; bufferSize = 0; for (int i=0; i= [typeString length]) return NULL; void* pointedValue = buffer; for (int i=0; i= [typeString length]) return '\0'; return [typeString UTF8String][idx]; } - (NSUInteger)typeCount { return [typeString length]; } -(BOOL)referenceObject:(id)o usingPointerAtIndex:(NSUInteger)idx { if ([self typeAtIndex:idx] != '^') return NO; void* v = *(void**)[self pointerForIndex:idx]; if (!v) return NO; *(id*)v = o; return YES; } - (id)dereferenceObjectAtIndex:(NSUInteger)idx { if ([self typeAtIndex:idx] != '^') return nil; void* v = *(void**)[self pointerForIndex:idx]; if (!v) return NULL; id o = *(id*)v; return o; return *(id*)v; } // // Using JSValueRefAndContextRef as input to get the current context in which to create the return value // - (JSValueRef)valueAtIndex:(NSUInteger)idx inContext:(JSContextRef)ctx { char typeEncoding = [self typeAtIndex:idx]; void* pointedValue = [self pointerForIndex:idx]; if (!pointedValue) return JSValueMakeUndefined(ctx); JSValueRef returnValue; [JSCocoaFFIArgument toJSValueRef:&returnValue inContext:ctx typeEncoding:typeEncoding fullTypeEncoding:nil fromStorage:pointedValue]; return returnValue; } - (BOOL)setValue:(JSValueRef)jsValue atIndex:(NSUInteger)idx inContext:(JSContextRef)ctx { char typeEncoding = [self typeAtIndex:idx]; void* pointedValue = [self pointerForIndex:idx]; if (!pointedValue) return NO; [JSCocoaFFIArgument fromJSValueRef:jsValue inContext:ctx typeEncoding:typeEncoding fullTypeEncoding:nil fromStorage:pointedValue]; return YES; } @end @implementation JSCocoaLib // // Class list // Some classes are skipped as adding them to an array crashes (Zombie, classes derived from Object or NSProxy) // + (NSArray*)classes { int classCount = objc_getClassList(nil, 0); Class* classList = malloc(sizeof(Class)*classCount); objc_getClassList(classList, classCount); NSMutableArray* classArray = [NSMutableArray array]; for (int i=0; i