private Object convertArgument( Object[] args, int index, Method invokingMethod, TypeMapper mapper, boolean allowObjects, Class expectedType) { 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, encoding); } 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)) { // If the signature is Structure[], disallow // Structure.ByReference[] and Structure.ByReference elements Structure[] ss = (Structure[]) arg; Class type = argClass.getComponentType(); boolean byRef = Structure.ByReference.class.isAssignableFrom(type); if (expectedType != null) { if (!Structure.ByReference[].class.isAssignableFrom(expectedType)) { if (byRef) { throw new IllegalArgumentException( "Function " + getName() + " declared Structure[] at parameter " + index + " but array of " + type + " was passed"); } for (int i = 0; i < ss.length; i++) { if (ss[i] instanceof Structure.ByReference) { throw new IllegalArgumentException( "Function " + getName() + " declared Structure[] at parameter " + index + " but element " + i + " is of Structure.ByReference type"); } } } } if (byRef) { Structure.autoWrite(ss); 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; }
/** @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) { Native.invokeVoid(peer, callFlags, args); result = null; } else if (returnType == boolean.class || returnType == Boolean.class) { result = valueOf(Native.invokeInt(peer, callFlags, args) != 0); } else if (returnType == byte.class || returnType == Byte.class) { result = new Byte((byte) Native.invokeInt(peer, callFlags, args)); } else if (returnType == short.class || returnType == Short.class) { result = new Short((short) Native.invokeInt(peer, callFlags, args)); } else if (returnType == char.class || returnType == Character.class) { result = new Character((char) Native.invokeInt(peer, callFlags, args)); } else if (returnType == int.class || returnType == Integer.class) { result = new Integer(Native.invokeInt(peer, callFlags, args)); } else if (returnType == long.class || returnType == Long.class) { result = new Long(Native.invokeLong(peer, callFlags, args)); } else if (returnType == float.class || returnType == Float.class) { result = new Float(Native.invokeFloat(peer, callFlags, args)); } else if (returnType == double.class || returnType == Double.class) { result = new Double(Native.invokeDouble(peer, 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)) { return invokePointer(callFlags, args); } else if (Structure.class.isAssignableFrom(returnType)) { if (Structure.ByValue.class.isAssignableFrom(returnType)) { Structure s = Native.invokeStructure(peer, callFlags, args, Structure.newInstance(returnType)); s.autoRead(); result = s; } else { result = invokePointer(callFlags, args); if (result != null) { Structure s = Structure.newInstance(returnType, (Pointer) result); s.conditionalAutoRead(); 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, encoding); } } else if (returnType == WString[].class) { Pointer p = invokePointer(callFlags, args); if (p != null) { String[] arr = p.getWideStringArray(0); 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 = Native.invokeObject(peer, 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; }