Skip to content

Instantly share code, notes, and snippets.

@TooTallNate
Created July 13, 2011 05:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save TooTallNate/1079750 to your computer and use it in GitHub Desktop.
Save TooTallNate/1079750 to your computer and use it in GitHub Desktop.
Experimentations with node-ffi
var ffi = require('node-ffi')
, objc = new ffi.Library(null, {
'objc_getClass': [ 'pointer', [ 'string' ] ]
, 'class_getName': [ 'string', [ 'pointer' ] ]
, 'sel_registerName': [ 'pointer', [ 'string' ] ]
, 'sel_getName': [ 'string', [ 'pointer' ] ]
, 'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer' ] ]
})
// The problem with libffi and C functions that accepts varargs is that we
// have to create new wrappers for each different argument and return value
// signature that we encounter
, objc1 = new ffi.Library(null, {
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'int32' ] ]
})
, objc2 = new ffi.Library(null, {
'objc_msgSend': [ 'string', [ 'pointer', 'pointer' ] ]
})
, objc3 = new ffi.Library(null, {
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'pointer' ] ]
})
, objc4 = new ffi.Library(null, {
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'string' ] ]
})
, getClass = objc.objc_getClass
// dlopen equivalent
new ffi.DynamicLibrary('/System/Library/Frameworks/Foundation.framework/Foundation');
new ffi.DynamicLibrary('/System/Library/Frameworks/ScriptingBridge.framework/ScriptingBridge');
function $C (v) {
return getClass(v);
}
function $R (v) {
return objc.sel_registerName(v);
}
function $D (v) {
return objc2.objc_msgSend(objc.objc_msgSend(v, description), objc.sel_registerName('UTF8String'));
}
var NSAP = $C('NSAutoreleasePool')
, alloc = $R('alloc')
, init = $R('init')
, pool = objc.objc_msgSend(objc.objc_msgSend(NSAP, alloc), init);
var NSArray = $C('NSMutableArray');
console.log(NSArray.address);
console.log(objc.class_getName(NSArray));
var NSString = $C('NSString')
, stringWithUTF8String = $R('stringWithUTF8String:')
, str = objc4.objc_msgSend(NSString, stringWithUTF8String, 'Hello Objective-C!')
, description = $R('description')
console.log($D(str));
var initWithCapacity = $R('initWithCapacity:')
, addObject = $R('addObject:')
console.log(objc.sel_getName(alloc));
var array = objc.objc_msgSend(NSArray, alloc);
array = objc1.objc_msgSend(array, init, 10);
objc3.objc_msgSend(array, addObject, NSArray);
objc3.objc_msgSend(array, addObject, str);
console.log($D(array));
// Normally this wouldn't work properly. However we have dynamically loaded the
// ScriptingBridge framework binary file above so this will work properly.
var SBApplication = objc.objc_getClass('SBApplication');
console.log(SBApplication.address);
console.log(objc.class_getName(SBApplication));
var ffi = require('node-ffi')
, stdio = new ffi.Library(null, {
'printf': [ 'int32', [ 'string', 'string' ]]
})
stdio.printf('hello %s\n', 'world');
// hello world
var ffi = require('node-ffi')
, time = new ffi.Library(null, {
'time': [ 'int32', [ 'pointer' ] ]
})
, NULL = new ffi.Pointer(0)
// Passing JS null converts to C NULL
console.log(time.time(null));
// new ffi.Pointer(0) creates a NULL pointer
console.log(time.time(NULL));
var time_t = new ffi.Pointer(4);
console.log(time.time(time_t));
console.log(time_t.getInt32());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment