Package org.jruby.ext.ffi.jna

Source Code of org.jruby.ext.ffi.jna.JNAProvider$Unsigned16Marshaller

/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2008 JRuby project
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby.ext.ffi.jna;

import com.sun.jna.CallbackProxy;
import org.jruby.ext.ffi.*;
import com.sun.jna.Function;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;
import java.nio.ByteBuffer;
import org.jruby.Ruby;
import org.jruby.RubyProc;
import org.jruby.RubyString;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;

/**
* A FFIProvider that uses JNA to load and execute native functions.
*/
public final class JNAProvider extends FFIProvider {

    JNAProvider(Ruby runtime) {
        super(runtime);
    }
   
    @Override
    public final Invoker createInvoker(Ruby runtime, String libraryName, String functionName,
            NativeType returnType, NativeParam[] parameterTypes, String convention) {
        int conv = "stdcall".equals(convention) ? Function.ALT_CONVENTION : Function.C_CONVENTION;
        Function function = NativeLibrary.getInstance(libraryName).getFunction(functionName, conv);
        FunctionInvoker functionInvoker = getFunctionInvoker(returnType);
        Marshaller[] marshallers = new Marshaller[parameterTypes.length];
        for (int i = 0; i < marshallers.length; ++i) {
            marshallers[i] = getMarshaller(parameterTypes[i], conv);
        }

        return new JNAInvoker(runtime, function, functionInvoker, marshallers);
    }

    @Override
    public Callback createCallback(Ruby runtime, NativeType returnType,
            NativeType[] parameterTypes) {
        return new Callback(runtime, returnType, parameterTypes);
    }
   
    public int getLastError() {
        return Native.getLastError();
    }
    public void setLastError(int error) {
        Native.setLastError(error);
    }

   
    /**
     * Gets a {@link FunctionInvoker} for a native return type.
     *
     * @param returnType The return type of the native function.
     * @return A new <tt>FunctionInvoker</tt> to invoke the native function.
     */
    private FunctionInvoker getFunctionInvoker(NativeType returnType) {
        switch (returnType) {
            case VOID:
                return VoidInvoker.INSTANCE;
            case POINTER:
                return PointerInvoker.INSTANCE;
            case INT8:
            case INT16:
            case INT32:
                return Signed32Invoker.INSTANCE;
            case UINT8:
            case UINT16:
            case UINT32:
                return Unsigned32Invoker.INSTANCE;
            case INT64:
            case UINT64:
                return Signed64Invoker.INSTANCE;
            case LONG:
                return Platform.getPlatform().addressSize() == 32
                        ? Signed32Invoker.INSTANCE
                        : Signed64Invoker.INSTANCE;
            case ULONG:
                return Platform.getPlatform().addressSize() == 32
                        ? Unsigned32Invoker.INSTANCE
                        : Signed64Invoker.INSTANCE;
            case FLOAT32:
                return Float32Invoker.INSTANCE;
            case FLOAT64:
                return Float64Invoker.INSTANCE;
            case STRING:
            case RBXSTRING:
                return StringInvoker.INSTANCE;
            default:
                throw new IllegalArgumentException("Invalid return type: " + returnType);
        }
    }
    /**
     * Gets a marshaller to convert from a ruby type to a native type.
     *
     * @param type The native type to convert to.
     * @return A new <tt>Marshaller</tt>
     */
    private static final Marshaller getMarshaller(NativeParam type, int convention) {
        if (type instanceof NativeType) {
            return getMarshaller((NativeType) type);
        } else if (type instanceof org.jruby.ext.ffi.Callback) {
            return new CallbackMarshaller((org.jruby.ext.ffi.Callback) type, convention);
        } else {
            return null;
        }       
    }
    /**
     * Gets a marshaller to convert from a ruby type to a native type.
     *
     * @param type The native type to convert to.
     * @return A new <tt>Marshaller</tt>
     */
    private static final Marshaller getMarshaller(NativeType type) {
        switch (type) {
            case INT8:
                return Signed8Marshaller.INSTANCE;
            case UINT8:
                return Unsigned8Marshaller.INSTANCE;
            case INT16:
                return Signed16Marshaller.INSTANCE;
            case UINT16:
                return Unsigned16Marshaller.INSTANCE;
            case INT32:
                return Signed32Marshaller.INSTANCE;
            case UINT32:
                return Unsigned32Marshaller.INSTANCE;
            case INT64:
                return Signed64Marshaller.INSTANCE;
            case UINT64:
                return Unsigned64Marshaller.INSTANCE;
            case LONG:
                return Platform.getPlatform().longSize() == 32
                        ? Signed32Marshaller.INSTANCE
                        : Signed64Marshaller.INSTANCE;
            case ULONG:
                return Platform.getPlatform().longSize() == 32
                        ? Signed32Marshaller.INSTANCE
                        : Signed64Marshaller.INSTANCE;
            case FLOAT32:
                return Float32Marshaller.INSTANCE;
            case FLOAT64:
                return Float64Marshaller.INSTANCE;
            case STRING:
                return StringMarshaller.INSTANCE;
            case RBXSTRING:
                return RbxStringMarshaller.INSTANCE;
            case POINTER:
                return PointerMarshaller.INSTANCE;
            case BUFFER_IN:
            case BUFFER_OUT:
            case BUFFER_INOUT:
                return BufferMarshaller.INSTANCE;
            default:
                throw new IllegalArgumentException("Invalid parameter type: " + type);
        }
    }
   
    /**
     * Invokes the native function with no return type, and returns nil to ruby.
     */
    private static final class VoidInvoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            function.invoke(args);
            return runtime.getNil();
        }
        public static final FunctionInvoker INSTANCE = new VoidInvoker();
    }
   
    /**
     * Invokes the native function with a 32 bit integer return value.
     * Returns a Fixnum to ruby.
     */
    private static final class Signed32Invoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {  
            return runtime.newFixnum(function.invokeInt(args));
        }
        public static final FunctionInvoker INSTANCE = new Signed32Invoker();
    }
   
    /**
     * Invokes the native function with an unsigned 32 bit integer return value.
     * Returns a Fixnum to ruby.
     */
    private static final class Unsigned32Invoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            return Util.newUnsigned32(runtime, function.invokeInt(args));
        }
        public static final FunctionInvoker INSTANCE = new Unsigned32Invoker();
    }
   
    /**
     * Invokes the native function with a 64 bit integer return value.
     * Returns a Fixnum to ruby.
     */
    private static final class Signed64Invoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            return runtime.newFixnum(function.invokeLong(args));
        }
        public static final FunctionInvoker INSTANCE = new Signed64Invoker();
    }
   
    /**
     * Invokes the native function with a 32 bit float return value.
     * Returns a Float to ruby.
     */
    private static final class Float32Invoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            return runtime.newFloat(function.invokeFloat(args));
        }
        public static final FunctionInvoker INSTANCE = new Float32Invoker();
    }
   
    /**
     * Invokes the native function with a 64 bit float return value.
     * Returns a Float to ruby.
     */
    private static final class Float64Invoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            return runtime.newFloat(function.invokeDouble(args));
        }
        public static final FunctionInvoker INSTANCE = new Float64Invoker();
    }
   
    /**
     * Invokes the native function with a native pointer return value.
     * Returns a {@link MemoryPointer} to ruby.
     */
    private static final class PointerInvoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            return new JNAMemoryPointer(runtime, function.invokePointer(args));
        }
        public static final FunctionInvoker INSTANCE = new PointerInvoker();
    }
   
    /**
     * Invokes the native function with a native string return value.
     * Returns a {@link RubyString} to ruby.
     */
    private static final class StringInvoker implements FunctionInvoker {
        public final IRubyObject invoke(Ruby runtime, Function function, Object[] args) {
            Pointer address = function.invokePointer(args);
            if (address == null) {
                return runtime.getNil();
            }
            int len = (int) address.indexOf(0, (byte) 0);
            if (len == 0) {
                return RubyString.newEmptyString(runtime);
            }
            ByteList bl = new ByteList(len);
            bl.length(len);
            address.read(0, bl.unsafeBytes(), bl.begin(), len);
           
            return RubyString.newString(runtime, bl);
        }
        public static final FunctionInvoker INSTANCE = new StringInvoker();
    }
   
    /**
     * Converts a ruby Fixnum into an 8 bit native integer.
     */
    private static final class Signed8Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Byte.valueOf(Util.int8Value(parameter));
        }
        public static final Marshaller INSTANCE = new Signed8Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into an 8 bit native unsigned integer.
     */
    private static final class Unsigned8Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Byte.valueOf((byte) Util.uint8Value(parameter));
        }
        public static final Marshaller INSTANCE = new Unsigned8Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into a 16 bit native signed integer.
     */
    private static final class Signed16Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Short.valueOf(Util.int16Value(parameter));
        }
        public static final Marshaller INSTANCE = new Signed16Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into a 16 bit native unsigned integer.
     */
    private static final class Unsigned16Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Short.valueOf((short) Util.uint16Value(parameter));
        }
        public static final Marshaller INSTANCE = new Unsigned16Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into a 32 bit native signed integer.
     */
    private static final class Signed32Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Integer.valueOf(Util.int32Value(parameter));
        }
        public static final Marshaller INSTANCE = new Signed32Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into a 32 bit native unsigned integer.
     */
    private static final class Unsigned32Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Integer.valueOf((int) Util.uint32Value(parameter));
        }
        public static final Marshaller INSTANCE = new Unsigned32Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into a 64 bit native signed integer.
     */
    private static final class Signed64Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Long.valueOf(Util.int64Value(parameter));
        }
        public static final Marshaller INSTANCE = new Signed64Marshaller();
    }
   
    /**
     * Converts a ruby Fixnum into a 64 bit native unsigned integer.
     */
    private static final class Unsigned64Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Long.valueOf(Util.uint64Value(parameter));
        }
        public static final Marshaller INSTANCE = new Unsigned64Marshaller();
    }
   
    /**
     * Converts a ruby Float into a 32 bit native float.
     */
    private static final class Float32Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Float.valueOf(Util.floatValue(parameter));
        }
        public static final Marshaller INSTANCE = new Float32Marshaller();
    }
   
    /**
     * Converts a ruby Float into a 64 bit native float.
     */
    private static final class Float64Marshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            return Double.valueOf(Util.doubleValue(parameter));
        }
        public static final Marshaller INSTANCE = new Float64Marshaller();
    }
   
    /**
     * Converts a ruby MemoryPointer into a native pointer.
     */
    private static final class PointerMarshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            if (parameter instanceof JNAMemory) {
                return (((JNAMemory) parameter).getNativeMemory());
            } else if (parameter.isNil()) {
                return Pointer.NULL;
            } else if (parameter instanceof RubyString) {
                // Handle a string being used as a inout buffer
                final ByteList bl = ((RubyString) parameter).getByteList();
                final int len = bl.length();
                final Memory memory = new Memory(len);
                memory.write(0, bl.unsafeBytes(), bl.begin(), len);

                //
                // Arrange for the bytes to be copied back after the function is called
                //
                invocation.addPostInvoke(new Runnable() {
                    public void run() {
                        memory.read(0, bl.unsafeBytes(), bl.begin(), len);
                    }
                });
                return memory;
            }
            return Util.convertParameter(parameter, Pointer.class);
        }
        public static final Marshaller INSTANCE = new PointerMarshaller();
    }
   
    /**
     * Converts a ruby string into a native string.
     * <p>
     * <b>Note:</b> This treats the string as immutable.  i.e. Native data is
     * <b>not</b> copied back to the ruby string after the call.
     * </p>
     */
    private static final class StringMarshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            // Ruby strings are UTF-8, so should be able to just copy directly
            RubyString s = parameter.asString();
            ByteList bl = s.getByteList();
            final Memory memory = new Memory(bl.length() + 1);
            memory.write(0, bl.unsafeBytes(), bl.begin(), bl.length());
            memory.setByte(bl.length(), (byte) 0);
            return memory;
        }
        public static final Marshaller INSTANCE = new StringMarshaller();
    }
   
    /**
     * Converts a ruby string into a native string.
     * <p>
     * <b>Note:</b> The string is mutable.  i.e. Changes to the native string
     * are copied back to the ruby string after the call.
     * </p>
     */
    private static final class RbxStringMarshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            // Ruby strings are UTF-8, so should be able to just copy directly
            final ByteList bl = parameter.asString().getByteList();
            final int strlen = bl.length();
            final Memory memory = new Memory(strlen + 1);
            memory.write(0, bl.unsafeBytes(), bl.begin(), strlen);
            memory.setByte(bl.length(), (byte) 0);
           
            //
            // Arrange for the bytes to be copied back after the function is called
            //
            invocation.addPostInvoke(new Runnable() {
                public void run() {
                    memory.read(0, bl.unsafeBytes(), bl.begin(), strlen);
                }
            });
            return memory;
        }
        public static final Marshaller INSTANCE = new RbxStringMarshaller();
    }
   
    /**
     * Converts a ruby string or java <tt>ByteBuffer</tt> into a native pointer.
     */
    private static final class BufferMarshaller implements Marshaller {
        public final Object marshal(Invocation invocation, IRubyObject parameter) {
            if (parameter instanceof JNAMemory) {
                return (((JNAMemory) parameter).getNativeMemory());
            } else if (parameter.isNil()) {
                return Pointer.NULL;
            } else if (parameter instanceof RubyString) {
                ByteList bl = ((RubyString) parameter).getByteList();
                return ByteBuffer.wrap(bl.unsafeBytes(), bl.begin(), bl.realSize);
            } else {
                return Util.convertParameter(parameter, Object.class);
            }
        }
        public static final Marshaller INSTANCE = new BufferMarshaller();
    }
}
TOP

Related Classes of org.jruby.ext.ffi.jna.JNAProvider$Unsigned16Marshaller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.