-
-
Save krasnobaev/06f6c14a390dfb85fa5e261ae8dcab8e to your computer and use it in GitHub Desktop.
Experimentations with node-ffi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://developer.apple.com/documentation/foundation/nsfilemanager/1642853-homedirectoryforuser | |
var ffi = require('ffi'); | |
var objc = new ffi.Library(null, { | |
'objc_getClass': [ 'pointer', [ 'string' ] ], | |
'sel_registerName': [ 'pointer', [ 'string' ] ], | |
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer' ] ] | |
}); | |
var objc2 = new ffi.Library(null, { | |
'objc_msgSend': [ 'string', [ 'pointer', 'pointer' ] ] | |
}); | |
var objc4 = new ffi.Library(null, { | |
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'string' ] ] | |
}); | |
function getDescription (v) { | |
const description = objc.sel_registerName('description'); | |
return objc2.objc_msgSend(objc.objc_msgSend(v, description), objc.sel_registerName('UTF8String')); | |
} | |
new ffi.DynamicLibrary('/System/Library/Frameworks/Foundation.framework/Foundation'); | |
var NSFM = objc.objc_getClass('NSFileManager'); | |
var nsfm = objc.objc_msgSend(NSFM, objc.sel_registerName('defaultManager')); | |
// (NSURL *)homeDirectoryForUser:(NSString *)userName; | |
var objc2_ = new ffi.Library(null, { | |
'objc_msgSend': [ 'pointer', [ 'pointer', | |
'pointer', 'pointer' | |
] ] | |
}); | |
var NSString = objc.objc_getClass('NSString'); | |
var stringWithUTF8String = objc.sel_registerName('stringWithUTF8String:'); | |
var str = objc4.objc_msgSend(NSString, stringWithUTF8String, 'sypwex'); | |
var homedir = objc2_.objc_msgSend(nsfm, | |
objc.sel_registerName('homeDirectoryForUser:'), str | |
); | |
getDescription(homedir); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ffi = require('ffi'); | |
var objc = new ffi.Library(null, { | |
'objc_getClass': [ 'pointer', [ 'string' ] ], | |
// | \> parameter type | |
// \> returned value type | |
'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 | |
var objc1 = new ffi.Library(null, { | |
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'int32' ] ] | |
}); | |
var objc2 = new ffi.Library(null, { | |
'objc_msgSend': [ 'string', [ 'pointer', 'pointer' ] ] | |
}); | |
var objc3 = new ffi.Library(null, { | |
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'pointer' ] ] | |
}); | |
var objc4 = new ffi.Library(null, { | |
'objc_msgSend': [ 'pointer', [ 'pointer', 'pointer', 'string' ] ] | |
}); | |
function getDescription (v) { | |
const description = objc.sel_registerName('description'); | |
return objc2.objc_msgSend(objc.objc_msgSend(v, description), objc.sel_registerName('UTF8String')); | |
} | |
// dlopen equivalent | |
new ffi.DynamicLibrary('/System/Library/Frameworks/Foundation.framework/Foundation'); | |
new ffi.DynamicLibrary('/System/Library/Frameworks/ScriptingBridge.framework/ScriptingBridge'); | |
// NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
var NSAP = objc.objc_getClass('NSAutoreleasePool'); | |
var alloc = objc.sel_registerName('alloc'); | |
var init = objc.sel_registerName('init'); | |
var pool = objc.objc_msgSend(objc.objc_msgSend(NSAP, alloc), init); | |
// NSMutableArray | |
var NSArray = objc.objc_getClass('NSMutableArray'); | |
console.log(NSArray.address); | |
console.log(objc.class_getName(NSArray)); | |
// NSString* str = [NSString stringWithUTF8String:"Hello Objective-C!"]; | |
var NSString = objc.objc_getClass('NSString'); | |
var stringWithUTF8String = objc.sel_registerName('stringWithUTF8String:'); | |
var str = objc4.objc_msgSend(NSString, stringWithUTF8String, 'Hello Objective-C!'); | |
console.log(getDescription(str)); | |
// | |
var initWithCapacity = objc.sel_registerName('initWithCapacity:'); | |
var addObject = objc.sel_registerName('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(getDescription(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)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ffi = require('ffi'); | |
var stdio = new ffi.Library(null, { | |
'printf': [ 'int32', [ 'string', 'string' ]] | |
}); | |
stdio.printf('hello %s\n', 'world'); | |
// hello world |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ffi = require('ffi'); | |
var time = new ffi.Library(null, { | |
'time': [ 'int32', [ 'pointer' ] ] | |
}); | |
// TypeError: ffi.Pointer is not a constructor ??? | |
var 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