Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit 5f055880d572105ed21f70af3d0b24bb19eb5997 @digitalstain digitalstain committed Jun 20, 2011
Showing with 9,625 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +41 −0 pom.xml
  3. +19 −0 src/main/java/com/sun/jna/AltCallingConvention.java
  4. +50 −0 src/main/java/com/sun/jna/Callback.java
  5. +31 −0 src/main/java/com/sun/jna/CallbackParameterContext.java
  6. +30 −0 src/main/java/com/sun/jna/CallbackProxy.java
  7. +585 −0 src/main/java/com/sun/jna/CallbackReference.java
  8. +12 −0 src/main/java/com/sun/jna/CallbackResultContext.java
  9. +146 −0 src/main/java/com/sun/jna/DefaultTypeMapper.java
  10. +25 −0 src/main/java/com/sun/jna/FromNativeContext.java
  11. +24 −0 src/main/java/com/sun/jna/FromNativeConverter.java
  12. +840 −0 src/main/java/com/sun/jna/Function.java
  13. +40 −0 src/main/java/com/sun/jna/FunctionMapper.java
  14. +33 −0 src/main/java/com/sun/jna/FunctionParameterContext.java
  15. +29 −0 src/main/java/com/sun/jna/FunctionResultContext.java
  16. +128 −0 src/main/java/com/sun/jna/IntegerType.java
  17. +75 −0 src/main/java/com/sun/jna/InvocationMapper.java
  18. +62 −0 src/main/java/com/sun/jna/LastErrorException.java
  19. +219 −0 src/main/java/com/sun/jna/Library.java
  20. +682 −0 src/main/java/com/sun/jna/Memory.java
  21. +27 −0 src/main/java/com/sun/jna/MethodParameterContext.java
  22. +30 −0 src/main/java/com/sun/jna/MethodResultContext.java
  23. +1,463 −0 src/main/java/com/sun/jna/Native.java
  24. +651 −0 src/main/java/com/sun/jna/NativeLibrary.java
  25. +34 −0 src/main/java/com/sun/jna/NativeLong.java
  26. +30 −0 src/main/java/com/sun/jna/NativeMapped.java
  27. +77 −0 src/main/java/com/sun/jna/NativeMappedConverter.java
  28. +107 −0 src/main/java/com/sun/jna/NativeString.java
  29. +102 −0 src/main/java/com/sun/jna/Platform.java
  30. +1,329 −0 src/main/java/com/sun/jna/Pointer.java
  31. +103 −0 src/main/java/com/sun/jna/PointerType.java
  32. +67 −0 src/main/java/com/sun/jna/StringArray.java
  33. +1,412 −0 src/main/java/com/sun/jna/Structure.java
  34. +33 −0 src/main/java/com/sun/jna/StructureReadContext.java
  35. +34 −0 src/main/java/com/sun/jna/StructureWriteContext.java
  36. +20 −0 src/main/java/com/sun/jna/ToNativeContext.java
  37. +42 −0 src/main/java/com/sun/jna/ToNativeConverter.java
  38. +19 −0 src/main/java/com/sun/jna/TypeConverter.java
  39. +24 −0 src/main/java/com/sun/jna/TypeMapper.java
  40. +238 −0 src/main/java/com/sun/jna/Union.java
  41. +47 −0 src/main/java/com/sun/jna/WString.java
  42. +659 −0 src/main/java/com/sun/jna/platform/win32/Advapi32.java
Sorry, we could not display the entire diff because it was too big.
6 .gitignore
@@ -0,0 +1,6 @@
+.project
+.settings/
+.classpath
+target/
+bin/
+.metadata/
41 pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.neo4j</groupId>
+ <artifactId>windows-service-wrapper</artifactId>
+ <version>1.0</version>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifest>
+ <mainClass>org.neo4j.wrapper.NeoServiceWrapper</mainClass>
+ <packageName>org.neo4j.wrapper</packageName>
+ </manifest>
+ <manifestEntries>
+ <url>http://neo4j.org</url>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
19 src/main/java/com/sun/jna/AltCallingConvention.java
@@ -0,0 +1,19 @@
+/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+/** Tagging interface to indicate the library or callback uses an alternate
+ * calling convention.
+ * @author twall
+ */
+public interface AltCallingConvention {}
50 src/main/java/com/sun/jna/Callback.java
@@ -0,0 +1,50 @@
+/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/** All callback definitions must derive from this interface. Any
+ * derived interfaces must define a single public method (which may not be named
+ * "hashCode", "equals", or "toString"), or one public method named "callback".
+ * You are responsible for deregistering your callback (if necessary)
+ * in its {@link Object#finalize} method. If native code attempts to call
+ * a callback which has been GC'd, you will likely crash the VM. If
+ * there is no method to deregister the callback (e.g. <code>atexit</code>
+ * in the C library), you must ensure that you always keep a live reference
+ * to the callback object.<p>
+ * A callback should generally never throw an exception, since it doesn't
+ * necessarily have an encompassing Java environment to catch it. Any
+ * exceptions thrown will be passed to the default callback exception
+ * handler.
+ */
+public interface Callback {
+ interface UncaughtExceptionHandler {
+ /** Method invoked when the given callback throws an uncaught
+ * exception.<p>
+ * Any exception thrown by this method will be ignored.
+ */
+ void uncaughtException(Callback c, Throwable e);
+ }
+ /** You must this method name if your callback interface has multiple
+ public methods. Typically a callback will have only one such
+ method, in which case any method name may be used, with the exception
+ of those in {@link #FORBIDDEN_NAMES}.
+ */
+ String METHOD_NAME = "callback";
+ /** These method names may not be used for a callback method. */
+ Collection FORBIDDEN_NAMES = Arrays.asList(new String[] {
+ "hashCode", "equals", "toString",
+ });
+}
31 src/main/java/com/sun/jna/CallbackParameterContext.java
@@ -0,0 +1,31 @@
+/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+import java.lang.reflect.Method;
+
+/** Provide argument conversion context for a callback invocation. */
+public class CallbackParameterContext extends FromNativeContext {
+ private Method method;
+ private Object[] args;
+ private int index;
+ CallbackParameterContext(Class javaType, Method m, Object[] args, int index) {
+ super(javaType);
+ this.method = m;
+ this.args = args;
+ this.index = index;
+ }
+ public Method getMethod() { return method; }
+ public Object[] getArguments() { return args; }
+ public int getIndex() { return index; }
+}
30 src/main/java/com/sun/jna/CallbackProxy.java
@@ -0,0 +1,30 @@
+/* Copyright (c) 2007 Wayne Meissner, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+/** Placeholder proxy interface to allow an InvocationHandler to convert
+ * arguments/return values on callback methods. This is a special sub-interface
+ * of {@link Callback} which expects its arguments in a single Object array
+ * passed to its {@link #callback} method.
+ */
+public interface CallbackProxy extends Callback {
+
+ /** This is the callback method invoked from native code.
+ * It must <em>not</em> throw any exceptions whatsoever.
+ */
+ Object callback(Object[] args);
+ /** Returns the types of the parameters to the callback method. */
+ Class[] getParameterTypes();
+ /** Returns the type of the callback method's return value. */
+ Class getReturnType();
+}
585 src/main/java/com/sun/jna/CallbackReference.java
@@ -0,0 +1,585 @@
+/* Copyright (c) 2007-2008 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/** Provides a reference to an association between a native callback closure
+ * and a Java {@link Callback} closure.
+ */
+
+class CallbackReference extends WeakReference {
+
+ static final Map callbackMap = new WeakHashMap();
+ static final Map directCallbackMap = new WeakHashMap();
+ static final Map allocations = new WeakHashMap();
+ private static final Method PROXY_CALLBACK_METHOD;
+
+ static {
+ try {
+ PROXY_CALLBACK_METHOD = CallbackProxy.class.getMethod("callback", new Class[] { Object[].class });
+ }
+ catch(Exception e) {
+ throw new Error("Error looking up CallbackProxy.callback() method");
+ }
+ }
+
+
+ /** Return a Callback associated with the given function pointer.
+ * If the pointer refers to a Java callback trampoline, return the original
+ * Java Callback. Otherwise, return a proxy to the native function pointer.
+ */
+ public static Callback getCallback(Class type, Pointer p) {
+ return getCallback(type, p, false);
+ }
+
+ private static Callback getCallback(Class type, Pointer p, boolean direct) {
+ if (p == null) {
+ return null;
+ }
+
+ if (!type.isInterface())
+ throw new IllegalArgumentException("Callback type must be an interface");
+ Map map = direct ? directCallbackMap : callbackMap;
+ synchronized(map) {
+ for (Iterator i=map.keySet().iterator();i.hasNext();) {
+ Callback cb = (Callback)i.next();
+ if (type.isAssignableFrom(cb.getClass())) {
+ CallbackReference cbref = (CallbackReference)map.get(cb);
+ Pointer cbp = cbref != null
+ ? cbref.getTrampoline() : getNativeFunctionPointer(cb);
+ if (p.equals(cbp)) {
+ return cb;
+ }
+ }
+ }
+ int ctype = AltCallingConvention.class.isAssignableFrom(type)
+ ? Function.ALT_CONVENTION : Function.C_CONVENTION;
+ Map foptions = new HashMap();
+ Map options = Native.getLibraryOptions(type);
+ if (options != null) {
+ foptions.putAll(options);
+ }
+ foptions.put(Function.OPTION_INVOKING_METHOD, getCallbackMethod(type));
+ NativeFunctionHandler h = new NativeFunctionHandler(p, ctype, foptions);
+ Callback cb = (Callback)Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, h);
+ map.put(cb, null);
+ return cb;
+ }
+ }
+
+ Pointer cbstruct;
+ // Keep a reference to the proxy to avoid premature GC of it
+ CallbackProxy proxy;
+ Method method;
+ private CallbackReference(Callback callback, int callingConvention, boolean direct) {
+ super(callback);
+ TypeMapper mapper = Native.getTypeMapper(callback.getClass());
+ Class[] nativeParamTypes;
+ Class returnType;
+
+ // Check whether direct mapping may be used, or whether
+ // we need to fall back to conventional mapping
+ String arch = System.getProperty("os.arch").toLowerCase();
+ boolean ppc = "ppc".equals(arch) || "powerpc".equals(arch);
+ if (direct) {
+ Method m = getCallbackMethod(callback);
+ Class[] ptypes = m.getParameterTypes();
+ for (int i=0;i < ptypes.length;i++) {
+ // varargs w/FP args via ffi_call fails on ppc (darwin)
+ if (ppc && (ptypes[i] == float.class
+ || ptypes[i] == double.class)) {
+ direct = false;
+ break;
+ }
+ // No TypeMapper support in native callback code
+ if (mapper != null
+ && mapper.getFromNativeConverter(ptypes[i]) != null) {
+ direct = false;
+ break;
+ }
+ }
+ if (mapper != null
+ && mapper.getToNativeConverter(m.getReturnType()) != null) {
+ direct = false;
+ }
+ }
+
+ if (direct) {
+ method = getCallbackMethod(callback);
+ nativeParamTypes = method.getParameterTypes();
+ returnType = method.getReturnType();
+ cbstruct = createNativeCallback(callback, method,
+ nativeParamTypes, returnType,
+ callingConvention, true);
+ }
+ else {
+ if (callback instanceof CallbackProxy) {
+ proxy = (CallbackProxy)callback;
+ }
+ else {
+ proxy = new DefaultCallbackProxy(getCallbackMethod(callback), mapper);
+ }
+ nativeParamTypes = proxy.getParameterTypes();
+ returnType = proxy.getReturnType();
+
+ // Generate a list of parameter types that the native code can
+ // handle. Let the CallbackProxy do any further conversion
+ // to match the true Java callback method signature
+ if (mapper != null) {
+ for (int i=0;i < nativeParamTypes.length;i++) {
+ FromNativeConverter rc = mapper.getFromNativeConverter(nativeParamTypes[i]);
+ if (rc != null) {
+ nativeParamTypes[i] = rc.nativeType();
+ }
+ }
+ ToNativeConverter tn = mapper.getToNativeConverter(returnType);
+ if (tn != null) {
+ returnType = tn.nativeType();
+ }
+ }
+ for (int i=0;i < nativeParamTypes.length;i++) {
+ nativeParamTypes[i] = getNativeType(nativeParamTypes[i]);
+ if (!isAllowableNativeType(nativeParamTypes[i])) {
+ String msg = "Callback argument " + nativeParamTypes[i]
+ + " requires custom type conversion";
+ throw new IllegalArgumentException(msg);
+ }
+ }
+ returnType = getNativeType(returnType);
+ if (!isAllowableNativeType(returnType)) {
+ String msg = "Callback return type " + returnType
+ + " requires custom type conversion";
+ throw new IllegalArgumentException(msg);
+ }
+ cbstruct = createNativeCallback(proxy, PROXY_CALLBACK_METHOD,
+ nativeParamTypes, returnType,
+ callingConvention, false);
+ }
+
+ }
+
+ private Class getNativeType(Class cls) {
+ if (Structure.class.isAssignableFrom(cls)) {
+ // Make sure we can instantiate an argument of this type
+ Structure.newInstance(cls);
+ if (!Structure.ByValue.class.isAssignableFrom(cls))
+ return Pointer.class;
+ }
+ else if (NativeMapped.class.isAssignableFrom(cls)) {
+ return NativeMappedConverter.getInstance(cls).nativeType();
+ }
+ else if (cls == String.class
+ || cls == WString.class
+ || cls == String[].class
+ || cls == WString[].class
+ || Callback.class.isAssignableFrom(cls)) {
+ return Pointer.class;
+ }
+ return cls;
+ }
+
+ private static Method checkMethod(Method m) {
+ if (m.getParameterTypes().length > Function.MAX_NARGS) {
+ String msg = "Method signature exceeds the maximum "
+ + "parameter count: " + m;
+ throw new UnsupportedOperationException(msg);
+ }
+ return m;
+ }
+
+ /** Find the first instance of an interface which implements the Callback
+ * interface or an interface derived from Callback, which defines an
+ * appropriate callback method.
+ */
+ static Class findCallbackClass(Class type) {
+ if (!Callback.class.isAssignableFrom(type)) {
+ throw new IllegalArgumentException(type.getName() + " is not derived from com.sun.jna.Callback");
+ }
+ if (type.isInterface()) {
+ return type;
+ }
+ Class[] ifaces = type.getInterfaces();
+ for (int i=0;i < ifaces.length;i++) {
+ if (Callback.class.isAssignableFrom(ifaces[i])) {
+ try {
+ // Make sure it's got a recognizable callback method
+ getCallbackMethod(ifaces[i]);
+ return ifaces[i];
+ }
+ catch(IllegalArgumentException e) {
+ break;
+ }
+ }
+ }
+ if (Callback.class.isAssignableFrom(type.getSuperclass())) {
+ return findCallbackClass(type.getSuperclass());
+ }
+ return type;
+ }
+
+ private static Method getCallbackMethod(Callback callback) {
+ return getCallbackMethod(findCallbackClass(callback.getClass()));
+ }
+
+ private static Method getCallbackMethod(Class cls) {
+ // Look at only public methods defined by the Callback class
+ Method[] pubMethods = cls.getDeclaredMethods();
+ Method[] classMethods = cls.getMethods();
+ Set pmethods = new HashSet(Arrays.asList(pubMethods));
+ pmethods.retainAll(Arrays.asList(classMethods));
+
+ // Remove Object methods disallowed as callback method names
+ for (Iterator i=pmethods.iterator();i.hasNext();) {
+ Method m = (Method)i.next();
+ if (Callback.FORBIDDEN_NAMES.contains(m.getName())) {
+ i.remove();
+ }
+ }
+ Method[] methods = (Method[])pmethods.toArray(new Method[pmethods.size()]);
+ if (methods.length == 1) {
+ return checkMethod(methods[0]);
+ }
+ for (int i=0;i < methods.length;i++) {
+ Method m = methods[i];
+ if (Callback.METHOD_NAME.equals(m.getName())) {
+ return checkMethod(m);
+ }
+ }
+ String msg = "Callback must implement a single public method, "
+ + "or one public method named '" + Callback.METHOD_NAME + "'";
+ throw new IllegalArgumentException(msg);
+ }
+
+ /** Obtain a pointer to the native glue code for this callback. */
+ public Pointer getTrampoline() {
+ return cbstruct.getPointer(0);
+ }
+
+ /** Free native resources associated with this callback. */
+ protected void finalize() {
+ freeNativeCallback(cbstruct.peer);
+ cbstruct.peer = 0;
+ }
+
+ private Callback getCallback() {
+ return (Callback)get();
+ }
+
+ private static Pointer getNativeFunctionPointer(Callback cb) {
+ if (Proxy.isProxyClass(cb.getClass())) {
+ Object handler = Proxy.getInvocationHandler(cb);
+ if (handler instanceof NativeFunctionHandler) {
+ return ((NativeFunctionHandler)handler).getPointer();
+ }
+ }
+ return null;
+ }
+
+ /** Return a {@link Pointer} to the native function address for the
+ * given callback.
+ */
+ public static Pointer getFunctionPointer(Callback cb) {
+ return getFunctionPointer(cb, false);
+ }
+
+ /** Native code calls this with direct=true. */
+ private static Pointer getFunctionPointer(Callback cb, boolean direct) {
+ Pointer fp = null;
+ if (cb == null) {
+ return null;
+ }
+ if ((fp = getNativeFunctionPointer(cb)) != null) {
+ return fp;
+ }
+ int callingConvention = cb instanceof AltCallingConvention
+ ? Function.ALT_CONVENTION : Function.C_CONVENTION;
+ Map map = direct ? directCallbackMap : callbackMap;
+ synchronized(map) {
+ CallbackReference cbref = (CallbackReference)map.get(cb);
+ if (cbref == null) {
+ cbref = new CallbackReference(cb, callingConvention, direct);
+ map.put(cb, cbref);
+ }
+ return cbref.getTrampoline();
+ }
+ }
+
+ private class DefaultCallbackProxy implements CallbackProxy {
+ private Method callbackMethod;
+ private ToNativeConverter toNative;
+ private FromNativeConverter[] fromNative;
+ public DefaultCallbackProxy(Method callbackMethod, TypeMapper mapper) {
+ this.callbackMethod = callbackMethod;
+ Class[] argTypes = callbackMethod.getParameterTypes();
+ Class returnType = callbackMethod.getReturnType();
+ fromNative = new FromNativeConverter[argTypes.length];
+ if (NativeMapped.class.isAssignableFrom(returnType)) {
+ toNative = NativeMappedConverter.getInstance(returnType);
+ }
+ else if (mapper != null) {
+ toNative = mapper.getToNativeConverter(returnType);
+ }
+ for (int i=0;i < fromNative.length;i++) {
+ if (NativeMapped.class.isAssignableFrom(argTypes[i])) {
+ fromNative[i] = new NativeMappedConverter(argTypes[i]);
+ }
+ else if (mapper != null) {
+ fromNative[i] = mapper.getFromNativeConverter(argTypes[i]);
+ }
+ }
+ if (!callbackMethod.isAccessible()) {
+ try {
+ callbackMethod.setAccessible(true);
+ }
+ catch(SecurityException e) {
+ throw new IllegalArgumentException("Callback method is inaccessible, make sure the interface is public: " + callbackMethod);
+ }
+ }
+ }
+
+ private Object invokeCallback(Object[] args) {
+ Class[] paramTypes = callbackMethod.getParameterTypes();
+ Object[] callbackArgs = new Object[args.length];
+
+ // convert basic supported types to appropriate Java parameter types
+ for (int i=0;i < args.length;i++) {
+ Class type = paramTypes[i];
+ Object arg = args[i];
+ if (fromNative[i] != null) {
+ FromNativeContext context =
+ new CallbackParameterContext(type, callbackMethod, args, i);
+ callbackArgs[i] = fromNative[i].fromNative(arg, context);
+ }
+ else {
+ callbackArgs[i] = convertArgument(arg, type);
+ }
+ }
+
+ Object result = null;
+ Callback cb = getCallback();
+ if (cb != null) {
+ try {
+ result = convertResult(callbackMethod.invoke(cb, callbackArgs));
+ }
+ catch (IllegalArgumentException e) {
+ Native.getCallbackExceptionHandler().uncaughtException(cb, e);
+ }
+ catch (IllegalAccessException e) {
+ Native.getCallbackExceptionHandler().uncaughtException(cb, e);
+ }
+ catch (InvocationTargetException e) {
+ Native.getCallbackExceptionHandler().uncaughtException(cb, e.getTargetException());
+ }
+ }
+ // Synch any structure arguments back to native memory
+ for (int i=0;i < callbackArgs.length;i++) {
+ if (callbackArgs[i] instanceof Structure
+ && !(callbackArgs[i] instanceof Structure.ByValue)) {
+ ((Structure)callbackArgs[i]).autoWrite();
+ }
+ }
+
+ return result;
+ }
+ /** Called from native code. All arguments are in an array of
+ * Object as the first argument. Converts all arguments to types
+ * required by the actual callback method signature, and converts
+ * the result back into an appropriate native type.
+ * This method <em>must not</em> throw exceptions.
+ */
+ public Object callback(Object[] args) {
+ try {
+ return invokeCallback(args);
+ }
+ catch (Throwable t) {
+ Native.getCallbackExceptionHandler().uncaughtException(getCallback(), t);
+ return null;
+ }
+ }
+
+ /** Convert argument from its basic native type to the given
+ * Java parameter type.
+ */
+ private Object convertArgument(Object value, Class dstType) {
+ if (value instanceof Pointer) {
+ if (dstType == String.class) {
+ value = ((Pointer)value).getString(0);
+ }
+ else if (dstType == WString.class) {
+ value = new WString(((Pointer)value).getString(0, true));
+ }
+ else if (dstType == String[].class
+ || dstType == WString[].class) {
+ value = ((Pointer)value).getStringArray(0, dstType == WString[].class);
+ }
+ else if (Callback.class.isAssignableFrom(dstType)) {
+ value = getCallback(dstType, (Pointer)value);
+ }
+ else if (Structure.class.isAssignableFrom(dstType)) {
+ Structure s = Structure.newInstance(dstType);
+ // If passed by value, don't hold onto the pointer, which
+ // is only valid for the duration of the callback call
+ if (Structure.ByValue.class.isAssignableFrom(dstType)) {
+ byte[] buf = new byte[s.size()];
+ ((Pointer)value).read(0, buf, 0, buf.length);
+ s.getPointer().write(0, buf, 0, buf.length);
+ }
+ else {
+ s.useMemory((Pointer)value);
+ }
+ s.read();
+ value = s;
+ }
+ }
+ else if ((boolean.class == dstType || Boolean.class == dstType)
+ && value instanceof Number) {
+ value = Function.valueOf(((Number)value).intValue() != 0);
+ }
+ return value;
+ }
+
+ private Object convertResult(Object value) {
+ if (toNative != null) {
+ value = toNative.toNative(value, new CallbackResultContext(callbackMethod));
+ }
+ if (value == null)
+ return null;
+ Class cls = value.getClass();
+ if (Structure.class.isAssignableFrom(cls)) {
+ if (Structure.ByValue.class.isAssignableFrom(cls)) {
+ return value;
+ }
+ return ((Structure)value).getPointer();
+ }
+ else if (cls == boolean.class || cls == Boolean.class) {
+ return Boolean.TRUE.equals(value) ?
+ Function.INTEGER_TRUE : Function.INTEGER_FALSE;
+ }
+ else if (cls == String.class || cls == WString.class) {
+ return getNativeString(value, cls == WString.class);
+ }
+ else if (cls == String[].class || cls == WString.class) {
+ StringArray sa = cls == String[].class
+ ? new StringArray((String[])value)
+ : new StringArray((WString[])value);
+ // Delay GC until array itself is GC'd.
+ allocations.put(value, sa);
+ return sa;
+ }
+ else if (Callback.class.isAssignableFrom(cls)) {
+ return getFunctionPointer((Callback)value);
+ }
+ return value;
+ }
+ public Class[] getParameterTypes() {
+ return callbackMethod.getParameterTypes();
+ }
+ public Class getReturnType() {
+ return callbackMethod.getReturnType();
+ }
+ }
+
+ /** Provide invocation handling for an auto-generated Java interface proxy
+ * for a native function pointer.
+ * Cf. Library.Handler
+ */
+ private static class NativeFunctionHandler implements InvocationHandler {
+ private Function function;
+ private Map options;
+
+ public NativeFunctionHandler(Pointer address, int callingConvention, Map options) {
+ this.function = new Function(address, callingConvention);
+ this.options = options;
+ }
+
+ /** Chain invocation to the native function. */
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (Library.Handler.OBJECT_TOSTRING.equals(method)) {
+ String str = "Proxy interface to " + function;
+ Method m = (Method)options.get(Function.OPTION_INVOKING_METHOD);
+ Class cls = findCallbackClass(m.getDeclaringClass());
+ str += " (" + cls.getName() + ")";
+
+ return str;
+ }
+ else if (Library.Handler.OBJECT_HASHCODE.equals(method)) {
+ return new Integer(hashCode());
+ }
+ else if (Library.Handler.OBJECT_EQUALS.equals(method)) {
+ Object o = args[0];
+ if (o != null && Proxy.isProxyClass(o.getClass())) {
+ return Function.valueOf(Proxy.getInvocationHandler(o) == this);
+ }
+ return Boolean.FALSE;
+ }
+ if (Function.isVarArgs(method)) {
+ args = Function.concatenateVarArgs(args);
+ }
+ return function.invoke(method.getReturnType(), args, options);
+ }
+
+ public Pointer getPointer() {
+ return function;
+ }
+ }
+ /** Returns whether the given class is supported in native code.
+ * Other types (String, WString, Structure, arrays, NativeMapped,
+ * etc) are supported in the Java library.
+ */
+ private static boolean isAllowableNativeType(Class cls) {
+ return cls == void.class || cls == Void.class
+ || cls == boolean.class || cls == Boolean.class
+ || cls == byte.class || cls == Byte.class
+ || cls == short.class || cls == Short.class
+ || cls == char.class || cls == Character.class
+ || cls == int.class || cls == Integer.class
+ || cls == long.class || cls == Long.class
+ || cls == float.class || cls == Float.class
+ || cls == double.class || cls == Double.class
+ || (Structure.ByValue.class.isAssignableFrom(cls)
+ && Structure.class.isAssignableFrom(cls))
+ || Pointer.class.isAssignableFrom(cls);
+ }
+
+ private static Pointer getNativeString(Object value, boolean wide) {
+ if (value != null) {
+ NativeString ns = new NativeString(value.toString(), wide);
+ // Delay GC until string itself is GC'd.
+ allocations.put(value, ns);
+ return ns.getPointer();
+ }
+ return null;
+ }
+
+ /** Create a native trampoline to delegate execution to the Java callback.
+ */
+ private static synchronized native Pointer createNativeCallback(Callback callback,
+ Method method,
+ Class[] parameterTypes,
+ Class returnType,
+ int callingConvention, boolean direct);
+ /** Free the given callback trampoline. */
+ private static synchronized native void freeNativeCallback(long ptr);
+}
12 src/main/java/com/sun/jna/CallbackResultContext.java
@@ -0,0 +1,12 @@
+package com.sun.jna;
+
+import java.lang.reflect.Method;
+
+/** Conversion context from a Java {@link Callback} result to a native value. */
+public class CallbackResultContext extends ToNativeContext {
+ private Method method;
+ CallbackResultContext(Method callbackMethod) {
+ this.method = callbackMethod;
+ }
+ public Method getMethod() { return method; }
+}
146 src/main/java/com/sun/jna/DefaultTypeMapper.java
@@ -0,0 +1,146 @@
+/* Copyright (c) 2007 Wayne Meissner, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+package com.sun.jna;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/** Provide custom mappings to and from native types. The default lookup
+ * checks classes corresponding to converters in the order added; if the
+ * class to be converted is an instance of the converter's registered class,
+ * the converter will be used.<p>
+ * Derived classes should install additional converters using
+ * {@link #addToNativeConverter}
+ * and/or {@link #addFromNativeConverter} in the default constructor. Classes
+ * for primitive types will automatically register for the corresponding
+ * Object type and vice versa (i.e. you don't have to register both
+ * <code>int.class</code> and <code>Integer.class</code>).
+ * If you want different mapping behavior than the default, simply override
+ * {@link #getToNativeConverter} and {@link #getFromNativeConverter}.
+ * @see Library#OPTION_TYPE_MAPPER
+ */
+public class DefaultTypeMapper implements TypeMapper {
+ private static class Entry {
+ public Class type;
+ public Object converter;
+ public Entry(Class type, Object converter) {
+ this.type = type;
+ this.converter = converter;
+ }
+ }
+ private List toNativeConverters = new ArrayList();
+ private List fromNativeConverters = new ArrayList();
+ private Class getAltClass(Class cls) {
+ if (cls == Boolean.class) {
+ return boolean.class;
+ }
+ else if (cls == boolean.class) {
+ return Boolean.class;
+ }
+ else if (cls == Byte.class) {
+ return byte.class;
+ }
+ else if (cls == byte.class) {
+ return Byte.class;
+ }
+ else if (cls == Character.class) {
+ return char.class;
+ }
+ else if (cls == char.class) {
+ return Character.class;
+ }
+ else if (cls == Short.class) {
+ return short.class;
+ }
+ else if (cls == short.class) {
+ return Short.class;
+ }
+ else if (cls == Integer.class) {
+ return int.class;
+ }
+ else if (cls == int.class) {
+ return Integer.class;
+ }
+ else if (cls == Long.class) {
+ return long.class;
+ }
+ else if (cls == long.class) {
+ return Long.class;
+ }
+ else if (cls == Float.class) {
+ return float.class;
+ }
+ else if (cls == float.class) {
+ return Float.class;
+ }
+ else if (cls == Double.class) {
+ return double.class;
+ }
+ else if (cls == double.class) {
+ return Double.class;
+ }
+ return null;
+ }
+ /** Add a {@link ToNativeConverter} to define the conversion into a native
+ * type from arguments of the given Java type. Converters are
+ * checked for in the order added.
+ */
+ public void addToNativeConverter(Class cls, ToNativeConverter converter) {
+ toNativeConverters.add(new Entry(cls, converter));
+ Class alt = getAltClass(cls);
+ if (alt != null) {
+ toNativeConverters.add(new Entry(alt, converter));
+ }
+ }
+ /** Add a {@link FromNativeConverter} to convert a native result type into the
+ * given Java type. Converters are checked for in the order added.
+ */
+ public void addFromNativeConverter(Class cls, FromNativeConverter converter) {
+ fromNativeConverters.add(new Entry(cls, converter));
+ Class alt = getAltClass(cls);
+ if (alt != null) {
+ fromNativeConverters.add(new Entry(alt, converter));
+ }
+ }
+ /** Add a {@link TypeConverter} to provide bidirectional mapping between
+ * a native and Java type.
+ */
+ protected void addTypeConverter(Class cls, TypeConverter converter) {
+ addFromNativeConverter(cls, converter);
+ addToNativeConverter(cls, converter);
+ }
+
+ private Object lookupConverter(Class javaClass, List converters) {
+ for (Iterator i=converters.iterator();i.hasNext();) {
+ Entry entry = (Entry)i.next();
+ if (entry.type.isAssignableFrom(javaClass)) {
+ return entry.converter;
+ }
+ }
+ return null;
+ }
+ /* (non-Javadoc)
+ * @see com.sun.jna.TypeMapper#getFromNativeConverter(java.lang.Class)
+ */
+ public FromNativeConverter getFromNativeConverter(Class javaType) {
+ return (FromNativeConverter)lookupConverter(javaType, fromNativeConverters);
+ }
+ /* (non-Javadoc)
+ * @see com.sun.jna.TypeMapper#getToNativeConverter(java.lang.Class)
+ */
+ public ToNativeConverter getToNativeConverter(Class javaType) {
+ return (ToNativeConverter)lookupConverter(javaType, toNativeConverters);
+ }
+}
25 src/main/java/com/sun/jna/FromNativeContext.java
@@ -0,0 +1,25 @@
+/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+/** Provides context for converting a native value into a Java type. */
+public class FromNativeContext {
+ private Class type;
+ FromNativeContext(Class javaType) {
+ this.type = javaType;
+ }
+ /** The desired Java type of the result. */
+ public Class getTargetType() {
+ return type;
+ }
+}
24 src/main/java/com/sun/jna/FromNativeConverter.java
@@ -0,0 +1,24 @@
+/* Copyright (c) 2007 Wayne Meissner, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+package com.sun.jna;
+
+/** Define conversion from a native type to the appropriate Java type. */
+public interface FromNativeConverter {
+ /** Convert the given native object into its Java representation using
+ * the given context.
+ */
+ Object fromNative(Object nativeValue, FromNativeContext context);
+ /** Indicate the native type used by this converter. */
+ Class nativeType();
+}
840 src/main/java/com/sun/jna/Function.java
@@ -0,0 +1,840 @@
+/* This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * An abstraction for a native function pointer. An instance of
+ * <code>Function</code> represents a pointer to some native function.
+ * {@link #invoke(Class,Object[],Map)} is the primary means to call
+ * the function. <p/>
+ * <a name=callflags></a>
+ * Function call behavior may be modified by passing one of the following call
+ * flags:
+ * <ul>
+ * <li>{@link Function#C_CONVENTION} Use C calling convention (default)
+ * <li>{@link Function#ALT_CONVENTION} Use alternate calling convention (e.g. stdcall)
+ * <li>{@link Function#THROW_LAST_ERROR} Throw a {@link LastErrorException} if
+ * the native function sets the system error to a non-zero value (errno or
+ * GetLastError). Setting this flag will cause the system error to be cleared
+ * prior to native function invocation.
+ * </ul>
+ *
+ * @author Sheng Liang, originator
+ * @author Todd Fast, suitability modifications
+ * @author Timothy Wall
+ * @see Pointer
+ */
+public class Function extends Pointer {
+ /** Any argument which implements this interface will have the
+ * {@link #read} method called immediately after function invocation.
+ */
+ public interface PostCallRead {
+ /** Perform any necessary post-call synchronization. Normally this
+ * just means reading from native memory any changes made by
+ * the native function call.
+ */
+ void read();
+ }
+
+ /** Maximum number of arguments supported by a JNA function call. */
+ public static final int MAX_NARGS = 256;
+
+ /** Standard C calling convention. */
+ public static final int C_CONVENTION = 0;
+ /** First alternate convention (currently used only for w32 stdcall). */
+ public static final int ALT_CONVENTION = 1;
+
+ private static final int MASK_CC = 0x3;
+ /** Whether to throw an exception if last error is non-zero after call. */
+ public static final int THROW_LAST_ERROR = (1<<2);
+
+ static final Integer INTEGER_TRUE = new Integer(-1);
+ static final Integer INTEGER_FALSE = new Integer(0);
+
+ /**
+ * Obtain a <code>Function</code> representing a native
+ * function that follows the standard "C" calling convention.
+ *
+ * <p>The allocated instance represents a pointer to the named native
+ * function from the named library, called with the standard "C" calling
+ * convention.
+ *
+ * @param libraryName
+ * Library in which to find the native function
+ * @param functionName
+ * Name of the native function to be linked with
+ * @throws {@link UnsatisfiedLinkError} if the library is not found or
+ * the given function name is not found within the library.
+ */
+ public static Function getFunction(String libraryName, String functionName) {
+ return NativeLibrary.getInstance(libraryName).getFunction(functionName);
+ }
+
+ /**
+ * Obtain a <code>Function</code> representing a native
+ * function.
+ *
+ * <p>The allocated instance represents a pointer to the named native
+ * function from the named library.
+ *
+ * @param libraryName
+ * Library in which to find the function
+ * @param functionName
+ * Name of the native function to be linked with
+ * @param callFlags
+ * Function <a href="#callflags">call flags</a>
+ *
+ * @throws {@link UnsatisfiedLinkError} if the library is not found or
+ * the given function name is not found within the library.
+ */
+ public static Function getFunction(String libraryName, String functionName, int callFlags) {
+ return NativeLibrary.getInstance(libraryName).getFunction(functionName, callFlags);
+ }
+
+ /**
+ * Obtain a <code>Function</code> representing a native
+ * function pointer. In general, this function should be used by dynamic
+ * languages; Java code should allow JNA to bind to a specific Callback
+ * interface instead by defining a return type or Structure field type.
+ *
+ * <p>The allocated instance represents a pointer to the native
+ * function pointer.
+ *
+ * @param p Native function pointer
+ */
+ public static Function getFunction(Pointer p) {
+ return getFunction(p, 0);
+ }
+
+ /**
+ * Obtain a <code>Function</code> representing a native
+ * function pointer. In general, this function should be used by dynamic
+ * languages; Java code should allow JNA to bind to a specific Callback
+ * interface instead by defining a return type or Structure field type.
+ *
+ * <p>The allocated instance represents a pointer to the native
+ * function pointer.
+ *
+ * @param p
+ * Native function pointer
+ * @param callFlags
+ * Function <a href="#callflags">call flags</a>
+ */
+ public static Function getFunction(Pointer p, int callFlags) {
+ return new Function(p, callFlags);
+ }
+
+ // Keep a reference to the NativeLibrary so it does not get garbage
+ // collected until the function is
+ private NativeLibrary library;
+ private final String functionName;
+ int callFlags;
+ final Map options;
+
+ /** For internal JNA use. */
+ static final String OPTION_INVOKING_METHOD = "invoking-method";
+
+ /**
+ * Create a new <code>Function</code> that is linked with a native
+ * function that follows the given calling convention.
+ *
+ * <p>The allocated instance represents a pointer to the named native
+ * function from the supplied library, called with the given calling
+ * convention.
+ *
+ * @param library
+ * {@link NativeLibrary} in which to find the function
+ * @param functionName
+ * Name of the native function to be linked with
+ * @param callFlags
+ * Function <a href="#callflags">call flags</a>
+ * @throws {@link UnsatisfiedLinkError} if the given function name is
+ * not found within the library.
+ */
+ Function(NativeLibrary library, String functionName, int callFlags) {
+ checkCallingConvention(callFlags & MASK_CC);
+ if (functionName == null)
+ throw new NullPointerException("Function name must not be null");
+ this.library = library;
+ this.functionName = functionName;
+ this.callFlags = callFlags;
+ this.options = library.options;
+ try {
+ this.peer = library.getSymbolAddress(functionName);
+ }
+ catch(UnsatisfiedLinkError e) {
+ throw new UnsatisfiedLinkError("Error looking up function '"
+ + functionName + "': "
+ + e.getMessage());
+ }
+ }
+
+ /**
+ * Create a new <code>Function</code> that is linked with a native
+ * function that follows the given calling convention.
+ *
+ * <p>The allocated instance represents a pointer to the given
+ * function address, called with the given calling
+ * convention.
+ *
+ * @param functionAddress
+ * Address of the native function
+ * @param callFlags
+ * Function <a href="#callflags">call flags</a>
+ */
+ Function(Pointer functionAddress, int callFlags) {
+ checkCallingConvention(callFlags & MASK_CC);
+ if (functionAddress == null
+ || functionAddress.peer == 0) {
+ throw new NullPointerException("Function address may not be null");
+ }
+ this.functionName = functionAddress.toString();
+ this.callFlags = callFlags;
+ this.peer = functionAddress.peer;
+ this.options = Collections.EMPTY_MAP;
+ }
+
+ private void checkCallingConvention(int convention)
+ throws IllegalArgumentException {
+ switch(convention) {
+ case C_CONVENTION:
+ case ALT_CONVENTION:
+ break;
+ default:
+ throw new IllegalArgumentException("Unrecognized calling convention: "
+ + convention);
+ }
+ }
+
+ public String getName() {
+ return functionName;
+ }
+
+
+ public int getCallingConvention() {
+ return callFlags & MASK_CC;
+ }
+
+ /** Invoke the native function with the given arguments, returning the
+ * native result as an Object.
+ */
+ public Object invoke(Class returnType, Object[] inArgs) {
+ return invoke(returnType, inArgs, this.options);
+ }
+
+ /** Invoke the native function with the given arguments, returning the
+ * native result as an Object.
+ */
+ public Object invoke(Class returnType, Object[] inArgs, Map options) {
+ // Clone the argument array to obtain a scratch space for modified
+ // types/values
+ Object[] args = { };
+ if (inArgs != null) {
+ if (inArgs.length > MAX_NARGS) {
+ throw new UnsupportedOperationException("Maximum argument count is " + MAX_NARGS);
+ }
+ args = new Object[inArgs.length];
+ System.arraycopy(inArgs, 0, args, 0, args.length);
+ }
+
+ TypeMapper mapper =
+ (TypeMapper)options.get(Library.OPTION_TYPE_MAPPER);
+ Method invokingMethod = (Method)options.get(OPTION_INVOKING_METHOD);
+ boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS));
+ for (int i=0; i < args.length; i++) {
+ args[i] = convertArgument(args, i, invokingMethod,
+ mapper, allowObjects);
+ }
+
+ Class nativeType = returnType;
+ FromNativeConverter resultConverter = null;
+ if (NativeMapped.class.isAssignableFrom(returnType)) {
+ NativeMappedConverter tc = NativeMappedConverter.getInstance(returnType);
+ resultConverter = tc;
+ nativeType = tc.nativeType();
+ }
+ else if (mapper != null) {
+ resultConverter = mapper.getFromNativeConverter(returnType);
+ if (resultConverter != null) {
+ nativeType = resultConverter.nativeType();
+ }
+ }
+
+ Object result = invoke(args, nativeType, allowObjects);
+
+ // Convert the result to a custom value/type if appropriate
+ if (resultConverter != null) {
+ FromNativeContext context;
+
+ if (invokingMethod != null) {
+ context = new MethodResultContext(returnType, this, inArgs, invokingMethod);
+ } else {
+ context = new FunctionResultContext(returnType, this, inArgs);
+ }
+ result = resultConverter.fromNative(result, context);
+ }
+
+ // Sync all memory which might have been modified by the native call
+ if (inArgs != null) {
+ for (int i=0; i < inArgs.length; i++) {
+ Object inArg = inArgs[i];
+ if (inArg == null)
+ continue;
+ if (inArg instanceof Structure) {
+ if (!(inArg instanceof Structure.ByValue)) {
+ ((Structure)inArg).autoRead();
+ }
+ }
+ else if (args[i] instanceof PostCallRead) {
+ ((PostCallRead)args[i]).read();
+ if (args[i] instanceof PointerArray) {
+ PointerArray array = (PointerArray)args[i];
+ if (Structure.ByReference[].class.isAssignableFrom(inArg.getClass())) {
+ Class type = inArg.getClass().getComponentType();
+ Structure[] ss = (Structure[])inArg;
+ for (int si=0;si < ss.length;si++) {
+ Pointer p = array.getPointer(Pointer.SIZE * si);
+ ss[si] = Structure.updateStructureByReference(type, ss[si], p);
+ }
+ }
+ }
+ }
+ else if (Structure[].class.isAssignableFrom(inArg.getClass())) {
+ Structure.autoRead((Structure[])inArg);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /** @see NativeLibrary#NativeLibrary(String,String,long,Map) implementation */
+ Object invoke(Object[] args, Class returnType, boolean allowObjects) {
+ Object result = null;
+ if (returnType == null || returnType==void.class || returnType==Void.class) {
+ invokeVoid(callFlags, args);
+ result = null;
+ }
+ else if (returnType==boolean.class || returnType==Boolean.class) {
+ result = valueOf(invokeInt(callFlags, args) != 0);
+ }
+ else if (returnType==byte.class || returnType==Byte.class) {
+ result = new Byte((byte)invokeInt(callFlags, args));
+ }
+ else if (returnType==short.class || returnType==Short.class) {
+ result = new Short((short)invokeInt(callFlags, args));
+ }
+ else if (returnType==char.class || returnType==Character.class) {
+ result = new Character((char)invokeInt(callFlags, args));
+ }
+ else if (returnType==int.class || returnType==Integer.class) {
+ result = new Integer(invokeInt(callFlags, args));
+ }
+ else if (returnType==long.class || returnType==Long.class) {
+ result = new Long(invokeLong(callFlags, args));
+ }
+ else if (returnType==float.class || returnType==Float.class) {
+ result = new Float(invokeFloat(callFlags, args));
+ }
+ else if (returnType==double.class || returnType==Double.class) {
+ result = new Double(invokeDouble(callFlags, args));
+ }
+ else if (returnType==String.class) {
+ result = invokeString(callFlags, args, false);
+ }
+ else if (returnType==WString.class) {
+ String s = invokeString(callFlags, args, true);
+ if (s != null) {
+ result = new WString(s);
+ }
+ }
+ else if (Pointer.class.isAssignableFrom(returnType)) {
+ result = invokePointer(callFlags, args);
+ }
+ else if (Structure.class.isAssignableFrom(returnType)) {
+ if (Structure.ByValue.class.isAssignableFrom(returnType)) {
+ Structure s =
+ invokeStructure(callFlags, args,
+ Structure.newInstance(returnType));
+ s.autoRead();
+ result = s;
+ }
+ else {
+ result = invokePointer(callFlags, args);
+ if (result != null) {
+ Structure s = Structure.newInstance(returnType);
+ s.useMemory((Pointer)result);
+ s.autoRead();
+ result = s;
+ }
+ }
+ }
+ else if (Callback.class.isAssignableFrom(returnType)) {
+ result = invokePointer(callFlags, args);
+ if (result != null) {
+ result = CallbackReference.getCallback(returnType, (Pointer)result);
+ }
+ }
+ else if (returnType==String[].class) {
+ Pointer p = invokePointer(callFlags, args);
+ if (p != null) {
+ result = p.getStringArray(0);
+ }
+ }
+ else if (returnType==WString[].class) {
+ Pointer p = invokePointer(callFlags, args);
+ if (p != null) {
+ String[] arr = p.getStringArray(0, true);
+ WString[] warr = new WString[arr.length];
+ for (int i=0;i < arr.length;i++) {
+ warr[i] = new WString(arr[i]);
+ }
+ result = warr;
+ }
+ }
+ else if (returnType==Pointer[].class) {
+ Pointer p = invokePointer(callFlags, args);
+ if (p != null) {
+ result = p.getPointerArray(0);
+ }
+ }
+ else if (allowObjects) {
+ result = invokeObject(callFlags, args);
+ if (result != null
+ && !returnType.isAssignableFrom(result.getClass())) {
+ throw new ClassCastException("Return type " + returnType
+ + " does not match result "
+ + result.getClass());
+ }
+ }
+ else {
+ throw new IllegalArgumentException("Unsupported return type "
+ + returnType
+ + " in function " + getName());
+ }
+ return result;
+ }
+
+ private Object convertArgument(Object[] args, int index,
+ Method invokingMethod, TypeMapper mapper,
+ boolean allowObjects) {
+ Object arg = args[index];
+ if (arg != null) {
+ Class type = arg.getClass();
+ ToNativeConverter converter = null;
+ if (NativeMapped.class.isAssignableFrom(type)) {
+ converter = NativeMappedConverter.getInstance(type);
+ }
+ else if (mapper != null) {
+ converter = mapper.getToNativeConverter(type);
+ }
+ if (converter != null) {
+ ToNativeContext context;
+ if (invokingMethod != null) {
+ context = new MethodParameterContext(this, args, index, invokingMethod) ;
+ }
+ else {
+ context = new FunctionParameterContext(this, args, index);
+ }
+ arg = converter.toNative(arg, context);
+ }
+ }
+ if (arg == null || isPrimitiveArray(arg.getClass())) {
+ return arg;
+ }
+ Class argClass = arg.getClass();
+ // Convert Structures to native pointers
+ if (arg instanceof Structure) {
+ Structure struct = (Structure)arg;
+ struct.autoWrite();
+ if (struct instanceof Structure.ByValue) {
+ // Double-check against the method signature, if available
+ Class ptype = struct.getClass();
+ if (invokingMethod != null) {
+ Class[] ptypes = invokingMethod.getParameterTypes();
+ if (isVarArgs(invokingMethod)) {
+ if (index < ptypes.length-1) {
+ ptype = ptypes[index];
+ }
+ else {
+ Class etype = ptypes[ptypes.length-1].getComponentType();
+ if (etype != Object.class) {
+ ptype = etype;
+ }
+ }
+ }
+ else {
+ ptype = ptypes[index];
+ }
+ }
+ if (Structure.ByValue.class.isAssignableFrom(ptype)) {
+ return struct;
+ }
+ }
+ return struct.getPointer();
+ }
+ // Convert Callback to Pointer
+ else if (arg instanceof Callback) {
+ return CallbackReference.getFunctionPointer((Callback)arg);
+ }
+ // String arguments are converted to native pointers here rather
+ // than in native code so that the values will be valid until
+ // this method returns.
+ // Convert String to native pointer (const)
+ else if (arg instanceof String) {
+ return new NativeString((String)arg, false).getPointer();
+ }
+ // Convert WString to native pointer (const)
+ else if (arg instanceof WString) {
+ return new NativeString(arg.toString(), true).getPointer();
+ }
+ // Default conversion of boolean to int; if you want something
+ // different, use a ToNativeConverter
+ else if (arg instanceof Boolean) {
+ return Boolean.TRUE.equals(arg) ? INTEGER_TRUE : INTEGER_FALSE;
+ }
+ else if (String[].class == argClass) {
+ return new StringArray((String[])arg);
+ }
+ else if (WString[].class == argClass) {
+ return new StringArray((WString[])arg);
+ }
+ else if (Pointer[].class == argClass) {
+ return new PointerArray((Pointer[])arg);
+ }
+ else if (NativeMapped[].class.isAssignableFrom(argClass)) {
+ return new NativeMappedArray((NativeMapped[])arg);
+ }
+ else if (Structure[].class.isAssignableFrom(argClass)) {
+ Structure[] ss = (Structure[])arg;
+ Class type = argClass.getComponentType();
+ boolean byRef = Structure.ByReference.class.isAssignableFrom(type);
+ if (byRef) {
+ Pointer[] pointers = new Pointer[ss.length + 1];
+ for (int i=0;i < ss.length;i++) {
+ pointers[i] = ss[i] != null ? ss[i].getPointer() : null;
+ }
+ return new PointerArray(pointers);
+ }
+ else if (ss.length == 0) {
+ throw new IllegalArgumentException("Structure array must have non-zero length");
+ }
+ else if (ss[0] == null) {
+ Structure.newInstance(type).toArray(ss);
+ return ss[0].getPointer();
+ }
+ else {
+ Structure.autoWrite(ss);
+ return ss[0].getPointer();
+ }
+ }
+ else if (argClass.isArray()){
+ throw new IllegalArgumentException("Unsupported array argument type: "
+ + argClass.getComponentType());
+ }
+ else if (allowObjects) {
+ return arg;
+ }
+ else if (!Native.isSupportedNativeType(arg.getClass())) {
+ throw new IllegalArgumentException("Unsupported argument type "
+ + arg.getClass().getName()
+ + " at parameter " + index
+ + " of function " + getName());
+ }
+ return arg;
+ }
+
+ private boolean isPrimitiveArray(Class argClass) {
+ return argClass.isArray()
+ && argClass.getComponentType().isPrimitive();
+ }
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @return The value returned by the target native function
+ */
+ private native int invokeInt(int callFlags, Object[] args);
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @return The value returned by the target native function
+ */
+ private native long invokeLong(int callFlags, Object[] args);
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param args
+ * Arguments to pass to the native function
+ */
+ public void invoke(Object[] args) {
+ invoke(Void.class, args);
+ }
+
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ */
+ private native void invokeVoid(int callFlags, Object[] args);
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @return The value returned by the target native function
+ */
+ private native float invokeFloat(int callFlags, Object[] args);
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @return The value returned by the target native function
+ */
+ private native double invokeDouble(int callFlags, Object[] args);
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @param wide whether the native string uses <code>wchar_t</code>;
+ * if false, <code>char</code> is assumed
+ * @return The value returned by the target native function, as a String
+ */
+ private String invokeString(int callFlags, Object[] args, boolean wide) {
+ Pointer ptr = invokePointer(callFlags, args);
+ String s = null;
+ if (ptr != null) {
+ if (wide)
+ s = ptr.getString(0, wide);
+ else
+ s = ptr.getString(0);
+ }
+ return s;
+ }
+
+ /**
+ * Call the native function being represented by this object
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @return The native pointer returned by the target native function
+ */
+ private native Pointer invokePointer(int callFlags, Object[] args);
+
+ /**
+ * Call the native function being represented by this object, returning
+ * a struct by value.
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @param result Pre-allocated structure to hold the result
+ * @return The passed-in struct argument
+ */
+ private native Structure invokeStructure(int callFlags, Object[] args,
+ Structure result);
+
+ /**
+ * Call the native function being represented by this object, returning
+ * a Java <code>Object</code>.
+ *
+ * @param callFlags calling convention to be used
+ * @param args
+ * Arguments to pass to the native function
+ * @return The returned Java <code>Object</code>
+ */
+ private native Object invokeObject(int callFlags, Object[] args);
+
+ /** Provide a human-readable representation of this object. */
+ public String toString() {
+ if (library != null) {
+ return "native function " + functionName + "(" + library.getName()
+ + ")@0x" + Long.toHexString(peer);
+ }
+ return "native function@0x" + Long.toHexString(peer);
+ }
+
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invokeObject(Object.class, args)}.
+ */
+ public Object invokeObject(Object[] args) {
+ return invoke(Object.class, args);
+ }
+
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(Pointer.class, args)}.
+ */
+ public Pointer invokePointer(Object[] args) {
+ return (Pointer)invoke(Pointer.class, args);
+ }
+
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(String.class, args)}
+ * or {@link #invoke(Class,Object[]) invoke(WString.class, args)}
+ * @param args Arguments passed to native function
+ * @param wide Whether the return value is of type <code>wchar_t*</code>;
+ * if false, the return value is of type <code>char*</code>.
+ */
+ public String invokeString(Object[] args, boolean wide) {
+ Object o = invoke(wide ? WString.class : String.class, args);
+ return o != null ? o.toString() : null;
+ }
+
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(Integer.class, args)}.
+ */
+ public int invokeInt(Object[] args) {
+ return ((Integer)invoke(Integer.class, args)).intValue();
+ }
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(Long.class, args)}.
+ */
+ public long invokeLong(Object[] args) {
+ return ((Long)invoke(Long.class, args)).longValue();
+ }
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(Float.class, args)}.
+ */
+ public float invokeFloat(Object[] args) {
+ return ((Float)invoke(Float.class, args)).floatValue();
+ }
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(Double.class, args)}.
+ */
+ public double invokeDouble(Object[] args) {
+ return ((Double)invoke(Double.class, args)).doubleValue();
+ }
+ /** Convenience method for
+ * {@link #invoke(Class,Object[]) invoke(Void.class, args)}.
+ */
+ public void invokeVoid(Object[] args) {
+ invoke(Void.class, args);
+ }
+
+ /** Two function pointers are equal if they share the same peer address
+ * and calling convention.
+ */
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null) return false;
+ if (o.getClass() == getClass()) {
+ Function other = (Function)o;
+ return other.callFlags == this.callFlags
+ && other.options.equals(this.options)
+ && other.peer == this.peer;
+ }
+ return false;
+ }
+
+ /** Concatenate varargs with normal args to obtain a simple argument
+ * array.
+ */
+ static Object[] concatenateVarArgs(Object[] inArgs) {
+ // If the final argument is an array of something other than
+ // primitives, Structure, or String, treat it as varargs and
+ // concatenate the previous arguments with the varargs elements.
+ if (inArgs != null && inArgs.length > 0) {
+ Object lastArg = inArgs[inArgs.length-1];
+ Class argType = lastArg != null ? lastArg.getClass() : null;
+ if (argType != null && argType.isArray()) {
+ Object[] varArgs = (Object[])lastArg;
+ Object[] fullArgs = new Object[inArgs.length+varArgs.length];
+ System.arraycopy(inArgs, 0, fullArgs, 0, inArgs.length-1);
+ System.arraycopy(varArgs, 0, fullArgs, inArgs.length-1, varArgs.length);
+ // For convenience, always append a NULL argument to the end
+ // of varargs, whether the called API requires it or not. If
+ // it is not needed, it will be ignored, but if it *is*
+ // required, it avoids forcing the Java client to always
+ // explicitly add it.
+ fullArgs[fullArgs.length-1] = null;
+ inArgs = fullArgs;
+ }
+ }
+ return inArgs;
+ }
+
+ /** Varargs are only supported on 1.5+. */
+ static boolean isVarArgs(Method m) {
+ try {
+ Method v = m.getClass().getMethod("isVarArgs", new Class[0]);
+ return Boolean.TRUE.equals(v.invoke(m, new Object[0]));
+ }
+ catch (SecurityException e) {
+ }
+ catch (NoSuchMethodException e) {
+ }
+ catch (IllegalArgumentException e) {
+ }
+ catch (IllegalAccessException e) {
+ }
+ catch (InvocationTargetException e) {
+ }
+ return false;
+ }
+
+ private static class NativeMappedArray extends Memory implements PostCallRead {
+ private final NativeMapped[] original;
+ public NativeMappedArray(NativeMapped[] arg) {
+ super(Native.getNativeSize(arg.getClass(), arg));
+ this.original = arg;
+ Class nativeType = arg.getClass().getComponentType();
+ setValue(0, original, original.getClass());
+ }
+ public void read() {
+ getValue(0, original.getClass(), original);
+ }
+ }
+
+ private static class PointerArray extends Memory implements PostCallRead {
+ private final Pointer[] original;
+ public PointerArray(Pointer[] arg) {
+ super(Pointer.SIZE * (arg.length+1));
+ this.original = arg;
+ for (int i=0;i < arg.length;i++) {
+ setPointer(i*Pointer.SIZE, arg[i]);
+ }
+ setPointer(Pointer.SIZE*arg.length, null);
+ }
+ public void read() {
+ read(0, original, 0, original.length);
+ }
+ }
+
+ /** Implementation of Boolean.valueOf for older VMs. */
+ static Boolean valueOf(boolean b) {
+ return b ? Boolean.TRUE : Boolean.FALSE;
+ }
+}
40 src/main/java/com/sun/jna/FunctionMapper.java
@@ -0,0 +1,40 @@
+/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+import java.lang.reflect.Method;
+
+/** Provides mapping of Java method names to native function names.
+ * An instance of this interface may be provided to
+ * {@link Native#loadLibrary(String, Class, java.util.Map)} as an entry in
+ * the options map with key {@link Library#OPTION_FUNCTION_MAPPER}.
+ * <p>
+ * There are several circumstances where this option might prove useful.
+ * <ul>
+ * <li>C preprocessor macros are used to allow C code to refer to a library
+ * function by a different name
+ * <li>Generated linker symbols are different than those used in C code.
+ * Windows <code>stdcall</code> functions, for instance, are exported with a
+ * special suffix that describes the stack size of the function arguments
+ * (see {@link com.sun.jna.win32.StdCallFunctionMapper}).
+ * <li>The naming of the C library methods conflicts horribly with your
+ * Java coding standards, or are otherwise hard to follow. It's generally
+ * better to keep the original function names in this case, to avoid confusion
+ * about what's actually being called, but the option is available.
+ * </ul>
+ *
+ * @see Library#OPTION_FUNCTION_MAPPER
+ */
+public interface FunctionMapper {
+ String getFunctionName(NativeLibrary library, Method method);
+}
33 src/main/java/com/sun/jna/FunctionParameterContext.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2007 Wayne Meissner, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+package com.sun.jna;
+
+
+public class FunctionParameterContext extends ToNativeContext {
+ private Function function;
+ private Object[] args;
+ private int index;
+
+ FunctionParameterContext(Function f, Object[] args, int index) {
+ this.function = f;
+ this.args = args;
+ this.index = index;
+ }
+ /** Get the function that was invoked. */
+ public Function getFunction() { return function; }
+ /** Get the arguments used in this function call. */
+ public Object[] getParameters() { return args; }
+ public int getParameterIndex() { return index; }
+
+}
29 src/main/java/com/sun/jna/FunctionResultContext.java
@@ -0,0 +1,29 @@
+/* Copyright (c) 2007 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+/** Provide result conversion context for a function call. */
+public class FunctionResultContext extends FromNativeContext {
+
+ private Function function;
+ private Object[] args;
+ FunctionResultContext(Class resultClass, Function function, Object[] args) {
+ super(resultClass);
+ this.function = function;
+ this.args = args;
+ }
+ /** Get the function that was invoked. */
+ public Function getFunction() { return function; }
+ /** Get the arguments used in this function call. */
+ public Object[] getArguments() { return args; }
+}
128 src/main/java/com/sun/jna/IntegerType.java
@@ -0,0 +1,128 @@
+/* Copyright (c) 2007 Wayne Meissner, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+package com.sun.jna;
+
+/**
+ * Represents a native integer value, which may have a platform-specific size
+ * (e.g. <code>long</code> on unix-based platforms).
+ *
+ * @author wmeissner@gmail.com
+ */
+public abstract class IntegerType extends Number implements NativeMapped {
+
+ private int size;
+ private long value;
+ private Number number;
+
+ /** Create a zero-valued IntegerType. */
+ public IntegerType(int size) {
+ this(size, 0);
+ }
+
+ /** Create a IntegerType with the given value. */
+ public IntegerType(int size, long value) {
+ this.size = size;
+ setValue(value);
+ }
+
+ /** Change the value for this data. */
+ public void setValue(long value) {
+ long truncated = value;
+ this.value = value;
+ switch (size) {
+ case 1:
+ truncated = (byte) value;
+ this.number = new Byte((byte) value);
+ break;
+ case 2:
+ truncated = (short) value;
+ this.number = new Short((short) value);
+ break;
+ case 4:
+ truncated = (int) value;
+ this.number = new Integer((int) value);
+ break;
+ case 8:
+ this.number = new Long(value);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported size: " + size);
+ }
+ if (size < 8) {
+ long mask = ~((1L << (size*8)) - 1);
+ if ((value < 0 && truncated != value)
+ || (value >= 0 && (mask & value) != 0)) {
+ throw new IllegalArgumentException("Argument value 0x"
+ + Long.toHexString(value) + " exceeds native capacity ("
+ + size + " bytes) mask=0x" + Long.toHexString(mask));
+ }
+ }
+ }
+
+ public Object toNative() {
+ return number;
+ }
+
+ public Object fromNative(Object nativeValue, FromNativeContext context) {
+ // be forgiving of null values read from memory
+ long value = nativeValue == null
+ ? 0 : ((Number) nativeValue).longValue();
+ try {
+ IntegerType number = (IntegerType) getClass().newInstance();
+ number.setValue(value);
+ return number;
+ }
+ catch (InstantiationException e) {
+ throw new IllegalArgumentException("Can't instantiate "
+ + getClass());
+ }
+ catch (IllegalAccessException e) {
+ throw new IllegalArgumentException("Not allowed to instantiate "
+ + getClass());
+ }
+ }
+
+ public Class nativeType() {
+ return number.getClass();
+ }
+
+ public int intValue() {
+ return number.intValue();
+ }
+
+ public long longValue() {
+ return number.longValue();
+ }
+
+ public float floatValue() {
+ return number.floatValue();
+ }
+
+ public double doubleValue() {
+ return number.doubleValue();
+ }
+
+ public boolean equals(Object rhs) {
+ return rhs instanceof IntegerType
+ && number.equals(((IntegerType)rhs).number);
+ }
+
+ public String toString() {
+ return number.toString();
+ }
+
+ public int hashCode() {
+ return number.hashCode();
+ }
+}
75 src/main/java/com/sun/jna/InvocationMapper.java
@@ -0,0 +1,75 @@
+package com.sun.jna;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/** Provide a method for overriding how a given function is invoked.
+ * An instance of this interface may be provided to
+ * {@link Native#loadLibrary(String, Class, java.util.Map)} as an entry in
+ * the options map with key {@link Library#OPTION_INVOCATION_MAPPER}.<p>
+ * This is useful for implementing inlined functions, or functions which
+ * are actually C preprocessor macros. Given a native library and JNA
+ * interface method, the mapper may provide a handler which implements the
+ * desired functionality (which may or may not actually make use of a
+ * native method).
+ * <p>
+ * For example, the GNU C library remaps the <code>stat</code> function
+ * into a call to <code>_xstat</code> with a slight rearrangement of arguments.
+ * A mapper for the GNU C library might look like the following:<br>
+ * <blockquote>
+ * <code><pre>
+ * new InvocationMapper() {
+ * public InvocationHandler getInvocationHandler(NativeLibrary lib, Method m) {
+ * if (m.getName().equals("stat")) {
+ * final Function f = lib.getFunction("_xstat");
+ * return new InvocationHandler() {
+ * public Object invoke(Object proxy, Method method, Object[] args) {
+ * Object[] newArgs = new Object[args.length+1];
+ * System.arraycopy(args, 0, newArgs, 1, args.length);
+ * newArgs[0] = new Integer(3); // _xstat version
+ * return f.invoke(newArgs);
+ * }
+ * };
+ * }
+ * return null;
+ * }
+ * }
+ * </pre></code>
+ * </blockquote>
+ * Another situation is where a header provides a function-like macro or
+ * inline function definition.
+ * <blockquote>
+ * <code><pre>
+ * // Original C code (macro and inline variations)
+ * #define allocblock(x) malloc(x * 1024)
+ * static inline void* allocblock(size_t x) { return malloc(x * 1024); }
+ *
+ * // Invocation mapping
+ * new InvocationMapper() {
+ * public InvocationHandler getInvocationHandler(NativeLibrary lib, Method m) {
+ * if (m.getName().equals("allocblock")) {
+ * final Function f = lib.getFunction("malloc");
+ * return new InvocationHandler() {
+ * public Object invoke(Object proxy, Method method, Object[] args) {
+ * args[0] = ((Integer)args[0]).intValue() * 1024;
+ * return f.invoke(newArgs);
+ * }
+ * };
+ * }
+ * return null;
+ * }
+ * }
+ * </pre></code>
+ * </blockquote>
+ * @author twall
+ */
+public interface InvocationMapper {
+ /** Return an {@link InvocationHandler} responsible for handling the
+ * invocation of the given method, or <code>null</code> if the default
+ * handling should be used. Note that the result of a call to this method
+ * with a given library and method may be cached.
+ * @param lib Target library
+ * @param m Original JNA interface method that was invoked.
+ */
+ InvocationHandler getInvocationHandler(NativeLibrary lib, Method m);
+}
62 src/main/java/com/sun/jna/LastErrorException.java
@@ -0,0 +1,62 @@
+/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+/**
+ * Exception representing a non-zero error code returned in either
+ * <code><a href="http://www.opengroup.org/onlinepubs/009695399/functions/errno.html">errno</a></code>
+ * or <code><a href="http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx">GetLastError()</a></code>.
+*/
+public class LastErrorException extends RuntimeException {
+
+ private int errorCode;
+
+ private static String formatMessage(int code) {
+ return Platform.isWindows()
+ ? "GetLastError() returned " + code
+ : "errno was " + code;
+ }
+
+ private static String parseMessage(String m) {
+ try {
+ return formatMessage(Integer.parseInt(m));
+ }
+ catch(NumberFormatException e) {
+ return m;
+ }
+ }
+
+ public LastErrorException(String msg) {
+ super(parseMessage(msg));
+ try {
+ this.errorCode = Integer.parseInt(msg);
+ }
+ catch(NumberFormatException e) {
+ this.errorCode = -1;
+ }
+ }
+
+ /**
+ * Returns the error code of the error.
+ * @return
+ * Error code.
+ */
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public LastErrorException(int code) {
+ super(formatMessage(code));
+ this.errorCode = code;
+ }
+}
219 src/main/java/com/sun/jna/Library.java
@@ -0,0 +1,219 @@
+/* This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * <p/>
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+package com.sun.jna;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/** Derive from this interface for all native library definitions.
+ *
+ * Define an instance of your library like this:
+ * <code><pre>
+ * MyNativeLibrary INSTANCE = (MyNativeLibrary)
+ * Native.loadLibrary("mylib", MyNativeLibrary.class);
+ * </pre></code>
+ * <p>
+ * By convention, method names are identical to the native names, although you
+ * can map java names to different native names by providing a
+ * {@link FunctionMapper} as a value for key {@link #OPTION_FUNCTION_MAPPER}
+ * in the options map passed to the
+ * {@link Native#loadLibrary(String, Class, Map)} call.
+ * <p>
+ * Although the names for structures and structure fields may be chosen
+ * arbitrarily, they should correspond as closely as possible to the native
+ * definitions. The same is true for parameter names.
+ * <p>
+ * This interface supports multiple, concurrent invocations of any library
+ * methods on the Java side. Check your library documentation for its
+ * multi-threading requirements on the native side. If a library is not safe
+ * for simultaneous multi-threaded access, consider using
+ * {@link Native#synchronizedLibrary} to prevent simultaneous multi-threaded
+ * access to the native code.
+ * <p>
+ * <b>Optional fields</b><br>
+ * Interface options will be automatically propagated to structures defined
+ * within the library provided a call to
+ * {@link Native#loadLibrary(String,Class,Map)} is made prior to instantiating
+ * any of those structures. One common way of ensuring this is to declare
+ * an <b>INSTANCE</b> field in the interface which holds the
+ * <code>loadLibrary</code> result.
+ * <p>
+ * <b>OPTIONS</b> (an instance of {@link Map}),
+ * <b>TYPE_MAPPER</b> (an instance of {@link TypeMapper}) and
+ * <b>STRUCTURE_ALIGNMENT</b> (one of the alignment types defined in
+ * {@link Structure}) may also be defined. If no instance of the interface
+ * has been instantiated, these fields will be used to determine customization
+ * settings for structures and methods defined within the interface.
+ * <p>
+ *
+ * @author Todd Fast, todd.fast@sun.com
+ * @author Timothy Wall, twalljava@dev.java.net
+ */
+public interface Library {
+ /** Option key for a {@link TypeMapper} for the library. */
+ String OPTION_TYPE_MAPPER = "type-mapper";
+ /** Option key for a {@link FunctionMapper} for the library. */
+ String OPTION_FUNCTION_MAPPER = "function-mapper";
+ /** Option key for an {@link InvocationMapper} for the library. */
+ String OPTION_INVOCATION_MAPPER = "invocation-mapper";
+ /** Option key for structure alignment type ({@link Integer}), which should
+ * be one of the predefined alignment types in {@link Structure}.
+ */
+ String OPTION_STRUCTURE_ALIGNMENT = "structure-alignment";
+ /** Option key for a boolean flag to allow any Java class instance as a
+ parameter. If no type mapper is found, the object is passed as a
+ pointer.
+ <em>NOTE:</em> This is for use with raw JNI interactions via the
+ JNIEnv data structure.
+ */
+ String OPTION_ALLOW_OBJECTS = "allow-objects";
+ /** Calling convention for the entire library. */
+ String OPTION_CALLING_CONVENTION = "calling-convention";
+
+ static class Handler implements InvocationHandler {
+
+ static final Method OBJECT_TOSTRING;
+ static final Method OBJECT_HASHCODE;
+ static final Method OBJECT_EQUALS;
+
+ static {
+ try {
+ OBJECT_TOSTRING = Object.class.getMethod("toString", new Class[0]);
+ OBJECT_HASHCODE= Object.class.getMethod("hashCode", new Class[0]);