Exemplo n.º 1
0
 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;
 }
Exemplo n.º 2
0
  /**
   * 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;
  }