#
# Copyright (C) 2008-2010 Wayne Meissner
# Copyright (c) 2007, 2008 Evan Phoenix
#
# This file is part of ruby-ffi.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the Ruby FFI project nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# see {file:README}
module FFI
# @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type}
# @param [Symbol] add new type definition's name to add
# @return [Type]
# Add a definition type to type definitions.
def self.typedef(old, add)
TypeDefs[add] = self.find_type(old)
end
# (see FFI.typedef)
def self.add_typedef(old, add)
typedef old, add
end
# @param [Type, DataConverter, Symbol] name
# @param [Hash] type_map if nil, {FFI::TypeDefs} is used
# @return [Type]
# Find a type in +type_map+ ({FFI::TypeDefs}, by default) from
# a type objet, a type name (symbol). If +name+ is a {DataConverter},
# a new {Type::Mapped} is created.
def self.find_type(name, type_map = nil)
if name.is_a?(Type)
name
elsif type_map && type_map.has_key?(name)
type_map[name]
elsif TypeDefs.has_key?(name)
TypeDefs[name]
elsif name.is_a?(DataConverter)
(type_map || TypeDefs)[name] = Type::Mapped.new(name)
else
raise TypeError, "unable to resolve type '#{name}'"
end
end
# List of type definitions
TypeDefs.merge!({
# The C void type; only useful for function return types
:void => Type::VOID,
# C boolean type
:bool => Type::BOOL,
# C nul-terminated string
:string => Type::STRING,
# C signed char
:char => Type::CHAR,
# C unsigned char
:uchar => Type::UCHAR,
# C signed short
:short => Type::SHORT,
# C unsigned short
:ushort => Type::USHORT,
# C signed int
:int => Type::INT,
# C unsigned int
:uint => Type::UINT,
# C signed long
:long => Type::LONG,
# C unsigned long
:ulong => Type::ULONG,
# C signed long long integer
:long_long => Type::LONG_LONG,
# C unsigned long long integer
:ulong_long => Type::ULONG_LONG,
# C single precision float
:float => Type::FLOAT,
# C double precision float
:double => Type::DOUBLE,
# C long double
:long_double => Type::LONGDOUBLE,
# Native memory address
:pointer => Type::POINTER,
# 8 bit signed integer
:int8 => Type::INT8,
# 8 bit unsigned integer
:uint8 => Type::UINT8,
# 16 bit signed integer
:int16 => Type::INT16,
# 16 bit unsigned integer
:uint16 => Type::UINT16,
# 32 bit signed integer
:int32 => Type::INT32,
# 32 bit unsigned integer
:uint32 => Type::UINT32,
# 64 bit signed integer
:int64 => Type::INT64,
# 64 bit unsigned integer
:uint64 => Type::UINT64,
:buffer_in => Type::BUFFER_IN,
:buffer_out => Type::BUFFER_OUT,
:buffer_inout => Type::BUFFER_INOUT,
# Used in function prototypes to indicate the arguments are variadic
:varargs => Type::VARARGS,
})
# This will convert a pointer to a Ruby string (just like `:string`), but
# also allow to work with the pointer itself. This is useful when you want
# a Ruby string already containing a copy of the data, but also the pointer
# to the data for you to do something with it, like freeing it, in case the
# library handed the memory off to the caller (Ruby-FFI).
#
# It's {typedef}'d as +:strptr+.
class StrPtrConverter
extend DataConverter
native_type Type::POINTER
# @param [Pointer] val
# @param ctx not used
# @return [Array(String, Pointer)]
# Returns a [ String, Pointer ] tuple so the C memory for the string can be freed
def self.from_native(val, ctx)
[ val.null? ? nil : val.get_string(0), val ]
end
end
typedef(StrPtrConverter, :strptr)
# @param type +type+ is an instance of class accepted by {FFI.find_type}
# @return [Numeric]
# Get +type+ size, in bytes.
def self.type_size(type)
find_type(type).size
end
# Load all the platform dependent types
begin
File.open(File.join(Platform::CONF_DIR, 'types.conf'), "r") do |f|
prefix = "rbx.platform.typedef."
f.each_line { |line|
if line.index(prefix) == 0
new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
typedef(orig_type.to_sym, new_type.to_sym)
end
}
end
typedef :pointer, :caddr_t
rescue Errno::ENOENT
end
end