/** @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; }
/** * 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); Class[] paramTypes = invokingMethod != null ? invokingMethod.getParameterTypes() : null; boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS)); boolean isVarArgs = args.length > 0 && invokingMethod != null ? isVarArgs(invokingMethod) : false; for (int i = 0; i < args.length; i++) { Class paramType = invokingMethod != null ? (isVarArgs && i >= paramTypes.length - 1 ? paramTypes[paramTypes.length - 1].getComponentType() : paramTypes[i]) : null; args[i] = convertArgument(args, i, invokingMethod, mapper, allowObjects, paramType); } Class nativeReturnType = returnType; FromNativeConverter resultConverter = null; if (NativeMapped.class.isAssignableFrom(returnType)) { NativeMappedConverter tc = NativeMappedConverter.getInstance(returnType); resultConverter = tc; nativeReturnType = tc.nativeType(); } else if (mapper != null) { resultConverter = mapper.getFromNativeConverter(returnType); if (resultConverter != null) { nativeReturnType = resultConverter.nativeType(); } } Object result = invoke(args, nativeReturnType, 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; }