gt:         else if (allowObjects) {
context: /* 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) {
              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);
                      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);
              }
          }
  