Ejemplo n.º 1
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;
  }