class CFString {
private int ref;
public CFString(String string) {
ref = CFStringCreateWithCharacters(0, string.toCharArray(), string.length());
}
public int length() {
return CFStringGetLength(ref);
}
public void show() {
CFShow(ref);
}
protected void finalize() {
if (ref != 0)
CFRelease(ref);
}
public String toString() {
return new String(getCharacters(0, CFStringGetLength(ref)));
}
public char[] getCharacters(int location, int length) {
char[] buffer = new char[length];
long range = (((long)location) << 32) | length;
CFStringGetCharacters(ref, range, buffer);
return buffer;
}
private static native int CFStringCreateWithCharacters(int alloc, char[] chars, int numChars);
private static native int CFStringGetLength(int ref);
private static native void CFStringGetCharacters(int ref, /* CFRange */ long range, char[] buffer);
private static native void CFRelease(int ref);
private static native void CFShow(int ref);
static {
jnidirect.Linker.link(CFString.class, new String[] { "CoreFoundation" });
}
} |
The arguments to jnidirect.Linker.link are the class to link, and an optional array of frameworks to link against.
public class pthread {
private int start_closure;
private int pthread;
public pthread() {
start_closure = jnidirect.Linker.newMethodClosure(runMethod, this);
}
public void start() {
int[] pthread_ptr = { 0 };
int [] attributes = default_attributes();
int rv = pthread_create(pthread_ptr, attributes, start_closure, 0);
if (rv != 0) throw new Error("pthread_create returned " + rv);
rv = pthread_attr_destroy(attributes);
if (rv != 0) throw new Error("pthread_attr_destroy returned " + rv);
pthread = pthread_ptr[0];
}
public void stop() {
int rv = pthread_cancel(pthread);
if (rv != 0) throw new Error("pthread_cancel returned " + rv);
}
protected int run(int arg) {
System.out.println("pthread.run() here!");
return 0;
}
private int[] default_attributes() {
// #define __PTHREAD_ATTR_SIZE__ 36
// struct _opaque_pthread_attr_t { long sig; char opaque[__PTHREAD_ATTR_SIZE__]; } pthread_attr_t;
int[] attr = new int[40];
int rv = pthread_attr_init(attr);
if (rv != 0) throw new Error("pthread_attr_init returned " + rv);
return attr;
}
private static native int pthread_attr_init(/* pthread_attr_t* */ int[] attr);
private static native int pthread_attr_destroy(/* pthread_attr_t* */ int[] attr);
private static native int pthread_create(/* pthread_t* */ int[] thread,
/* const pthread_attr_t* */ int[] attr,
/* void* (*start_routine)(void*) */ int start_closure,
/* void* */ int arg);
private static native int pthread_cancel(/* pthread_t */ int thread);
private static Method runMethod;
static {
try {
runMethod = pthread.class.getDeclaredMethod("run", new Class[] { Integer.TYPE });
jnidirect.Linker.link(pthread.class, new Method[] { runMethod });
} catch (Exception ex) {
}
}
} |
In this case the link method is passed the class to link, and an optional array of Method objects that will be used as method closures.
public class NSImage {
private int image;
public NSImage(File f) throws IOException {
byte[] path = (f.getPath() + '\0').getBytes();
image = NSAddImage(path, 0);
if (image == 0)
throw new IOException("NSAddImage failed.");
}
public int getSymbolAddress(String symbolName) {
int symbol = NSLookupSymbolInImage(image, ("_" + symbolName + '\0').getBytes(), 0);
if (symbol != 0)
return NSAddressOfSymbol(symbol);
return 0;
}
public boolean isSymbolDefined(String symbolName) {
return NSIsSymbolNameDefinedInImage(image, ("_" + symbolName + '\0').getBytes());
}
public static void test() {
try {
NSImage system = new NSImage(new File("/usr/lib/libc.dylib"));
int printf = system.getSymbolAddress("printf");
if (printf != 0) {
$call$(printf, "hello indirect printf.\n\0".getBytes());
System.out.println("NSImage test successful.");
} else {
System.out.println("NSImage test failed.");
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
private static native int NSAddImage(byte[] image_name, int options);
private static native int NSLookupSymbolInImage(int image, byte[] symbolName, int options);
private static native int NSAddressOfSymbol(int symbol);
private static native boolean NSIsSymbolNameDefinedInImage(int image, byte[] symbolName);
private static native int $call$(int f, byte[] format);
static {
jnidirect.Linker.link(NSImage.class);
}
} |
This demonstrates a few feature, unique to JNIDirect, intrinsic native methods that perform primitive operations. The $call$() native method provides an operator for calling native function pointers.
public class NSString {
// from libobjc.dylib:
// id objc_getClass(const char *name);
// SEL sel_registerName(const char *str);
// id objc_msgSend(id self, SEL op, ...);
private static native int objc_getClass(byte[] name);
private static native int sel_registerName(byte[] name);
private static native int objc_msgSend(int self, int op);
private static native int objc_msgSend(int self, int op, char[] ch, int length);
// void NSLog(NSString* format, ...);
private static native void NSLog(int format);
private static native void NSLog(int format, double value);
static {
jnidirect.Linker.link(NSString.class, new String[] { "Foundation" });
}
static int
alloc = sel_registerName("alloc\0".getBytes()),
init = sel_registerName("init\0".getBytes()),
release = sel_registerName("release\0".getBytes()),
stringWithCharacters_length = sel_registerName("stringWithCharacters:length:\0".getBytes());
public static class Test extends junit.framework.TestCase {
public void test() {
int NSAutoreleasePool = objc_getClass("NSAutoreleasePool\0".getBytes());
assertTrue(NSAutoreleasePool != 0);
int pool = objc_msgSend(objc_msgSend(NSAutoreleasePool, alloc), init);
assertTrue(pool != 0);
int NSString = objc_getClass("NSString\0".getBytes());
assertTrue(NSString != 0);
char[] m1 = "Hello World!".toCharArray();
int msg1 = objc_msgSend(NSString, stringWithCharacters_length, m1, m1.length);
assertTrue(msg1 != 0);
NSLog(msg1);
char[] m2 = "PI = %lg".toCharArray();
int msg2 = objc_msgSend(NSString, stringWithCharacters_length, m2, m2.length);
assertTrue(msg2 != 0);
NSLog(msg2, Math.PI);
objc_msgSend(pool, release);
}
}
} |
This shows how thin a veneer the Objective C language runtime is. Classes are objects, so to create one from Java one simply needs to be able to look up the class by name, look up the relevant method names (selectors in Objective C parlance), then use various overloads of objc_msgSend() to call the methods. This example also creates an auto release pool which gets associated with the current Java thread.
All examples (C) Copyright 2003 by Patrick C. Beard. All rights reserved.