mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-11 11:15:24 +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 */; };
|
8359A69213FE1FE900AC37E3 /* worker-javascript.js in Resources */ = {isa = PBXBuildFile; fileRef = 8359A63413FE1FCA00AC37E3 /* worker-javascript.js */; };
|
||||||
8359A6B413FE24B300AC37E3 /* atomicity.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6B313FE24B300AC37E3 /* atomicity.js */; };
|
8359A6B413FE24B300AC37E3 /* atomicity.js in Sources */ = {isa = PBXBuildFile; fileRef = 8359A6B313FE24B300AC37E3 /* atomicity.js */; };
|
||||||
8359A6B713FE24BC00AC37E3 /* atomicity.js in Resources */ = {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 */; };
|
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
|
||||||
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
|
||||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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; };
|
8D1107320486CEB800E47090 /* Atomicity.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Atomicity.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@ -139,6 +164,7 @@
|
|||||||
files = (
|
files = (
|
||||||
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
|
||||||
83599F9B13FE0F8400AC37E3 /* WebKit.framework in Frameworks */,
|
83599F9B13FE0F8400AC37E3 /* WebKit.framework in Frameworks */,
|
||||||
|
8359A6EE13FE26DA00AC37E3 /* JavaScriptCore.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -159,6 +185,7 @@
|
|||||||
children = (
|
children = (
|
||||||
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
|
||||||
83599F9A13FE0F8400AC37E3 /* WebKit.framework */,
|
83599F9A13FE0F8400AC37E3 /* WebKit.framework */,
|
||||||
|
8359A6ED13FE26DA00AC37E3 /* JavaScriptCore.framework */,
|
||||||
);
|
);
|
||||||
name = "Linked Frameworks";
|
name = "Linked Frameworks";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -188,6 +215,7 @@
|
|||||||
080E96DDFE201D6D7F000001 /* Classes */,
|
080E96DDFE201D6D7F000001 /* Classes */,
|
||||||
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
29B97315FDCFA39411CA2CEA /* Other Sources */,
|
||||||
29B97317FDCFA39411CA2CEA /* Resources */,
|
29B97317FDCFA39411CA2CEA /* Resources */,
|
||||||
|
8359A6F713FE270F00AC37E3 /* JSCocoa */,
|
||||||
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
29B97323FDCFA39411CA2CEA /* Frameworks */,
|
||||||
19C28FACFE9D520D11CA2CBB /* Products */,
|
19C28FACFE9D520D11CA2CBB /* Products */,
|
||||||
);
|
);
|
||||||
@ -287,6 +315,28 @@
|
|||||||
name = ace;
|
name = ace;
|
||||||
sourceTree = "<group>";
|
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 */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -402,6 +452,14 @@
|
|||||||
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
||||||
256AC3DA0F4B6AC300CF3369 /* AtomicityAppDelegate.m in Sources */,
|
256AC3DA0F4B6AC300CF3369 /* AtomicityAppDelegate.m in Sources */,
|
||||||
8359A6B413FE24B300AC37E3 /* atomicity.js 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;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -432,6 +490,10 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"$(SRCROOT)\"",
|
||||||
|
);
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
@ -449,6 +511,10 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"\"$(SRCROOT)\"",
|
||||||
|
);
|
||||||
GCC_MODEL_TUNING = G5;
|
GCC_MODEL_TUNING = G5;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = Atomicity_Prefix.pch;
|
GCC_PREFIX_HEADER = Atomicity_Prefix.pch;
|
||||||
@ -467,6 +533,10 @@
|
|||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
OTHER_LDFLAGS = (
|
||||||
|
"-lxml2",
|
||||||
|
"-lffi",
|
||||||
|
);
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.6;
|
SDKROOT = macosx10.6;
|
||||||
};
|
};
|
||||||
@ -479,6 +549,10 @@
|
|||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
OTHER_LDFLAGS = (
|
||||||
|
"-lxml2",
|
||||||
|
"-lffi",
|
||||||
|
);
|
||||||
PREBINDING = NO;
|
PREBINDING = NO;
|
||||||
SDKROOT = macosx10.6;
|
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