mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-12-26 08:03:17 +03:00
JSCocoa
This commit is contained in:
parent
bb51f70c5b
commit
7a773615f2
@ -61,6 +61,15 @@
|
||||
8359A69213FE1FE900AC37E3 /* worker-javascript.js in Resources */ = {isa = PBXBuildFile; fileRef = 8359A63413FE1FCA00AC37E3 /* worker-javascript.js */; };
|
||||
8359A6B413FE24B300AC37E3 /* atomicity.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6B313FE24B300AC37E3 /* atomicity.js */; };
|
||||
8359A6B713FE24BC00AC37E3 /* atomicity.js in Resources */ = {isa = PBXBuildFile; fileRef = 8359A6B313FE24B300AC37E3 /* atomicity.js */; };
|
||||
8359A6EE13FE26DA00AC37E3 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */; };
|
||||
8359A72213FE270F00AC37E3 /* BridgeSupportController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6F913FE270F00AC37E3 /* BridgeSupportController.m */; };
|
||||
8359A72313FE270F00AC37E3 /* class.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6FA13FE270F00AC37E3 /* class.js */; };
|
||||
8359A72F13FE270F00AC37E3 /* JSCocoaController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71813FE270F00AC37E3 /* JSCocoaController.m */; };
|
||||
8359A73013FE270F00AC37E3 /* JSCocoaFFIArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71A13FE270F00AC37E3 /* JSCocoaFFIArgument.m */; };
|
||||
8359A73113FE270F00AC37E3 /* JSCocoaFFIClosure.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71C13FE270F00AC37E3 /* JSCocoaFFIClosure.m */; };
|
||||
8359A73213FE270F00AC37E3 /* JSCocoaLib.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A71E13FE270F00AC37E3 /* JSCocoaLib.m */; };
|
||||
8359A73313FE270F00AC37E3 /* JSCocoaPrivateObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8359A72013FE270F00AC37E3 /* JSCocoaPrivateObject.m */; };
|
||||
8359A73413FE270F00AC37E3 /* jslint-jscocoa.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A72113FE270F00AC37E3 /* jslint-jscocoa.js */; };
|
||||
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
|
||||
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
||||
@ -128,6 +137,22 @@
|
||||
8359A63313FE1FCA00AC37E3 /* worker-css.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "worker-css.js"; path = "HTML/ace/worker-css.js"; sourceTree = "<group>"; };
|
||||
8359A63413FE1FCA00AC37E3 /* worker-javascript.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = "worker-javascript.js"; path = "HTML/ace/worker-javascript.js"; sourceTree = "<group>"; };
|
||||
8359A6B313FE24B300AC37E3 /* atomicity.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = atomicity.js; path = HTML/atomicity.js; sourceTree = "<group>"; };
|
||||
8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||
8359A6F813FE270F00AC37E3 /* BridgeSupportController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BridgeSupportController.h; sourceTree = "<group>"; };
|
||||
8359A6F913FE270F00AC37E3 /* BridgeSupportController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BridgeSupportController.m; sourceTree = "<group>"; };
|
||||
8359A6FA13FE270F00AC37E3 /* class.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = class.js; sourceTree = "<group>"; };
|
||||
8359A71313FE270F00AC37E3 /* JSCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoa.h; sourceTree = "<group>"; };
|
||||
8359A71713FE270F00AC37E3 /* JSCocoaController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaController.h; sourceTree = "<group>"; };
|
||||
8359A71813FE270F00AC37E3 /* JSCocoaController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaController.m; sourceTree = "<group>"; };
|
||||
8359A71913FE270F00AC37E3 /* JSCocoaFFIArgument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaFFIArgument.h; sourceTree = "<group>"; };
|
||||
8359A71A13FE270F00AC37E3 /* JSCocoaFFIArgument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaFFIArgument.m; sourceTree = "<group>"; };
|
||||
8359A71B13FE270F00AC37E3 /* JSCocoaFFIClosure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaFFIClosure.h; sourceTree = "<group>"; };
|
||||
8359A71C13FE270F00AC37E3 /* JSCocoaFFIClosure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaFFIClosure.m; sourceTree = "<group>"; };
|
||||
8359A71D13FE270F00AC37E3 /* JSCocoaLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaLib.h; sourceTree = "<group>"; };
|
||||
8359A71E13FE270F00AC37E3 /* JSCocoaLib.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaLib.m; sourceTree = "<group>"; };
|
||||
8359A71F13FE270F00AC37E3 /* JSCocoaPrivateObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCocoaPrivateObject.h; sourceTree = "<group>"; };
|
||||
8359A72013FE270F00AC37E3 /* JSCocoaPrivateObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSCocoaPrivateObject.m; sourceTree = "<group>"; };
|
||||
8359A72113FE270F00AC37E3 /* jslint-jscocoa.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "jslint-jscocoa.js"; sourceTree = "<group>"; };
|
||||
8D1107310486CEB800E47090 /* Atomicity-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Atomicity-Info.plist"; sourceTree = "<group>"; };
|
||||
8D1107320486CEB800E47090 /* Atomicity.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Atomicity.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
@ -139,6 +164,7 @@
|
||||
files = (
|
||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||
83599F9B13FE0F8400AC37E3 /* WebKit.framework in Frameworks */,
|
||||
8359A6EE13FE26DA00AC37E3 /* JavaScriptCore.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -159,6 +185,7 @@
|
||||
children = (
|
||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||
83599F9A13FE0F8400AC37E3 /* WebKit.framework */,
|
||||
8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */,
|
||||
);
|
||||
name = "Linked Frameworks";
|
||||
sourceTree = "<group>";
|
||||
@ -188,6 +215,7 @@
|
||||
080E96DDFE201D6D7F000001 /* Classes */,
|
||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||
29B97317FDCFA39411CA2CEA /* Resources */,
|
||||
8359A6F713FE270F00AC37E3 /* JSCocoa */,
|
||||
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
||||
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||
);
|
||||
@ -287,6 +315,28 @@
|
||||
name = ace;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8359A6F713FE270F00AC37E3 /* JSCocoa */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8359A6F813FE270F00AC37E3 /* BridgeSupportController.h */,
|
||||
8359A6F913FE270F00AC37E3 /* BridgeSupportController.m */,
|
||||
8359A6FA13FE270F00AC37E3 /* class.js */,
|
||||
8359A71313FE270F00AC37E3 /* JSCocoa.h */,
|
||||
8359A71713FE270F00AC37E3 /* JSCocoaController.h */,
|
||||
8359A71813FE270F00AC37E3 /* JSCocoaController.m */,
|
||||
8359A71913FE270F00AC37E3 /* JSCocoaFFIArgument.h */,
|
||||
8359A71A13FE270F00AC37E3 /* JSCocoaFFIArgument.m */,
|
||||
8359A71B13FE270F00AC37E3 /* JSCocoaFFIClosure.h */,
|
||||
8359A71C13FE270F00AC37E3 /* JSCocoaFFIClosure.m */,
|
||||
8359A71D13FE270F00AC37E3 /* JSCocoaLib.h */,
|
||||
8359A71E13FE270F00AC37E3 /* JSCocoaLib.m */,
|
||||
8359A71F13FE270F00AC37E3 /* JSCocoaPrivateObject.h */,
|
||||
8359A72013FE270F00AC37E3 /* JSCocoaPrivateObject.m */,
|
||||
8359A72113FE270F00AC37E3 /* jslint-jscocoa.js */,
|
||||
);
|
||||
path = JSCocoa;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -402,6 +452,14 @@
|
||||
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
||||
256AC3DA0F4B6AC300CF3369 /* AtomicityAppDelegate.m in Sources */,
|
||||
8359A6B413FE24B300AC37E3 /* atomicity.js in Sources */,
|
||||
8359A72213FE270F00AC37E3 /* BridgeSupportController.m in Sources */,
|
||||
8359A72313FE270F00AC37E3 /* class.js in Sources */,
|
||||
8359A72F13FE270F00AC37E3 /* JSCocoaController.m in Sources */,
|
||||
8359A73013FE270F00AC37E3 /* JSCocoaFFIArgument.m in Sources */,
|
||||
8359A73113FE270F00AC37E3 /* JSCocoaFFIClosure.m in Sources */,
|
||||
8359A73213FE270F00AC37E3 /* JSCocoaLib.m in Sources */,
|
||||
8359A73313FE270F00AC37E3 /* JSCocoaPrivateObject.m in Sources */,
|
||||
8359A73413FE270F00AC37E3 /* jslint-jscocoa.js in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -432,6 +490,10 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)\"",
|
||||
);
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
@ -449,6 +511,10 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)\"",
|
||||
);
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = Atomicity_Prefix.pch;
|
||||
@ -467,6 +533,10 @@
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-lxml2",
|
||||
"-lffi",
|
||||
);
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.6;
|
||||
};
|
||||
@ -479,6 +549,10 @@
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
OTHER_LDFLAGS = (
|
||||
"-lxml2",
|
||||
"-lffi",
|
||||
);
|
||||
PREBINDING = NO;
|
||||
SDKROOT = macosx10.6;
|
||||
};
|
||||
|
43
JSCocoa/BridgeSupportController.h
Normal file
43
JSCocoa/BridgeSupportController.h
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// BridgeSupportController.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 08/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
@interface BridgeSupportController : NSObject {
|
||||
|
||||
|
||||
NSMutableArray* paths;
|
||||
NSMutableArray* xmlDocuments;
|
||||
|
||||
NSMutableDictionary* hash;
|
||||
NSMutableDictionary* variadicSelectors;
|
||||
NSMutableDictionary* variadicFunctions;
|
||||
}
|
||||
|
||||
+ (id)sharedController;
|
||||
|
||||
- (BOOL)loadBridgeSupport:(NSString*)path;
|
||||
- (BOOL)isBridgeSupportLoaded:(NSString*)path;
|
||||
- (NSUInteger)bridgeSupportIndexForString:(NSString*)string;
|
||||
|
||||
- (NSMutableDictionary*)variadicSelectors;
|
||||
- (NSMutableDictionary*)variadicFunctions;
|
||||
|
||||
/*
|
||||
- (NSString*)query:(NSString*)name withType:(NSString*)type;
|
||||
- (NSString*)query:(NSString*)name withType:(NSString*)type inBridgeSupportFile:(NSString*)file;
|
||||
*/
|
||||
- (NSString*)queryName:(NSString*)name;
|
||||
- (NSString*)queryName:(NSString*)name type:(NSString*)type;
|
||||
|
||||
- (NSArray*)keys;
|
||||
|
||||
|
||||
@end
|
254
JSCocoa/BridgeSupportController.m
Normal file
254
JSCocoa/BridgeSupportController.m
Normal file
@ -0,0 +1,254 @@
|
||||
//
|
||||
// BridgeSupportController.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 08/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BridgeSupportController.h"
|
||||
|
||||
|
||||
@implementation BridgeSupportController
|
||||
|
||||
|
||||
+ (id)sharedController
|
||||
{
|
||||
static id singleton;
|
||||
@synchronized(self)
|
||||
{
|
||||
if (!singleton)
|
||||
singleton = [[BridgeSupportController alloc] init];
|
||||
return singleton;
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
paths = [[NSMutableArray alloc] init];
|
||||
xmlDocuments = [[NSMutableArray alloc] init];
|
||||
hash = [[NSMutableDictionary alloc] init];
|
||||
variadicSelectors = [[NSMutableDictionary alloc] init];
|
||||
variadicFunctions = [[NSMutableDictionary alloc] init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[variadicFunctions release];
|
||||
[variadicSelectors release];
|
||||
[hash release];
|
||||
[paths release];
|
||||
[xmlDocuments release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
//
|
||||
// Load a bridgeSupport file into a hash as { name : xmlTagString }
|
||||
//
|
||||
- (BOOL)loadBridgeSupport:(NSString*)path
|
||||
{
|
||||
NSError* error = nil;
|
||||
/*
|
||||
Adhoc parser
|
||||
NSXMLDocument is too slow
|
||||
loading xml document as string then querying on-demand is too slow
|
||||
can't get CFXMLParserRef to work
|
||||
don't wan't to delve into expat
|
||||
-> ad hoc : load file, build a hash of { name : xmlTagString }
|
||||
*/
|
||||
NSString* xmlDocument = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
|
||||
if (error) return NSLog(@"loadBridgeSupport : %@", error), NO;
|
||||
|
||||
char* c = (char*)[xmlDocument UTF8String];
|
||||
#ifdef __OBJC_GC__
|
||||
char* originalC = c;
|
||||
[[NSGarbageCollector defaultCollector] disableCollectorForPointer:originalC];
|
||||
#endif
|
||||
|
||||
// double t0 = CFAbsoluteTimeGetCurrent();
|
||||
// Start parsing
|
||||
for (; *c; c++)
|
||||
{
|
||||
if (*c == '<')
|
||||
{
|
||||
char startTagChar = c[1];
|
||||
if (startTagChar == 0) return NO;
|
||||
|
||||
// 'co' constant
|
||||
// 'cl' class
|
||||
// 'e' enum
|
||||
// 'fu' function
|
||||
// 'st' struct
|
||||
if ((c[1] == 'c' && (c[2] == 'o' || c[2] == 'l')) || c[1] == 'e' || (c[1] == 'f' && c[2] == 'u') || (c[1] == 's' && c[2] == 't'))
|
||||
{
|
||||
// Extract name
|
||||
char* tagStart = c;
|
||||
for (; *c && *c != '\''; c++);
|
||||
c++;
|
||||
char* c0 = c;
|
||||
for (; *c && *c != '\''; c++);
|
||||
|
||||
id name = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
|
||||
|
||||
// Move to tag end
|
||||
BOOL foundEndTag = NO;
|
||||
BOOL foundOpenTag = NO;
|
||||
c++;
|
||||
for (; *c && !foundEndTag; c++)
|
||||
{
|
||||
if (*c == '<') foundOpenTag = YES;
|
||||
else
|
||||
if (*c == '/')
|
||||
{
|
||||
if (!foundOpenTag)
|
||||
{
|
||||
if(c[1] == '>') foundEndTag = YES, c++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startTagChar == c[1])
|
||||
{
|
||||
foundEndTag = YES;
|
||||
// Skip to end of tag
|
||||
for (; *c && *c != '>'; c++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
// Variadic parsing
|
||||
if (c[0] == 'v' && c[1] == 'a' && c[2] == 'r')
|
||||
{
|
||||
if (strncmp(c, "variadic", 8) == 0)
|
||||
{
|
||||
// Skip back to tag start
|
||||
c0 = c;
|
||||
for (; *c0 != '<'; c0--);
|
||||
|
||||
// Tag name starts with 'm' : variadic method
|
||||
// <method variadic='true' selector='alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat:' class_method='true'>
|
||||
if (c0[1] == 'm')
|
||||
{
|
||||
c = c0;
|
||||
id variadicMethodName = nil;
|
||||
// Extract selector name
|
||||
for (; *c != '>'; c++)
|
||||
{
|
||||
if (c[0] == ' ' && c[1] == 's' && c[2] == 'e' && c[3] == 'l')
|
||||
{
|
||||
for (; *c && *c != '\''; c++);
|
||||
c++;
|
||||
c0 = c;
|
||||
for (; *c && *c != '\''; c++);
|
||||
variadicMethodName = [[[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding] autorelease];
|
||||
}
|
||||
}
|
||||
[variadicSelectors setValue:@"true" forKey:variadicMethodName];
|
||||
// NSLog(@"SELECTOR %@", name);
|
||||
}
|
||||
else
|
||||
// Variadic function
|
||||
// <function name='NSBeginAlertSheet' variadic='true'>
|
||||
{
|
||||
[variadicFunctions setValue:@"true" forKey:name];
|
||||
// NSLog(@"function %@", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c0 = tagStart;
|
||||
id value = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
|
||||
|
||||
[hash setValue:value forKey:name];
|
||||
[value release];
|
||||
[name release];
|
||||
}
|
||||
}
|
||||
}
|
||||
// double t1 = CFAbsoluteTimeGetCurrent();
|
||||
// NSLog(@"BridgeSupport %@ parsed in %f", [[path lastPathComponent] stringByDeletingPathExtension], t1-t0);
|
||||
#ifdef __OBJC_GC__
|
||||
[[NSGarbageCollector defaultCollector] enableCollectorForPointer:originalC];
|
||||
#endif
|
||||
[paths addObject:path];
|
||||
[xmlDocuments addObject:xmlDocument];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isBridgeSupportLoaded:(NSString*)path
|
||||
{
|
||||
NSUInteger idx = [self bridgeSupportIndexForString:path];
|
||||
return idx == NSNotFound ? NO : YES;
|
||||
}
|
||||
|
||||
//
|
||||
// bridgeSupportIndexForString
|
||||
// given 'AppKit', return index of '/System/Library/Frameworks/AppKit.framework/Versions/C/Resources/BridgeSupport/AppKitFull.bridgesupport'
|
||||
//
|
||||
- (NSUInteger)bridgeSupportIndexForString:(NSString*)string
|
||||
{
|
||||
NSUInteger i, l = [paths count];
|
||||
for (i=0; i<l; i++)
|
||||
{
|
||||
NSString* path = [paths objectAtIndex:i];
|
||||
NSRange range = [path rangeOfString:string];
|
||||
|
||||
if (range.location != NSNotFound) return range.location;
|
||||
}
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary*)variadicSelectors
|
||||
{
|
||||
return variadicSelectors;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary*)variadicFunctions
|
||||
{
|
||||
return variadicFunctions;
|
||||
}
|
||||
|
||||
- (NSArray*)keys
|
||||
{
|
||||
[hash removeObjectForKey:@"NSProxy"];
|
||||
[hash removeObjectForKey:@"NSProtocolChecker"];
|
||||
[hash removeObjectForKey:@"NSDistantObject"];
|
||||
|
||||
return [hash allKeys];
|
||||
}
|
||||
|
||||
|
||||
- (NSString*)queryName:(NSString*)name
|
||||
{
|
||||
return [hash valueForKey:name];
|
||||
}
|
||||
- (NSString*)queryName:(NSString*)name type:(NSString*)type
|
||||
{
|
||||
id v = [self queryName:name];
|
||||
if (!v) return nil;
|
||||
|
||||
char* c = (char*)[v UTF8String];
|
||||
// Skip tag start
|
||||
c++;
|
||||
char* c0 = c;
|
||||
for (; *c && *c != ' '; c++);
|
||||
id extractedType = [[NSString alloc] initWithBytes:c0 length:c-c0 encoding:NSUTF8StringEncoding];
|
||||
[extractedType autorelease];
|
||||
// NSLog(@"extractedType=%@", extractedType);
|
||||
|
||||
if (![extractedType isEqualToString:type]) return nil;
|
||||
return v;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
11
JSCocoa/JSCocoa.h
Normal file
11
JSCocoa/JSCocoa.h
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// JSCocoa.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 16/12/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
#define JSCOCOA
|
||||
#import "JSCocoaController.h"
|
359
JSCocoa/JSCocoaController.h
Normal file
359
JSCocoa/JSCocoaController.h
Normal file
@ -0,0 +1,359 @@
|
||||
//
|
||||
// JSCocoa.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 09/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#define MACOSX
|
||||
#import <ffi/ffi.h>
|
||||
#endif
|
||||
#import "BridgeSupportController.h"
|
||||
#import "JSCocoaPrivateObject.h"
|
||||
#import "JSCocoaFFIArgument.h"
|
||||
#import "JSCocoaFFIClosure.h"
|
||||
|
||||
|
||||
// JS value container, used by methods wanting a straight JSValue and not a converted JS->ObjC value.
|
||||
struct JSValueRefAndContextRef
|
||||
{
|
||||
JSValueRef value;
|
||||
JSContextRef ctx;
|
||||
};
|
||||
typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import "iPhone/libffi/ffi.h"
|
||||
#import "iPhone/BurksPool.h"
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// JSCocoaController
|
||||
//
|
||||
@interface JSCocoaController : NSObject {
|
||||
|
||||
JSGlobalContextRef ctx;
|
||||
BOOL ownsContext;
|
||||
id _delegate;
|
||||
|
||||
//
|
||||
// Split call
|
||||
// Allows calling multi param ObjC messages with a jQuery-like syntax.
|
||||
//
|
||||
// obj.do({ this : 'hello', andThat : 'world' })
|
||||
// instead of
|
||||
// obj.dothis_andThat_('hello', 'world')
|
||||
//
|
||||
BOOL useSplitCall;
|
||||
|
||||
// JSLint : used for ObjJ syntax, class syntax, return if
|
||||
BOOL useJSLint;
|
||||
|
||||
// Auto call zero arg methods : allow NSWorkspace.sharedWorkspace instead of NSWorkspace.sharedWorkspace()
|
||||
BOOL useAutoCall;
|
||||
// Allow setting javascript values on boxed objects (which are collected after nulling all references to them)
|
||||
BOOL canSetOnBoxedObjects;
|
||||
// Allow calling obj.method(...) instead of obj.method_(...)
|
||||
BOOL callSelectorsMissingTrailingSemicolon;
|
||||
|
||||
// Log all exceptions to NSLog, even if they're caught later by downstream Javascript (in f(g()), log even if f catches after g threw)
|
||||
BOOL logAllExceptions;
|
||||
|
||||
//
|
||||
// Safe dealloc (For ObjC classes written in Javascript)
|
||||
// - (void)dealloc cannot be overloaded as it is called during JS GC, which forbids new JS code execution.
|
||||
// As the js dealloc method cannot be called, safe dealloc allows it to be executed during the next run loop cycle
|
||||
// NOTE : upon destroying a JSCocoaController, safe dealloc is disabled
|
||||
//
|
||||
BOOL useSafeDealloc;
|
||||
|
||||
|
||||
NSMutableDictionary* boxedObjects;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@property (assign) id delegate;
|
||||
@property BOOL useSafeDealloc, useSplitCall, useJSLint, useAutoCall, callSelectorsMissingTrailingSemicolon, canSetOnBoxedObjects, logAllExceptions;
|
||||
|
||||
|
||||
- (id)init;
|
||||
- (id)initWithGlobalContext:(JSGlobalContextRef)ctx;
|
||||
|
||||
+ (id)sharedController;
|
||||
+ (id)controllerFromContext:(JSContextRef)ctx;
|
||||
+ (BOOL)hasSharedController;
|
||||
- (JSGlobalContextRef)ctx;
|
||||
+ (void)hazardReport;
|
||||
+ (NSString*)runningArchitecture;
|
||||
+ (void)updateCustomCallPaths;
|
||||
- (void)accomodateWebKitInspector;
|
||||
|
||||
//
|
||||
// Evaluation
|
||||
//
|
||||
- (id)eval:(NSString*)script;
|
||||
- (id)callFunction:(NSString*)name;
|
||||
- (id)callFunction:(NSString*)name withArguments:(NSArray*)arguments;
|
||||
- (BOOL)hasFunction:(NSString*)name;
|
||||
- (BOOL)isSyntaxValid:(NSString*)script;
|
||||
|
||||
- (BOOL)evalJSFile:(NSString*)path;
|
||||
- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue;
|
||||
- (JSValueRef)evalJSString:(NSString*)script;
|
||||
- (JSValueRef)evalJSString:(NSString*)script withScriptPath:(NSString*)path;
|
||||
- (JSValueRef)callJSFunction:(JSValueRef)function withArguments:(NSArray*)arguments;
|
||||
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArguments:arguments, ... NS_REQUIRES_NIL_TERMINATION;
|
||||
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArgumentsArray:(NSArray*)arguments;
|
||||
- (JSObjectRef)JSFunctionNamed:(NSString*)functionName;
|
||||
- (BOOL)hasJSFunctionNamed:(NSString*)functionName;
|
||||
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path;
|
||||
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path errors:(NSMutableArray*)array;
|
||||
- (BOOL)isSyntaxValid:(NSString*)script error:(NSString**)error;
|
||||
- (BOOL)setObject:(id)object withName:(NSString*)name;
|
||||
- (BOOL)setObject:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
|
||||
- (BOOL)setObjectNoRetain:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
|
||||
- (id)objectWithName:(NSString*)name;
|
||||
- (BOOL)removeObjectWithName:(NSString*)name;
|
||||
// Get ObjC and raw values from Javascript
|
||||
- (id)unboxJSValueRef:(JSValueRef)jsValue;
|
||||
- (BOOL)toBool:(JSValueRef)value;
|
||||
- (double)toDouble:(JSValueRef)value;
|
||||
- (int)toInt:(JSValueRef)value;
|
||||
- (NSString*)toString:(JSValueRef)value;
|
||||
// Wrapper for unboxJSValueRef
|
||||
- (id)toObject:(JSValueRef)value;
|
||||
|
||||
|
||||
//
|
||||
// Framework
|
||||
//
|
||||
- (BOOL)loadFrameworkWithName:(NSString*)name;
|
||||
- (BOOL)loadFrameworkWithName:(NSString*)frameworkName inPath:(NSString*)path;
|
||||
|
||||
//
|
||||
// Garbage collection
|
||||
//
|
||||
+ (void)garbageCollect;
|
||||
- (void)garbageCollect;
|
||||
- (void)unlinkAllReferences;
|
||||
+ (void)upJSCocoaPrivateObjectCount;
|
||||
+ (void)downJSCocoaPrivateObjectCount;
|
||||
+ (int)JSCocoaPrivateObjectCount;
|
||||
|
||||
+ (void)upJSValueProtectCount;
|
||||
+ (void)downJSValueProtectCount;
|
||||
+ (int)JSValueProtectCount;
|
||||
|
||||
+ (void)logInstanceStats;
|
||||
- (id)instanceStats;
|
||||
- (void)logBoxedObjects;
|
||||
|
||||
//
|
||||
// Class inspection (shortcuts to JSCocoaLib)
|
||||
//
|
||||
+ (id)rootclasses;
|
||||
+ (id)classes;
|
||||
+ (id)protocols;
|
||||
+ (id)imageNames;
|
||||
+ (id)methods;
|
||||
+ (id)runtimeReport;
|
||||
+ (id)explainMethodEncoding:(id)encoding;
|
||||
|
||||
//
|
||||
// Class handling
|
||||
//
|
||||
+ (BOOL)overloadInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
|
||||
+ (BOOL)overloadClassMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext;
|
||||
|
||||
+ (BOOL)addClassMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext encoding:(char*)encoding;
|
||||
+ (BOOL)addInstanceMethod:(NSString*)methodName class:(Class)class jsFunction:(JSValueRefAndContextRef)valueAndContext encoding:(char*)encoding;
|
||||
|
||||
// Tests
|
||||
- (int)runTests:(NSString*)path;
|
||||
- (int)runTests:(NSString*)path withSelector:(SEL)sel;
|
||||
|
||||
//
|
||||
// Autorelease pool
|
||||
//
|
||||
+ (void)allocAutoreleasePool;
|
||||
+ (void)deallocAutoreleasePool;
|
||||
|
||||
//
|
||||
// Boxing : each object gets only one box, stored in boxedObjects
|
||||
//
|
||||
//+ (JSObjectRef)boxedJSObject:(id)o inContext:(JSContextRef)ctx;
|
||||
- (JSObjectRef)boxObject:(id)o;
|
||||
- (BOOL)isObjectBoxed:(id)o;
|
||||
- (void)deleteBoxOfObject:(id)o;
|
||||
//+ (void)downBoxedJSObjectCount:(id)o;
|
||||
|
||||
|
||||
//
|
||||
// Various internals
|
||||
//
|
||||
//+ (JSObjectRef)jsCocoaPrivateObjectInContext:(JSContextRef)ctx;
|
||||
- (JSObjectRef)newPrivateObject;
|
||||
- (JSObjectRef)newPrivateFunction;
|
||||
+ (NSMutableArray*)parseObjCMethodEncoding:(const char*)typeEncoding;
|
||||
+ (NSMutableArray*)parseCFunctionEncoding:(NSString*)xml functionName:(NSString**)functionNamePlaceHolder;
|
||||
|
||||
//+ (void)ensureJSValueIsObjectAfterInstanceAutocall:(JSValueRef)value inContext:(JSContextRef)ctx;
|
||||
- (NSString*)formatJSException:(JSValueRef)exception;
|
||||
- (id)selectorForJSFunction:(JSObjectRef)function;
|
||||
|
||||
|
||||
- (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
|
||||
+ (const char*)typeEncodingOfMethod:(NSString*)methodName class:(NSString*)className;
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// JSCocoa delegate methods
|
||||
//
|
||||
|
||||
//
|
||||
// Error reporting
|
||||
//
|
||||
@interface NSObject (JSCocoaControllerDelegateMethods)
|
||||
- (void) JSCocoa:(JSCocoaController*)controller hadError:(NSString*)error onLineNumber:(NSInteger)lineNumber atSourceURL:(id)url;
|
||||
- (void) safeDealloc;
|
||||
|
||||
//
|
||||
// Getting
|
||||
//
|
||||
// Check if getting property is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canGetProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for getting properties
|
||||
// Return a custom JSValueRef to bypass JSCocoa
|
||||
// Return NULL to let JSCocoa handle getProperty
|
||||
// Return JSValueMakeNull() to return a Javascript null
|
||||
- (JSValueRef) JSCocoa:(JSCocoaController*)controller getProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Setting
|
||||
//
|
||||
// Check if setting property is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canSetProperty:(NSString*)propertyName ofObject:(id)object toValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for setting properties
|
||||
// Return YES to indicate you handled setting
|
||||
// Return NO to let JSCocoa handle setProperty
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller setProperty:(NSString*)propertyName ofObject:(id)object toValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Calling
|
||||
//
|
||||
// Check if calling a C function is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canCallFunction:(NSString*)functionName argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Check if calling an ObjC method is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canCallMethod:(NSString*)methodName ofObject:(id)object argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for calling
|
||||
// Return YES to indicate you handled calling
|
||||
// Return NO to let JSCocoa handle calling
|
||||
- (JSValueRef) JSCocoa:(JSCocoaController*)controller callMethod:(NSString*)methodName ofObject:(id)callee privateObject:(JSCocoaPrivateObject*)thisPrivateObject argumentCount:(size_t)argumentCount arguments:(JSValueRef*)arguments inContext:(JSContextRef)localCtx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Getting global properties (classes, structures, C function names, enums via OSXObject_getProperty)
|
||||
//
|
||||
// Check if getting property is allowed
|
||||
- (BOOL) JSCocoa:(JSCocoaController*)controller canGetGlobalProperty:(NSString*)propertyName inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
// Custom handler for getting properties
|
||||
// Return a custom JSValueRef to bypass JSCocoa
|
||||
// Return NULL to let JSCocoa handle getProperty
|
||||
// Return JSValueMakeNull() to return a Javascript null
|
||||
- (JSValueRef) JSCocoa:(JSCocoaController*)controller getGlobalProperty:(NSString*)propertyName inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Returning values to Javascript
|
||||
//
|
||||
// Called before returning any value to Javascript : return a new value or the original one
|
||||
//- (JSValueRef) JSCocoa:(JSCocoaController*)controller willReturnValue:(JSValueRef)value inContext:(JSContextRef)ctx exception:(JSValueRef*)exception;
|
||||
|
||||
//
|
||||
// Evaling
|
||||
//
|
||||
// Check if file can be loaded
|
||||
- (BOOL)JSCocoa:(JSCocoaController*)controller canLoadJSFile:(NSString*)path;
|
||||
// Check if script can be evaluated
|
||||
- (BOOL)JSCocoa:(JSCocoaController*)controller canEvaluateScript:(NSString*)script;
|
||||
// Called before evalJSString, used to modify script about to be evaluated
|
||||
// Return a custom NSString (eg a macro expanded version of the source)
|
||||
// Return NULL to let JSCocoa handle evaluation
|
||||
- (NSString*)JSCocoa:(JSCocoaController*)controller willEvaluateScript:(NSString*)script;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// JSCocoa shorthand
|
||||
//
|
||||
@interface JSCocoa : JSCocoaController
|
||||
@end
|
||||
|
||||
//
|
||||
// Boxed object cache : holds one JSObjectRef for each reference to a pointer to an ObjC object
|
||||
//
|
||||
@interface BoxedJSObject : NSObject {
|
||||
JSObjectRef jsObject;
|
||||
}
|
||||
- (void)setJSObject:(JSObjectRef)o;
|
||||
- (JSObjectRef)jsObject;
|
||||
|
||||
@end
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
id NSStringFromJSValue(JSContextRef ctx, JSValueRef value);
|
||||
//void* malloc_autorelease(size_t size);
|
||||
|
||||
// Convert values between contexts (eg user context and webkit page context)
|
||||
JSValueRef valueToExternalContext(JSContextRef ctx, JSValueRef value, JSContextRef externalCtx);
|
||||
|
||||
// valueOf() is called by Javascript on objects, eg someObject + ' someString'
|
||||
JSValueRef valueOfCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception);
|
||||
|
||||
//
|
||||
// From PyObjC : when to call objc_msgSend_stret, for structure return
|
||||
// Depending on structure size & architecture, structures are returned as function first argument (done transparently by ffi) or via registers
|
||||
//
|
||||
|
||||
#if defined(__ppc__)
|
||||
# define SMALL_STRUCT_LIMIT 4
|
||||
#elif defined(__ppc64__)
|
||||
# define SMALL_STRUCT_LIMIT 8
|
||||
#elif defined(__i386__)
|
||||
# define SMALL_STRUCT_LIMIT 8
|
||||
#elif defined(__x86_64__)
|
||||
# define SMALL_STRUCT_LIMIT 16
|
||||
#elif TARGET_OS_IPHONE
|
||||
// TOCHECK
|
||||
# define SMALL_STRUCT_LIMIT 4
|
||||
#else
|
||||
# error "Unsupported MACOSX platform"
|
||||
#endif
|
||||
|
||||
|
||||
// Stored in boxedobjects to access a list of methods, properties, ...
|
||||
#define RuntimeInformationPropertyName "info"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Some more doc
|
||||
|
||||
__jsHash
|
||||
__jsCocoaController
|
||||
Instance variables set on ObjC classes written in Javascript.
|
||||
These variables enable classes to store Javascript values in them.
|
||||
|
||||
*/
|
||||
|
||||
|
5035
JSCocoa/JSCocoaController.m
Normal file
5035
JSCocoa/JSCocoaController.m
Normal file
File diff suppressed because it is too large
Load Diff
97
JSCocoa/JSCocoaFFIArgument.h
Normal file
97
JSCocoa/JSCocoaFFIArgument.h
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// JSCocoaFFIArgument.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 14/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#define MACOSX
|
||||
#include <ffi/ffi.h>
|
||||
#endif
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import "iPhone/libffi/ffi.h"
|
||||
#endif
|
||||
|
||||
@interface JSCocoaFFIArgument : NSObject {
|
||||
char typeEncoding;
|
||||
NSString* structureTypeEncoding;
|
||||
NSString* pointerTypeEncoding;
|
||||
|
||||
void* ptr;
|
||||
|
||||
ffi_type structureType;
|
||||
|
||||
id customData;
|
||||
BOOL isReturnValue;
|
||||
BOOL ownsStorage;
|
||||
BOOL isOutArgument;
|
||||
}
|
||||
|
||||
- (NSString*)typeDescription;
|
||||
|
||||
- (BOOL)setTypeEncoding:(char)encoding;
|
||||
- (BOOL)setTypeEncoding:(char)encoding withCustomStorage:(void*)storagePtr;
|
||||
- (void)setStructureTypeEncoding:(NSString*)encoding;
|
||||
- (void)setStructureTypeEncoding:(NSString*)encoding withCustomStorage:(void*)storagePtr;
|
||||
- (void)setPointerTypeEncoding:(NSString*)encoding;
|
||||
|
||||
+ (int)sizeOfTypeEncoding:(char)encoding;
|
||||
+ (int)alignmentOfTypeEncoding:(char)encoding;
|
||||
|
||||
+ (ffi_type*)ffi_typeForTypeEncoding:(char)encoding;
|
||||
|
||||
+ (int)sizeOfStructure:(NSString*)encoding;
|
||||
|
||||
|
||||
+ (NSArray*)typeEncodingsFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
|
||||
+ (NSArray*)typeEncodingsFromStructureTypeEncoding:(NSString*)structureTypeEncoding parsedCount:(NSInteger*)count;
|
||||
|
||||
|
||||
+ (NSString*)structureNameFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
|
||||
+ (NSString*)structureFullTypeEncodingFromStructureTypeEncoding:(NSString*)structureTypeEncoding;
|
||||
+ (NSString*)structureFullTypeEncodingFromStructureName:(NSString*)structureName;
|
||||
+ (NSString*)structureTypeEncodingDescription:(NSString*)structureTypeEncoding;
|
||||
|
||||
+ (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
|
||||
|
||||
+ (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx typeEncoding:(char)typeEncoding fullTypeEncoding:(NSString*)fullTypeEncoding fromStorage:(void*)ptr;
|
||||
|
||||
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)storage;
|
||||
+ (NSInteger)structureToJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx fromCString:(char*)c fromStorage:(void**)ptr initialValues:(JSValueRef*)initialValues initialValueCount:(NSInteger)initialValueCount convertedValueCount:(NSInteger*)convertedValueCount;
|
||||
+ (NSInteger)structureFromJSObjectRef:(JSObjectRef)value inContext:(JSContextRef)ctx inParentJSValueRef:(JSValueRef)parentValue fromCString:(char*)c fromStorage:(void**)ptr;
|
||||
|
||||
+ (void)alignPtr:(void**)ptr accordingToEncoding:(char)encoding;
|
||||
+ (void)advancePtr:(void**)ptr accordingToEncoding:(char)encoding;
|
||||
|
||||
|
||||
- (void*)allocateStorage;
|
||||
- (void*)allocatePointerStorage;
|
||||
- (void**)storage;
|
||||
- (void**)rawStoragePointer;
|
||||
- (char)typeEncoding;
|
||||
- (NSString*)structureTypeEncoding;
|
||||
- (id)pointerTypeEncoding;
|
||||
|
||||
|
||||
- (void)setIsReturnValue:(BOOL)v;
|
||||
- (BOOL)isReturnValue;
|
||||
- (void)setIsOutArgument:(BOOL)v;
|
||||
- (BOOL)isOutArgument;
|
||||
|
||||
- (BOOL)fromJSValueRef:(JSValueRef)value inContext:(JSContextRef)ctx;
|
||||
- (BOOL)toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx;
|
||||
|
||||
|
||||
+ (BOOL)boxObject:(id)o toJSValueRef:(JSValueRef*)value inContext:(JSContextRef)ctx;
|
||||
+ (BOOL)unboxJSValueRef:(JSValueRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
|
||||
+ (BOOL)unboxJSArray:(JSObjectRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
|
||||
+ (BOOL)unboxJSHash:(JSObjectRef)value toObject:(id*)o inContext:(JSContextRef)ctx;
|
||||
|
||||
|
||||
- (ffi_type*)ffi_type;
|
||||
|
||||
@end
|
1357
JSCocoa/JSCocoaFFIArgument.m
Normal file
1357
JSCocoa/JSCocoaFFIArgument.m
Normal file
File diff suppressed because it is too large
Load Diff
45
JSCocoa/JSCocoaFFIClosure.h
Normal file
45
JSCocoa/JSCocoaFFIClosure.h
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// JSCocoaFFIClosure.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 29/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#define MACOSX
|
||||
#import <ffi/ffi.h>
|
||||
#endif
|
||||
#import "JSCocoaFFIArgument.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import "iPhone/libffi/ffi.h"
|
||||
#endif
|
||||
|
||||
|
||||
@interface JSCocoaFFIClosure : NSObject {
|
||||
|
||||
JSValueRef jsFunction;
|
||||
// ##UNSURE This might cause a crash if we're registered in a non global context that will have been destroyed when we JSValueUnprotect the function
|
||||
JSContextRef ctx;
|
||||
|
||||
ffi_cif cif;
|
||||
#if !TARGET_OS_IPHONE
|
||||
ffi_closure* closure;
|
||||
#endif
|
||||
ffi_type** argTypes;
|
||||
|
||||
NSMutableArray* encodings;
|
||||
|
||||
JSObjectRef jsThisObject;
|
||||
|
||||
BOOL isObjC;
|
||||
}
|
||||
|
||||
- (IMP)setJSFunction:(JSValueRef)fn inContext:(JSContextRef)ctx argumentEncodings:(NSMutableArray*)argumentEncodings objC:(BOOL)objC;
|
||||
- (void*)functionPointer;
|
||||
- (void)calledByClosureWithArgs:(void**)args returnValue:(void*)returnValue;
|
||||
|
||||
@end
|
213
JSCocoa/JSCocoaFFIClosure.m
Normal file
213
JSCocoa/JSCocoaFFIClosure.m
Normal file
@ -0,0 +1,213 @@
|
||||
//
|
||||
// JSCocoaFFIClosure.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 29/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSCocoaFFIClosure.h"
|
||||
#import "JSCocoaController.h"
|
||||
#include <sys/mman.h> // for mmap()
|
||||
|
||||
@implementation JSCocoaFFIClosure
|
||||
|
||||
|
||||
//
|
||||
// Common closure function, calling back closure object
|
||||
//
|
||||
void closure_function(ffi_cif* cif, void* resp, void** args, void* userdata)
|
||||
{
|
||||
[(id)userdata calledByClosureWithArgs:args returnValue:resp];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
argTypes = NULL;
|
||||
encodings = NULL;
|
||||
jsFunction = NULL;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//
|
||||
// Cleanup : called by dealloc and finalize
|
||||
//
|
||||
- (void)cleanUp
|
||||
{
|
||||
if (encodings) [encodings release];
|
||||
if (argTypes) free(argTypes);
|
||||
|
||||
if (jsFunction)
|
||||
{
|
||||
JSValueUnprotect(ctx, jsFunction);
|
||||
[JSCocoaController downJSValueProtectCount];
|
||||
}
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (munmap(closure, sizeof(closure)) == -1) NSLog(@"ffi closure munmap failed");
|
||||
#endif
|
||||
}
|
||||
- (void)dealloc
|
||||
{
|
||||
// NSLog(@"deallocing closure %p IMP=%p", self, closure);
|
||||
[self cleanUp];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
[self cleanUp];
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
- (void*)functionPointer
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
return closure;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Bind a js function to closure. We'll jsValueProtect that function from GC.
|
||||
//
|
||||
- (IMP)setJSFunction:(JSValueRef)fn inContext:(JSContextRef)context argumentEncodings:(NSMutableArray*)argumentEncodings objC:(BOOL)objC
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
if ([argumentEncodings count] == 0) return NULL;
|
||||
|
||||
encodings = argumentEncodings;
|
||||
[encodings retain];
|
||||
isObjC = objC;
|
||||
|
||||
unsigned int i, argumentCount = (unsigned int)([argumentEncodings count]-1);
|
||||
argTypes = malloc(sizeof(ffi_type*)*argumentCount);
|
||||
for (i=0; i<argumentCount; i++)
|
||||
{
|
||||
JSCocoaFFIArgument* arg = [argumentEncodings objectAtIndex:i+1];
|
||||
argTypes[i] = [arg ffi_type];
|
||||
}
|
||||
if ((closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)) == (void*)-1)
|
||||
{
|
||||
NSLog(@"ffi closure mmap failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id returnValue = [argumentEncodings objectAtIndex:0];
|
||||
ffi_status prep_status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argumentCount, [returnValue ffi_type], argTypes);
|
||||
if (prep_status != FFI_OK)
|
||||
{
|
||||
NSLog(@"ffi_prep_cif failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ffi_prep_closure(closure, &cif, closure_function, (void *)self) != FFI_OK)
|
||||
{
|
||||
NSLog(@"ffi_prep_closure failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1)
|
||||
{
|
||||
NSLog(@"ffi closure mprotect failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jsFunction = fn;
|
||||
ctx = context;
|
||||
|
||||
// Protect function from GC
|
||||
JSValueProtect(ctx, jsFunction);
|
||||
[JSCocoaController upJSValueProtectCount];
|
||||
|
||||
return (IMP)closure;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Called by ffi
|
||||
//
|
||||
- (void)calledByClosureWithArgs:(void**)closureArgs returnValue:(void*)returnValue
|
||||
{
|
||||
JSObjectRef jsFunctionObject = JSValueToObject(ctx, jsFunction, NULL);
|
||||
JSValueRef exception = NULL;
|
||||
|
||||
// ## Only objC for now. Need to test C function pointers.
|
||||
|
||||
// Argument count is encodings count minus return value
|
||||
NSUInteger i, idx = 0, effectiveArgumentCount = [encodings count]-1;
|
||||
// Skip self and selector
|
||||
if (isObjC)
|
||||
{
|
||||
effectiveArgumentCount -= 2;
|
||||
idx = 2;
|
||||
}
|
||||
// Convert arguments
|
||||
JSValueRef* args = NULL;
|
||||
if (effectiveArgumentCount)
|
||||
{
|
||||
args = malloc(effectiveArgumentCount*sizeof(JSValueRef));
|
||||
for (i=0; i<effectiveArgumentCount; i++, idx++)
|
||||
{
|
||||
// +1 to skip return value
|
||||
id encodingObject = [encodings objectAtIndex:idx+1];
|
||||
|
||||
id arg = [[JSCocoaFFIArgument alloc] init];
|
||||
char encoding = [encodingObject typeEncoding];
|
||||
if (encoding == '{') [arg setStructureTypeEncoding:[encodingObject structureTypeEncoding] withCustomStorage:*(void**)&closureArgs[idx]];
|
||||
else [arg setTypeEncoding:[encodingObject typeEncoding] withCustomStorage:closureArgs[idx]];
|
||||
|
||||
args[i] = NULL;
|
||||
[arg toJSValueRef:&args[i] inContext:ctx];
|
||||
[arg release];
|
||||
}
|
||||
}
|
||||
|
||||
JSObjectRef jsThis = NULL;
|
||||
|
||||
// Create 'this'
|
||||
if (isObjC)
|
||||
jsThis = [[JSCocoa controllerFromContext:ctx] boxObject:*(void**)closureArgs[0]];
|
||||
|
||||
// Call !
|
||||
JSValueRef jsReturnValue = JSObjectCallAsFunction(ctx, jsFunctionObject, jsThis, effectiveArgumentCount, args, &exception);
|
||||
|
||||
// Convert return value if it's not void
|
||||
char encoding = [[encodings objectAtIndex:0] typeEncoding];
|
||||
if (jsReturnValue && encoding != 'v')
|
||||
{
|
||||
[JSCocoaFFIArgument fromJSValueRef:jsReturnValue inContext:ctx typeEncoding:encoding fullTypeEncoding:[[encodings objectAtIndex:0] structureTypeEncoding] fromStorage:returnValue];
|
||||
#ifdef __BIG_ENDIAN__
|
||||
// As ffi always uses a sizeof(long) return value (even for chars and shorts), do some shifting
|
||||
int size = [JSCocoaFFIArgument sizeOfTypeEncoding:encoding];
|
||||
int paddedSize = sizeof(long);
|
||||
long v;
|
||||
if (size > 0 && size < paddedSize && paddedSize == 4)
|
||||
{
|
||||
v = *(long*)returnValue;
|
||||
v = CFSwapInt32(v);
|
||||
*(long*)returnValue = v;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (effectiveArgumentCount) free(args);
|
||||
if (exception)
|
||||
{
|
||||
@throw [NSException exceptionWithName:@"JSCocoa exception"
|
||||
reason:[[JSCocoaController controllerFromContext:ctx] formatJSException:exception]
|
||||
userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
98
JSCocoa/JSCocoaLib.h
Normal file
98
JSCocoa/JSCocoaLib.h
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// JSCocoaLib.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 21/12/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
#import "JSCocoa.h"
|
||||
|
||||
@class JSCocoaMemoryBuffer;
|
||||
|
||||
@interface JSCocoaOutArgument : NSObject
|
||||
{
|
||||
JSCocoaFFIArgument* arg;
|
||||
JSCocoaMemoryBuffer* buffer;
|
||||
int bufferIndex;
|
||||
}
|
||||
- (BOOL)mateWithJSCocoaFFIArgument:(JSCocoaFFIArgument*)arg;
|
||||
- (JSValueRef)outJSValueRefInContext:(JSContextRef)ctx;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface JSCocoaMemoryBuffer : NSObject
|
||||
{
|
||||
void* buffer;
|
||||
int bufferSize;
|
||||
// NSString holding types
|
||||
id typeString;
|
||||
|
||||
// Indicates whether types are aligned.
|
||||
// types not aligned (DEFAULT)
|
||||
// size('fcf') = 4 + 1 + 4 = 9
|
||||
// types aligned
|
||||
// size('fcf') = 4 + 4(align) + 4 = 12
|
||||
BOOL alignTypes;
|
||||
}
|
||||
+ (id)bufferWithTypes:(id)types;
|
||||
- (id)initWithTypes:(id)types;
|
||||
//- (id)initWithTypes:(id)types andValues:(id)values;
|
||||
//- (id)initWithMemoryBuffers:(id)buffers;
|
||||
|
||||
- (void*)pointerForIndex:(NSUInteger)index;
|
||||
- (char)typeAtIndex:(NSUInteger)index;
|
||||
- (JSValueRef)valueAtIndex:(NSUInteger)index inContext:(JSContextRef)ctx;
|
||||
- (BOOL)setValue:(JSValueRef)jsValue atIndex:(NSUInteger)index inContext:(JSContextRef)ctx;
|
||||
- (NSUInteger)typeCount;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JSCocoaLib : NSObject
|
||||
|
||||
+ (id)rootclasses;
|
||||
+ (id)classes;
|
||||
+ (id)protocols;
|
||||
+ (id)imageNames;
|
||||
+ (id)methods;
|
||||
+ (id)runtimeReport;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@interface NSObject(ClassWalker)
|
||||
+ (id)__classImage;
|
||||
- (id)__classImage;
|
||||
+ (id)__derivationPath;
|
||||
- (id)__derivationPath;
|
||||
+ (NSUInteger)__derivationLevel;
|
||||
- (NSUInteger)__derivationLevel;
|
||||
+ (id)__ownMethods;
|
||||
- (id)__ownMethods;
|
||||
+ (id)__methods;
|
||||
- (id)__methods;
|
||||
+ (id)__subclasses;
|
||||
- (id)__subclasses;
|
||||
+ (id)__subclassTree;
|
||||
- (id)__subclassTree;
|
||||
+ (id)__ownIvars;
|
||||
- (id)__ownIvars;
|
||||
+ (id)__ivars;
|
||||
- (id)__ivars;
|
||||
+ (id)__ownProperties;
|
||||
- (id)__ownProperties;
|
||||
+ (id)__properties;
|
||||
- (id)__properties;
|
||||
+ (id)__ownProtocols;
|
||||
- (id)__ownProtocols;
|
||||
+ (id)__protocols;
|
||||
- (id)__protocols;
|
||||
|
||||
@end
|
830
JSCocoa/JSCocoaLib.m
Normal file
830
JSCocoa/JSCocoaLib.m
Normal file
@ -0,0 +1,830 @@
|
||||
//
|
||||
// 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<l; i++)
|
||||
{
|
||||
int size = [JSCocoaFFIArgument sizeOfTypeEncoding:types[i]];
|
||||
if (size == -1) return NSLog(@"JSCocoaMemoryBuffer initWithTypes : unknown type %c", types[i]), self;
|
||||
bufferSize += size;
|
||||
}
|
||||
|
||||
if (bufferSize == 0) {
|
||||
NSLog(@"initWithTypes has no types");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Malloc
|
||||
// NSLog(@"mallocing %d bytes for %@", bufferSize, typeString);
|
||||
buffer = malloc(bufferSize);
|
||||
memset(buffer, bufferSize, 1);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
[typeString release];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
//
|
||||
// Returns pointer for index without any padding
|
||||
//
|
||||
- (void*)pointerForIndex:(NSUInteger)idx
|
||||
{
|
||||
const char* types = [typeString UTF8String];
|
||||
if (idx >= [typeString length]) return NULL;
|
||||
void* pointedValue = buffer;
|
||||
for (int i=0; i<idx; i++)
|
||||
{
|
||||
// NSLog(@"advancing %c", types[i]);
|
||||
[JSCocoaFFIArgument advancePtr:&pointedValue accordingToEncoding:types[i]];
|
||||
}
|
||||
return pointedValue;
|
||||
}
|
||||
|
||||
- (char)typeAtIndex:(NSUInteger)idx
|
||||
{
|
||||
if (idx >= [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<classCount; i++)
|
||||
{
|
||||
id class = classList[i];
|
||||
const char* name= class_getName(class);
|
||||
if (!name) continue;
|
||||
id className = [NSString stringWithUTF8String:name];
|
||||
|
||||
id superclass = class_getSuperclass(class);
|
||||
id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : @"";
|
||||
|
||||
// Check if this class inherits from NSProxy. isKindOfClass crashes, so use raw ObjC api.
|
||||
BOOL isKindOfNSProxy = NO;
|
||||
id c = class;
|
||||
while (c)
|
||||
{
|
||||
if ([[NSString stringWithUTF8String:class_getName(c)] isEqualToString:@"NSProxy"]) isKindOfNSProxy = YES;
|
||||
c = class_getSuperclass(c);
|
||||
}
|
||||
|
||||
// Skip classes crashing when added to an NSArray
|
||||
if ([className hasPrefix:@"_NSZombie_"]
|
||||
|| [className isEqualToString:@"Object"]
|
||||
|| [superclassName isEqualToString:@"Object"]
|
||||
|| [className isEqualToString:@"NSMessageBuilder"]
|
||||
|| [className isEqualToString:@"NSLeafProxy"]
|
||||
|| [className isEqualToString:@"__NSGenericDeallocHandler"]
|
||||
|| isKindOfNSProxy
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
[classArray addObject:class];
|
||||
}
|
||||
|
||||
free(classList);
|
||||
return classArray;
|
||||
}
|
||||
|
||||
+ (NSArray*)rootclasses
|
||||
{
|
||||
id classes = [self classes];
|
||||
NSMutableArray* classArray = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
{
|
||||
id superclass = class_getSuperclass(class);
|
||||
if (superclass) continue;
|
||||
|
||||
[classArray addObject:class];
|
||||
}
|
||||
return classArray;
|
||||
}
|
||||
|
||||
//
|
||||
// Return an array of { name : imageName, classNames : [className, className, ...] }
|
||||
//
|
||||
+ (id)imageNames
|
||||
{
|
||||
id array = [NSMutableArray array];
|
||||
|
||||
unsigned int imageCount;
|
||||
const char** imageNames = objc_copyImageNames(&imageCount);
|
||||
|
||||
for (int i=0; i<imageCount; i++)
|
||||
{
|
||||
const char* cname = imageNames[i];
|
||||
|
||||
// Gather image class names
|
||||
id array2 = [NSMutableArray array];
|
||||
unsigned int classCount;
|
||||
const char** classNames = objc_copyClassNamesForImage(cname, &classCount);
|
||||
for (int j=0; j<classCount; j++)
|
||||
[array2 addObject:[NSString stringWithUTF8String:classNames[j]]];
|
||||
|
||||
free(classNames);
|
||||
|
||||
// Hash of name and classNames
|
||||
id name = [NSString stringWithUTF8String:cname];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
array2, @"classNames",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
free(imageNames);
|
||||
return array;
|
||||
}
|
||||
|
||||
//
|
||||
// Return protocols and their associated methods
|
||||
//
|
||||
+ (id)protocols
|
||||
{
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
id array = [NSMutableArray array];
|
||||
unsigned int protocolCount;
|
||||
Protocol** protocols = objc_copyProtocolList(&protocolCount);
|
||||
|
||||
for (int i=0; i<protocolCount; i++)
|
||||
{
|
||||
// array2 is modified by the following block
|
||||
__block id array2 = [NSMutableArray array];
|
||||
Protocol* p = protocols[i];
|
||||
|
||||
// Common block for copying protocol method descriptions
|
||||
void (^b)(BOOL, BOOL) = ^(BOOL isRequiredMethod, BOOL isInstanceMethod) {
|
||||
unsigned int descriptionCount;
|
||||
struct objc_method_description* methodDescriptions = protocol_copyMethodDescriptionList(p, isRequiredMethod, isInstanceMethod, &descriptionCount);
|
||||
for (int j=0; j<descriptionCount; j++)
|
||||
{
|
||||
struct objc_method_description d = methodDescriptions[j];
|
||||
|
||||
id name = NSStringFromSelector(d.name);
|
||||
id encoding = [NSString stringWithUTF8String:d.types];
|
||||
id isRequired = [NSNumber numberWithBool:isRequiredMethod];
|
||||
id type = isInstanceMethod ? @"instance" : @"class";
|
||||
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
encoding, @"encoding",
|
||||
isRequired, @"isRequired",
|
||||
type, @"type",
|
||||
nil];
|
||||
|
||||
[array2 addObject:hash];
|
||||
}
|
||||
if (methodDescriptions) free(methodDescriptions);
|
||||
};
|
||||
|
||||
// Copy all methods, going through required, non-required, class, instance methods
|
||||
b(YES, YES);
|
||||
b(YES, NO);
|
||||
b(NO, YES);
|
||||
b(NO, NO);
|
||||
|
||||
// Main object : { name : protocolName, methods : [{ name, encoding, isRequired, type }, ...]
|
||||
id name = [NSString stringWithUTF8String:protocol_getName(p)];
|
||||
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
array2, @"methods",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
free(protocols);
|
||||
return array;
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (id)methods
|
||||
{
|
||||
id classes = [self classes];
|
||||
id methods = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[methods addObjectsFromArray:[class __ownMethods]];
|
||||
return methods;
|
||||
}
|
||||
|
||||
//
|
||||
// Runtime report
|
||||
// Report EVERYTHING
|
||||
// classes
|
||||
// { className : { name
|
||||
// superclassName
|
||||
// derivationPath
|
||||
// subclasses
|
||||
// methods
|
||||
// protocols
|
||||
// ivars
|
||||
// properties
|
||||
// }
|
||||
// protocols
|
||||
// { protocolName : { name
|
||||
// methods
|
||||
// }
|
||||
// imageNames
|
||||
// { imageName : { name
|
||||
// classNames : [className1, className2, ...]
|
||||
// }
|
||||
//
|
||||
+ (id)runtimeReport
|
||||
{
|
||||
/*
|
||||
id classList = [self classes];
|
||||
id protocols = [self protocols];
|
||||
id imageNames = [self imageNames];
|
||||
|
||||
id classes = [NSMutableDictionary dictionary];
|
||||
int classCount = [classList count];
|
||||
// for (id class in classList)
|
||||
for (int i=0; i<classCount; i++)
|
||||
{
|
||||
id class = [classList objectAtIndex:i];
|
||||
id className = [class description];
|
||||
NSLog(@"%d/%d %@", i, (classCount-1), className);
|
||||
|
||||
id superclass = [class superclass];
|
||||
id superclassName = superclass ? [NSString stringWithUTF8String:class_getName(superclass)] : nil;
|
||||
//NSLog(@"%@ (%d/%d)", className, i, classCount-1);
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
className, @"name",
|
||||
superclassName, @"superclassName",
|
||||
[class __derivationPath], @"derivationPath",
|
||||
[class __methods], @"methods",
|
||||
[class __protocols], @"protocols",
|
||||
[class __ivars], @"ivars",
|
||||
[class __properties], @"properties",
|
||||
nil];
|
||||
[classes setObject:hash forKey:className];
|
||||
}
|
||||
|
||||
id dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
classes, @"classes",
|
||||
protocols, @"protocols",
|
||||
imageNames, @"imageNames",
|
||||
nil];
|
||||
*/
|
||||
// This happens on the ObjC side, NOT in jsc.
|
||||
// There are 2500 classes to dump, this takes a while.
|
||||
// The memory hog is also on the ObjC side, happening during [dict description]
|
||||
return @"Disabled for now, as the resulting hash hangs the app while goring memory";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// Runtime information
|
||||
//
|
||||
@implementation NSObject(ClassWalker)
|
||||
|
||||
//
|
||||
// Class name (description might have been overriden, and classes don't seem to travel well over NSDistantObject)
|
||||
//
|
||||
- (id)__className
|
||||
{
|
||||
return [[self class] description];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Returns which framework containing the class
|
||||
//
|
||||
+ (id)__classImage
|
||||
{
|
||||
const char* name = class_getImageName(self);
|
||||
if (!name) return nil;
|
||||
return [NSString stringWithUTF8String:name];
|
||||
}
|
||||
- (id)__classImage
|
||||
{
|
||||
return [[self class] __classImage];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Derivation path
|
||||
// derivationPath(NSButton) = NSObject, NSResponder, NSView, NSControl, NSButton
|
||||
//
|
||||
+ (id)__derivationPath
|
||||
{
|
||||
int level = -1;
|
||||
id class = self;
|
||||
id classes = [NSMutableArray array];
|
||||
while (class)
|
||||
{
|
||||
[classes insertObject:class atIndex:0];
|
||||
level++;
|
||||
class = [class superclass];
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
- (id)__derivationPath
|
||||
{
|
||||
return [[self class] __derivationPath];
|
||||
}
|
||||
|
||||
//
|
||||
// Derivation level
|
||||
//
|
||||
+ (NSUInteger)__derivationLevel
|
||||
{
|
||||
return [[self __derivationPath] count]-1;
|
||||
}
|
||||
- (NSUInteger)__derivationLevel
|
||||
{
|
||||
return [[self class] __derivationLevel];
|
||||
}
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
// Copy all class or instance (type) methods of a class in an array
|
||||
static id copyMethods(Class class, NSMutableArray* array, NSString* type)
|
||||
{
|
||||
if ([type isEqualToString:@"class"]) class = objc_getMetaClass(class_getName(class));
|
||||
|
||||
unsigned int methodCount;
|
||||
Method* methods = class_copyMethodList(class, &methodCount);
|
||||
|
||||
for (int i=0; i<methodCount; i++)
|
||||
{
|
||||
Method m = methods[i];
|
||||
Dl_info info;
|
||||
dladdr(method_getImplementation(m), &info);
|
||||
|
||||
id name = NSStringFromSelector(method_getName(m));
|
||||
id encoding = [NSString stringWithUTF8String:method_getTypeEncoding(m)];
|
||||
id framework= [NSString stringWithUTF8String:info.dli_fname];
|
||||
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
encoding, @"encoding",
|
||||
type, @"type",
|
||||
class, @"class",
|
||||
framework, @"framework",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
free(methods);
|
||||
return array;
|
||||
}
|
||||
+ (id)__ownMethods
|
||||
{
|
||||
id methods = [NSMutableArray array];
|
||||
copyMethods([self class], methods, @"class");
|
||||
copyMethods([self class], methods, @"instance");
|
||||
return methods;
|
||||
}
|
||||
- (id)__ownMethods
|
||||
{
|
||||
return [[self class] __ownMethods];
|
||||
}
|
||||
+ (id)__methods
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id methods = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[methods addObjectsFromArray:[class __ownMethods]];
|
||||
return methods;
|
||||
}
|
||||
- (id)__methods
|
||||
{
|
||||
return [[self class] __methods];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Subclasses
|
||||
//
|
||||
|
||||
// Recursively go breadth first all a class' subclasses
|
||||
static void populateSubclasses(Class class, NSMutableArray* array, NSMutableDictionary* subclassesHash)
|
||||
{
|
||||
// Add ourselves
|
||||
[array addObject:class];
|
||||
|
||||
id className = [NSString stringWithUTF8String:class_getName(class)];
|
||||
id subclasses = [subclassesHash objectForKey:className];
|
||||
for (id subclass in subclasses)
|
||||
{
|
||||
populateSubclasses(subclass, array, subclassesHash);
|
||||
}
|
||||
}
|
||||
// Build a hash of className : [direct subclasses] then walk it down recursively.
|
||||
+ (id)__subclasses
|
||||
{
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
id classes = [JSCocoaLib classes];
|
||||
id subclasses = [NSMutableArray array];
|
||||
id subclassesHash = [NSMutableDictionary dictionary];
|
||||
|
||||
for (id class in classes)
|
||||
{
|
||||
id superclass = [class superclass];
|
||||
if (!superclass) continue;
|
||||
id superclassName = [NSString stringWithUTF8String:class_getName(superclass)];
|
||||
|
||||
id subclassesArray = [subclassesHash objectForKey:superclassName];
|
||||
if (!subclassesArray)
|
||||
{
|
||||
subclassesArray = [NSMutableArray array];
|
||||
[subclassesHash setObject:subclassesArray forKey:superclassName];
|
||||
}
|
||||
[subclassesArray addObject:class];
|
||||
}
|
||||
|
||||
// (Optional) sort by class name
|
||||
for (id className in subclassesHash)
|
||||
{
|
||||
id subclassesArray = [subclassesHash objectForKey:className];
|
||||
[subclassesArray sortUsingComparator:
|
||||
^(id a, id b)
|
||||
{
|
||||
// Case insensitive compare + remove underscores for sorting (yields [..., NSStatusBarButton, _NSThemeWidget, NSToolbarButton] )
|
||||
return [[[a description] stringByReplacingOccurrencesOfString:@"_" withString:@""]
|
||||
compare:[[b description] stringByReplacingOccurrencesOfString:@"_" withString:@""] options:NSCaseInsensitiveSearch];
|
||||
}];
|
||||
}
|
||||
|
||||
populateSubclasses(self, subclasses, subclassesHash);
|
||||
return subclasses;
|
||||
#else
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
- (id)__subclasses
|
||||
{
|
||||
return [[self class] __subclasses];
|
||||
}
|
||||
|
||||
// Returns a string showing subclasses, prefixed with as many spaces as their derivation level
|
||||
+ (id)__subclassTree
|
||||
{
|
||||
id subclasses = [self __subclasses];
|
||||
id str = [NSMutableString string];
|
||||
for (id subclass in subclasses)
|
||||
{
|
||||
NSUInteger level = [subclass __derivationLevel];
|
||||
for (int i=0; i<level; i++)
|
||||
[str appendString:@" "];
|
||||
[str appendString:[NSString stringWithUTF8String:class_getName(subclass)]];
|
||||
[str appendString:@"\n"];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
- (id)__subclassTree
|
||||
{
|
||||
return [[self class] __subclassTree];
|
||||
}
|
||||
|
||||
//
|
||||
// ivars
|
||||
//
|
||||
+ (id)__ownIvars
|
||||
{
|
||||
unsigned int ivarCount;
|
||||
Ivar* ivars = class_copyIvarList(self, &ivarCount);
|
||||
|
||||
id array = [NSMutableArray array];
|
||||
for (int i=0; i<ivarCount; i++)
|
||||
{
|
||||
Ivar ivar = ivars[i];
|
||||
|
||||
id name = [NSString stringWithUTF8String:ivar_getName(ivar)];
|
||||
id encoding = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
|
||||
id offset = [NSNumber numberWithLong:ivar_getOffset(ivar)];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
encoding, @"encoding",
|
||||
offset, @"offset",
|
||||
self, @"class",
|
||||
nil];
|
||||
|
||||
[array addObject:hash];
|
||||
}
|
||||
|
||||
free(ivars);
|
||||
return array;
|
||||
}
|
||||
- (id)__ownIvars
|
||||
{
|
||||
return [[self class] __ownIvars];
|
||||
}
|
||||
+ (id)__ivars
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id ivars = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[ivars addObjectsFromArray:[class __ownIvars]];
|
||||
return ivars;
|
||||
}
|
||||
- (id)__ivars
|
||||
{
|
||||
return [[self class] __ivars];
|
||||
}
|
||||
|
||||
//
|
||||
// Properties
|
||||
//
|
||||
+ (id)__ownProperties
|
||||
{
|
||||
unsigned int propertyCount;
|
||||
objc_property_t* properties = class_copyPropertyList(self, &propertyCount);
|
||||
|
||||
id array = [NSMutableArray array];
|
||||
for (int i=0; i<propertyCount; i++)
|
||||
{
|
||||
objc_property_t property = properties[i];
|
||||
|
||||
id name = [NSString stringWithUTF8String:property_getName(property)];
|
||||
id attributes = [NSString stringWithUTF8String:property_getAttributes(property)];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
attributes, @"attributes",
|
||||
self, @"class",
|
||||
nil];
|
||||
[array addObject:hash];
|
||||
}
|
||||
|
||||
free(properties);
|
||||
return array;
|
||||
}
|
||||
- (id)__ownProperties
|
||||
{
|
||||
return [[self class] __ownProperties];
|
||||
}
|
||||
+ (id)__properties
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id properties = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[properties addObjectsFromArray:[class __ownProperties]];
|
||||
return properties;
|
||||
}
|
||||
- (id)__properties
|
||||
{
|
||||
return [[self class] __properties];
|
||||
}
|
||||
|
||||
//
|
||||
// Protocols
|
||||
//
|
||||
+ (id)__ownProtocols
|
||||
{
|
||||
unsigned int protocolCount;
|
||||
Protocol** protocols = class_copyProtocolList(self, &protocolCount);
|
||||
|
||||
id array = [NSMutableArray array];
|
||||
for (int i=0; i<protocolCount; i++)
|
||||
{
|
||||
id name = [NSString stringWithUTF8String:protocol_getName(protocols[i])];
|
||||
id hash = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
name, @"name",
|
||||
self, @"class",
|
||||
nil];
|
||||
[array addObject:hash];
|
||||
}
|
||||
|
||||
free(protocols);
|
||||
return array;
|
||||
}
|
||||
- (id)__ownProtocols
|
||||
{
|
||||
return [[self class] __ownProtocols];
|
||||
}
|
||||
|
||||
+ (id)__protocols
|
||||
{
|
||||
id classes = [self __derivationPath];
|
||||
id protocols = [NSMutableArray array];
|
||||
for (id class in classes)
|
||||
[protocols addObjectsFromArray:[class __ownProtocols]];
|
||||
return protocols;
|
||||
}
|
||||
- (id)__protocols
|
||||
{
|
||||
return [[self class] __protocols];
|
||||
}
|
||||
|
||||
@end
|
92
JSCocoa/JSCocoaPrivateObject.h
Normal file
92
JSCocoa/JSCocoaPrivateObject.h
Normal file
@ -0,0 +1,92 @@
|
||||
//
|
||||
// JSCocoaPrivateObject.h
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 09/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_IPHONE
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#endif
|
||||
|
||||
#import <mach-o/dyld.h>
|
||||
#import <dlfcn.h>
|
||||
//#import <objc/objc-class.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
//
|
||||
// Boxing object
|
||||
//
|
||||
// type
|
||||
// @ ObjC object
|
||||
// struct C struct
|
||||
// method ObjC method name
|
||||
// function C function
|
||||
// rawPointer raw C pointer (_C_PTR)
|
||||
// jsFunction Javascript function
|
||||
// jsValueRef raw jsvalue
|
||||
// externalJSValueRef jsvalue coming from an external context (eg, a WebView)
|
||||
//
|
||||
|
||||
@interface JSCocoaPrivateObject : NSObject {
|
||||
|
||||
NSString* type;
|
||||
NSString* xml;
|
||||
NSString* methodName;
|
||||
NSString* structureName;
|
||||
|
||||
NSString* declaredType;
|
||||
void* rawPointer;
|
||||
|
||||
id object;
|
||||
|
||||
Method method;
|
||||
|
||||
JSValueRef jsValue;
|
||||
JSContextRef ctx;
|
||||
unsigned int externalJSValueIndex;
|
||||
// (test) when storing JSValues from a WebView, used to retain the WebView's context.
|
||||
// Disabled for now. Just make sure the WebView has a longer life than the vars it uses.
|
||||
//
|
||||
// Disabled because retaining the context crashes in 32 bits, but works in 64 bit.
|
||||
// May be reenabled someday.
|
||||
// JSContextGroupRef contextGroup;
|
||||
|
||||
BOOL isAutoCall;
|
||||
BOOL retainObject;
|
||||
// Disabled because of a crash on i386. Release globalContext last.
|
||||
// BOOL retainContext;
|
||||
}
|
||||
|
||||
@property (copy) NSString* type;
|
||||
@property (copy) NSString* xml;
|
||||
@property (copy) NSString* methodName;
|
||||
@property (copy) NSString* structureName;
|
||||
@property (copy) NSString* declaredType;
|
||||
@property BOOL isAutoCall;
|
||||
|
||||
//- (void)setPtr:(void*)ptrValue;
|
||||
//- (void*)ptr;
|
||||
|
||||
- (void)setObject:(id)o;
|
||||
- (void)setObjectNoRetain:(id)o;
|
||||
- (BOOL)retainObject;
|
||||
- (id)object;
|
||||
|
||||
- (void)setMethod:(Method)m;
|
||||
- (Method)method;
|
||||
|
||||
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
|
||||
- (JSValueRef)jsValueRef;
|
||||
- (void)setCtx:(JSContextRef)ctx;
|
||||
- (JSContextRef)ctx;
|
||||
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)ctx;
|
||||
|
||||
- (void*)rawPointer;
|
||||
- (void)setRawPointer:(void*)rp encoding:(id)encoding;
|
||||
- (id)rawPointerEncoding;
|
||||
|
||||
@end
|
236
JSCocoa/JSCocoaPrivateObject.m
Normal file
236
JSCocoa/JSCocoaPrivateObject.m
Normal file
@ -0,0 +1,236 @@
|
||||
//
|
||||
// JSCocoaPrivateObject.m
|
||||
// JSCocoa
|
||||
//
|
||||
// Created by Patrick Geiller on 09/07/08.
|
||||
// Copyright 2008 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JSCocoaPrivateObject.h"
|
||||
#import "JSCocoaController.h"
|
||||
|
||||
@implementation JSCocoaPrivateObject
|
||||
|
||||
@synthesize type, xml, declaredType, methodName, structureName, isAutoCall;
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
type = xml = declaredType = methodName = nil;
|
||||
object = nil;
|
||||
isAutoCall = NO;
|
||||
jsValue = NULL;
|
||||
retainObject= YES;
|
||||
rawPointer = NULL;
|
||||
ctx = NULL;
|
||||
// retainContext = NO;
|
||||
externalJSValueIndex = 0;
|
||||
|
||||
|
||||
[JSCocoaController upJSCocoaPrivateObjectCount];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)cleanUp
|
||||
{
|
||||
[JSCocoaController downJSCocoaPrivateObjectCount];
|
||||
if (object && retainObject)
|
||||
{
|
||||
// NSLog(@"commented downBoxedJSObjectCount");
|
||||
// [JSCocoaController downBoxedJSObjectCount:object];
|
||||
// NSLog(@"releasing %@(%d)", [object class], [object retainCount]);
|
||||
// if ([object isKindOfClass:[JSCocoaController class]])
|
||||
// [object autorelease];
|
||||
// else
|
||||
[object release];
|
||||
}
|
||||
if (jsValue)
|
||||
{
|
||||
if (!externalJSValueIndex) JSValueUnprotect(ctx, jsValue);
|
||||
[JSCocoaController downJSValueProtectCount];
|
||||
|
||||
// If holding a value from an external context, remove it from the GC-safe hash and release context.
|
||||
if (externalJSValueIndex)
|
||||
{
|
||||
JSStringRef scriptJS = JSStringCreateWithUTF8CString("delete __gcprotect[arguments[0]]");
|
||||
JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
|
||||
JSStringRelease(scriptJS);
|
||||
JSValueRef jsNumber = JSValueMakeNumber(ctx, externalJSValueIndex);
|
||||
JSValueRef exception = NULL;
|
||||
JSObjectCallAsFunction(ctx, fn, NULL, 1, (JSValueRef*)&jsNumber, &exception);
|
||||
// JSGlobalContextRelease((JSGlobalContextRef)ctx);
|
||||
|
||||
if (exception)
|
||||
NSLog(@"Got an exception while trying to release externalJSValueRef %p of context %p", jsValue, ctx);
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (retainContext)
|
||||
{
|
||||
NSLog(@"releasing %p", ctx);
|
||||
JSContextGroupRelease(contextGroup);
|
||||
// JSGlobalContextRelease((JSGlobalContextRef)ctx);
|
||||
}
|
||||
*/
|
||||
// Release properties
|
||||
[type release];
|
||||
[xml release];
|
||||
[methodName release];
|
||||
[structureName release];
|
||||
[declaredType release];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self cleanUp];
|
||||
[super dealloc];
|
||||
}
|
||||
- (void)finalize
|
||||
{
|
||||
[self cleanUp];
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
- (void)setObject:(id)o
|
||||
{
|
||||
// if (object && retainObject)
|
||||
// [object release];
|
||||
object = o;
|
||||
if (object && [object retainCount] == -1) return;
|
||||
[object retain];
|
||||
}
|
||||
|
||||
- (void)setObjectNoRetain:(id)o
|
||||
{
|
||||
object = o;
|
||||
retainObject = NO;
|
||||
}
|
||||
|
||||
- (BOOL)retainObject
|
||||
{
|
||||
return retainObject;
|
||||
}
|
||||
|
||||
- (id)object
|
||||
{
|
||||
return object;
|
||||
}
|
||||
|
||||
- (void)setMethod:(Method)m
|
||||
{
|
||||
method = m;
|
||||
}
|
||||
- (Method)method
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
- (void)setJSValueRef:(JSValueRef)v ctx:(JSContextRef)c
|
||||
{
|
||||
// While autocalling we'll get a NULL value when boxing a void return type - just skip JSValueProtect
|
||||
if (!v)
|
||||
{
|
||||
// NSLog(@"setJSValueRef: NULL value");
|
||||
jsValue = 0;
|
||||
return;
|
||||
}
|
||||
jsValue = v;
|
||||
// ctx = c;
|
||||
// Register global context (this would crash the launcher as JSValueUnprotect was called on a destroyed context)
|
||||
ctx = [[JSCocoaController controllerFromContext:c] ctx];
|
||||
JSValueProtect(ctx, jsValue);
|
||||
[JSCocoaController upJSValueProtectCount];
|
||||
}
|
||||
- (JSValueRef)jsValueRef
|
||||
{
|
||||
return jsValue;
|
||||
}
|
||||
|
||||
- (void)setCtx:(JSContextRef)_ctx {
|
||||
ctx = _ctx;
|
||||
}
|
||||
- (JSContextRef)ctx
|
||||
{
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
- (void)setExternalJSValueRef:(JSValueRef)v ctx:(JSContextRef)c
|
||||
{
|
||||
if (!v)
|
||||
{
|
||||
jsValue = 0;
|
||||
return;
|
||||
}
|
||||
jsValue = v;
|
||||
ctx = c;
|
||||
|
||||
// Register value in a global hash to protect it from GC. This sucks but JSValueProtect() fails.
|
||||
JSStringRef scriptJS = JSStringCreateWithUTF8CString("if (!('__gcprotect' in this)) { __gcprotect = {}; __gcprotectidx = 1; } __gcprotect[__gcprotectidx] = arguments[0]; return __gcprotectidx++ ");
|
||||
JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
|
||||
JSStringRelease(scriptJS);
|
||||
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef result = JSObjectCallAsFunction(ctx, fn, NULL, 1, (JSValueRef*)&jsValue, &exception);
|
||||
if (exception) return;
|
||||
|
||||
// Use hash index as key, will be used to remove value from hash upon deletion.
|
||||
externalJSValueIndex = (unsigned int)JSValueToNumber(ctx, result, &exception);
|
||||
if (exception) return;
|
||||
|
||||
// JSGlobalContextRetain((JSGlobalContextRef)ctx);
|
||||
[JSCocoaController upJSValueProtectCount];
|
||||
}
|
||||
|
||||
|
||||
- (void*)rawPointer
|
||||
{
|
||||
return rawPointer;
|
||||
}
|
||||
- (void)setRawPointer:(void*)rp encoding:(id)encoding
|
||||
{
|
||||
rawPointer = rp;
|
||||
// NSLog(@"RAWPOINTER=%@", encoding);
|
||||
declaredType = encoding;
|
||||
[declaredType retain];
|
||||
}
|
||||
|
||||
- (id)rawPointerEncoding
|
||||
{
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
|
||||
- (id)description {
|
||||
id extra = @"";
|
||||
if ([type isEqualToString:@"rawPointer"])
|
||||
extra = [NSString stringWithFormat:@" rawPointer=%p declaredType=%@", rawPointer, declaredType];
|
||||
return [NSString stringWithFormat:@"<%@: %p holding %@%@>",
|
||||
[self class],
|
||||
self,
|
||||
type,
|
||||
extra
|
||||
];
|
||||
}
|
||||
|
||||
+ (id)description {
|
||||
return @"<JSCocoaPrivateObject class>";
|
||||
}
|
||||
|
||||
- (id)dereferencedObject {
|
||||
if (![type isEqualToString:@"rawPointer"] || !rawPointer)
|
||||
return nil;
|
||||
return *(void**)rawPointer;
|
||||
}
|
||||
|
||||
- (BOOL)referenceObject:(id)o {
|
||||
if (![type isEqualToString:@"rawPointer"])
|
||||
return NO;
|
||||
*(id*)rawPointer = o;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
1055
JSCocoa/class.js
Normal file
1055
JSCocoa/class.js
Normal file
File diff suppressed because it is too large
Load Diff
5686
JSCocoa/jslint-jscocoa.js
Normal file
5686
JSCocoa/jslint-jscocoa.js
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user