ffi 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ffi might be problematic. Click here for more details.
- data/README.rdoc +15 -15
- data/Rakefile +57 -8
- data/ext/ffi_c/AbstractMemory.c +101 -24
- data/ext/ffi_c/AbstractMemory.h +98 -6
- data/ext/ffi_c/ArrayType.c +129 -0
- data/ext/ffi_c/ArrayType.h +58 -0
- data/ext/ffi_c/AutoPointer.c +1 -0
- data/ext/ffi_c/Buffer.c +59 -43
- data/ext/ffi_c/Call.c +853 -0
- data/ext/ffi_c/Call.h +86 -0
- data/ext/ffi_c/ClosurePool.c +302 -0
- data/ext/ffi_c/ClosurePool.h +29 -0
- data/ext/ffi_c/DynamicLibrary.c +3 -0
- data/ext/ffi_c/Function.c +478 -0
- data/ext/ffi_c/Function.h +80 -0
- data/ext/ffi_c/FunctionInfo.c +221 -0
- data/ext/ffi_c/LastError.c +30 -6
- data/ext/ffi_c/MemoryPointer.c +50 -28
- data/ext/ffi_c/MethodHandle.c +346 -0
- data/ext/ffi_c/MethodHandle.h +53 -0
- data/ext/ffi_c/Pointer.c +73 -13
- data/ext/ffi_c/Pointer.h +31 -7
- data/ext/ffi_c/Struct.c +517 -224
- data/ext/ffi_c/Struct.h +60 -6
- data/ext/ffi_c/StructByValue.c +140 -0
- data/ext/ffi_c/StructByValue.h +53 -0
- data/ext/ffi_c/StructLayout.c +450 -0
- data/ext/ffi_c/Type.c +121 -22
- data/ext/ffi_c/Type.h +37 -8
- data/ext/ffi_c/Types.c +46 -61
- data/ext/ffi_c/Types.h +38 -7
- data/ext/ffi_c/Variadic.c +260 -0
- data/ext/ffi_c/compat.h +53 -3
- data/ext/ffi_c/extconf.rb +6 -7
- data/ext/ffi_c/ffi.c +45 -39
- data/ext/ffi_c/libffi.darwin.mk +2 -2
- data/ext/ffi_c/rbffi.h +3 -0
- data/lib/ffi/ffi.rb +7 -4
- data/lib/ffi/library.rb +34 -59
- data/lib/ffi/platform.rb +14 -4
- data/lib/ffi/struct.rb +110 -281
- data/lib/ffi/union.rb +4 -9
- data/lib/ffi/variadic.rb +1 -6
- data/spec/ffi/buffer_spec.rb +6 -0
- data/spec/ffi/callback_spec.rb +34 -3
- data/spec/ffi/function_spec.rb +73 -0
- data/spec/ffi/library_spec.rb +56 -52
- data/spec/ffi/pointer_spec.rb +3 -3
- data/spec/ffi/struct_callback_spec.rb +26 -3
- data/spec/ffi/struct_spec.rb +56 -3
- metadata +42 -11
- data/ext/ffi_c/Callback.c +0 -374
- data/ext/ffi_c/Callback.h +0 -47
- data/ext/ffi_c/Invoker.c +0 -962
- data/ext/ffi_c/NullPointer.c +0 -143
data/ext/ffi_c/libffi.darwin.mk
CHANGED
@@ -47,9 +47,9 @@ build_ffi = \
|
|
47
47
|
|
48
48
|
$(LIBFFI):
|
49
49
|
@for arch in $(ARCHES); do $(call build_ffi,$$arch);done
|
50
|
-
# Assemble into a FAT (i386, ppc) library
|
50
|
+
# Assemble into a FAT (x86_64, i386, ppc) library
|
51
51
|
@mkdir -p $(BUILD_DIR)/libffi/.libs
|
52
|
-
|
52
|
+
/usr/bin/libtool -static -o $@ \
|
53
53
|
$(foreach arch, $(ARCHES),$(BUILD_DIR)/libffi-$(arch)/.libs/libffi_convenience.a)
|
54
54
|
@mkdir -p $(LIBFFI_BUILD_DIR)/include
|
55
55
|
$(RM) $(LIBFFI_BUILD_DIR)/include/ffi.h
|
data/ext/ffi_c/rbffi.h
CHANGED
@@ -9,9 +9,12 @@ extern "C" {
|
|
9
9
|
|
10
10
|
#define MAX_PARAMETERS (32)
|
11
11
|
|
12
|
+
extern VALUE rbffi_FFIModule;
|
13
|
+
|
12
14
|
extern void rbffi_Type_Init(VALUE ffiModule);
|
13
15
|
extern void rbffi_Buffer_Init(VALUE ffiModule);
|
14
16
|
extern void rbffi_Invoker_Init(VALUE ffiModule);
|
17
|
+
extern void rbffi_Variadic_Init(VALUE ffiModule);
|
15
18
|
extern VALUE rbffi_AbstractMemoryClass, rbffi_InvokerClass;
|
16
19
|
extern int rbffi_type_size(VALUE type);
|
17
20
|
|
data/lib/ffi/ffi.rb
CHANGED
@@ -66,7 +66,9 @@ module FFI
|
|
66
66
|
end
|
67
67
|
lib
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
|
+
|
71
|
+
def self.create_invoker(lib, name, args, ret_type, options = { :convention => :default })
|
70
72
|
# Current artificial limitation based on JRuby::FFI limit
|
71
73
|
raise SignatureError, 'FFI functions may take max 32 arguments!' if args.size > 32
|
72
74
|
|
@@ -85,12 +87,13 @@ module FFI
|
|
85
87
|
raise NotFoundError.new(name, library.name) unless function
|
86
88
|
|
87
89
|
args = args.map {|e| find_type(e) }
|
88
|
-
if args.length > 0 && args[args.length - 1] == FFI::NativeType::VARARGS
|
89
|
-
|
90
|
+
invoker = if args.length > 0 && args[args.length - 1] == FFI::NativeType::VARARGS
|
91
|
+
FFI::VariadicInvoker.new(function, args, find_type(ret_type), options)
|
90
92
|
else
|
91
|
-
|
93
|
+
FFI::Function.new(find_type(ret_type), args, function, options)
|
92
94
|
end
|
93
95
|
raise NotFoundError.new(name, library.name) unless invoker
|
96
|
+
|
94
97
|
return invoker
|
95
98
|
end
|
96
99
|
end
|
data/lib/ffi/library.rb
CHANGED
@@ -28,6 +28,22 @@ module FFI::Library
|
|
28
28
|
def ffi_convention(convention)
|
29
29
|
@ffi_convention = convention
|
30
30
|
end
|
31
|
+
|
32
|
+
def ffi_libraries
|
33
|
+
unless defined?(@ffi_libs) or self.name.nil?
|
34
|
+
libs = []
|
35
|
+
# Try the exact name (e.g. User32) and all lower case (e.g. LibC -> libc)
|
36
|
+
[ self.name, self.name.downcase ].each do |name|
|
37
|
+
begin
|
38
|
+
libs << FFI::DynamicLibrary.open(name, FFI::DynamicLibrary::RTLD_LAZY | FFI::DynamicLibrary::RTLD_GLOBAL)
|
39
|
+
rescue Exception
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@ffi_libs = libs unless libs.empty?
|
43
|
+
end
|
44
|
+
defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
|
45
|
+
end
|
46
|
+
|
31
47
|
##
|
32
48
|
# Attach C function +name+ to this module.
|
33
49
|
#
|
@@ -51,15 +67,14 @@ module FFI::Library
|
|
51
67
|
|
52
68
|
# Try to locate the function in any of the libraries
|
53
69
|
invokers = []
|
54
|
-
|
55
|
-
libraries.each do |lib|
|
70
|
+
ffi_libraries.each do |lib|
|
56
71
|
begin
|
57
|
-
invokers << FFI.create_invoker(lib, cname.to_s, arg_types,
|
72
|
+
invokers << FFI.create_invoker(lib, cname.to_s, arg_types, find_type(ret_type), options)
|
58
73
|
rescue LoadError => ex
|
59
74
|
end if invokers.empty?
|
60
75
|
end
|
61
76
|
invoker = invokers.compact.shift
|
62
|
-
raise FFI::NotFoundError.new(cname.to_s,
|
77
|
+
raise FFI::NotFoundError.new(cname.to_s, ffi_libraries.map { |lib| lib.name }) unless invoker
|
63
78
|
|
64
79
|
# Setup the parameter list for the module function as (a1, a2)
|
65
80
|
arity = arg_types.length
|
@@ -91,71 +106,31 @@ module FFI::Library
|
|
91
106
|
end
|
92
107
|
def attach_variable(mname, a1, a2 = nil)
|
93
108
|
cname, type = a2 ? [ a1, a2 ] : [ mname.to_s, a1 ]
|
94
|
-
libraries = defined?(@ffi_libs) ? @ffi_libs : [ DEFAULT ]
|
95
109
|
address = nil
|
96
|
-
|
110
|
+
ffi_libraries.each do |lib|
|
97
111
|
begin
|
98
112
|
address = lib.find_variable(cname.to_s)
|
99
113
|
break unless address.nil?
|
100
114
|
rescue LoadError
|
101
115
|
end
|
102
116
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
when :char, FFI::NativeType::INT8
|
108
|
-
op = :int8
|
109
|
-
when :uchar, FFI::NativeType::UINT8
|
110
|
-
op = :uint8
|
111
|
-
when :short, FFI::NativeType::INT16
|
112
|
-
op = :int16
|
113
|
-
when :ushort, FFI::NativeType::UINT16
|
114
|
-
op = :uint16
|
115
|
-
when :int, FFI::NativeType::INT32
|
116
|
-
op = :int32
|
117
|
-
when :uint, FFI::NativeType::UINT32
|
118
|
-
op = :uint32
|
119
|
-
when :long, FFI::NativeType::LONG
|
120
|
-
op = :long
|
121
|
-
when :ulong, FFI::NativeType::ULONG
|
122
|
-
op = :ulong
|
123
|
-
when :long_long, FFI::NativeType::INT64
|
124
|
-
op = :int64
|
125
|
-
when :ulong_long, FFI::NativeType::UINT64
|
126
|
-
op = :uint64
|
127
|
-
else
|
128
|
-
if ffi_type.is_a?(FFI::CallbackInfo)
|
129
|
-
op = :callback
|
130
|
-
else
|
131
|
-
raise TypeError, "Cannot access library variable of type #{type}"
|
132
|
-
end
|
133
|
-
end
|
117
|
+
|
118
|
+
raise FFI::NotFoundError.new(cname, ffi_libraries) if address.nil? || address.null?
|
119
|
+
s = FFI::Struct.new(address, :gvar, find_type(type))
|
120
|
+
|
134
121
|
#
|
135
122
|
# Attach to this module as mname/mname=
|
136
123
|
#
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
@@ffi_gvar_#{mname}
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
code
|
148
|
-
else
|
149
|
-
self.module_eval <<-code
|
150
|
-
@@ffi_gvar_#{mname} = address
|
151
|
-
def self.#{mname}
|
152
|
-
@@ffi_gvar_#{mname}.get_#{op.to_s}(0)
|
153
|
-
end
|
154
|
-
def self.#{mname}=(value)
|
155
|
-
@@ffi_gvar_#{mname}.put_#{op.to_s}(0, value)
|
156
|
-
end
|
157
|
-
code
|
158
|
-
end
|
124
|
+
self.module_eval <<-code
|
125
|
+
@@ffi_gvar_#{mname} = s
|
126
|
+
def self.#{mname}
|
127
|
+
@@ffi_gvar_#{mname}[:gvar]
|
128
|
+
end
|
129
|
+
def self.#{mname}=(value)
|
130
|
+
@@ffi_gvar_#{mname}[:gvar] = value
|
131
|
+
end
|
132
|
+
code
|
133
|
+
|
159
134
|
address
|
160
135
|
end
|
161
136
|
|
data/lib/ffi/platform.rb
CHANGED
@@ -17,8 +17,9 @@ module FFI
|
|
17
17
|
when /win|mingw/
|
18
18
|
"windows"
|
19
19
|
else
|
20
|
-
|
20
|
+
Config::CONFIG['host_os'].downcase
|
21
21
|
end
|
22
|
+
|
22
23
|
ARCH = case CPU.downcase
|
23
24
|
when /amd64|x86_64/
|
24
25
|
"x86_64"
|
@@ -27,8 +28,9 @@ module FFI
|
|
27
28
|
when /ppc|powerpc/
|
28
29
|
"powerpc"
|
29
30
|
else
|
30
|
-
|
31
|
+
Config::CONFIG['host_cpu']
|
31
32
|
end
|
33
|
+
|
32
34
|
private
|
33
35
|
def self.is_os(os)
|
34
36
|
OS == os
|
@@ -43,6 +45,7 @@ module FFI
|
|
43
45
|
IS_BSD = IS_MAC || IS_FREEBSD || IS_OPENBSD
|
44
46
|
CONF_DIR = File.dirname(__FILE__)
|
45
47
|
public
|
48
|
+
|
46
49
|
LIBC = if IS_WINDOWS
|
47
50
|
"msvcrt"
|
48
51
|
elsif IS_LINUX
|
@@ -50,26 +53,33 @@ module FFI
|
|
50
53
|
else
|
51
54
|
"c"
|
52
55
|
end
|
56
|
+
|
53
57
|
LIBPREFIX = IS_WINDOWS ? '' : 'lib'
|
58
|
+
|
54
59
|
LIBSUFFIX = case OS
|
55
60
|
when /darwin/
|
56
61
|
'dylib'
|
57
62
|
when /linux|bsd|solaris/
|
58
63
|
'so'
|
59
|
-
when /
|
64
|
+
when /windows/
|
60
65
|
'dll'
|
61
66
|
else
|
62
|
-
|
67
|
+
# Punt and just assume a sane unix (i.e. anything but AIX)
|
68
|
+
'so'
|
63
69
|
end
|
70
|
+
|
64
71
|
def self.bsd?
|
65
72
|
IS_BSD
|
66
73
|
end
|
74
|
+
|
67
75
|
def self.windows?
|
68
76
|
IS_WINDOWS
|
69
77
|
end
|
78
|
+
|
70
79
|
def self.mac?
|
71
80
|
IS_MAC
|
72
81
|
end
|
82
|
+
|
73
83
|
def self.unix?
|
74
84
|
!IS_WINDOWS
|
75
85
|
end
|
data/lib/ffi/struct.rb
CHANGED
@@ -2,353 +2,182 @@ require 'ffi/platform'
|
|
2
2
|
module FFI
|
3
3
|
|
4
4
|
class StructLayout
|
5
|
-
attr_reader :size, :align
|
6
5
|
|
7
|
-
def members
|
8
|
-
@field_names
|
9
|
-
end
|
10
6
|
def offsets
|
11
|
-
|
7
|
+
members.map { |m| [ m, self[m].offset ] }
|
12
8
|
end
|
9
|
+
|
13
10
|
def offset_of(field_name)
|
14
|
-
|
11
|
+
self[field_name].offset
|
15
12
|
end
|
16
13
|
end
|
17
14
|
|
18
|
-
|
19
|
-
|
20
|
-
def size
|
21
|
-
self.class.size
|
22
|
-
end
|
23
|
-
def align
|
24
|
-
self.class.align
|
25
|
-
end
|
26
|
-
def offset
|
27
|
-
@off
|
28
|
-
end
|
29
|
-
def self.size
|
30
|
-
const_get(:SIZE)
|
31
|
-
end
|
32
|
-
def self.align
|
33
|
-
const_get(:ALIGN)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.struct_field_class_from(type)
|
38
|
-
klass_name = type.name.split('::').last
|
39
|
-
code = <<-code
|
40
|
-
class StructField_#{klass_name} < Field
|
41
|
-
@info = #{type}
|
42
|
-
class << self
|
43
|
-
attr_reader :info
|
44
|
-
def size
|
45
|
-
#{type.size}
|
46
|
-
end
|
47
|
-
def align
|
48
|
-
#{type.align}
|
49
|
-
end
|
50
|
-
end
|
51
|
-
def get(ptr)
|
52
|
-
self.class.info.new(ptr + @off)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
StructField_#{klass_name}
|
56
|
-
code
|
57
|
-
self.module_eval(code)
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.array_field_class_from(type, num)
|
61
|
-
klass_name = type.name.split('::').last
|
62
|
-
code = <<-code
|
63
|
-
class ArrayField_#{klass_name}_#{num} < Field
|
64
|
-
@info = #{type}
|
65
|
-
@num = #{num}
|
66
|
-
class << self
|
67
|
-
attr_reader :info, :num
|
68
|
-
def size
|
69
|
-
#{type.size} * #{num}
|
70
|
-
end
|
71
|
-
def align
|
72
|
-
#{type.align}
|
73
|
-
end
|
74
|
-
end
|
75
|
-
def get(ptr)
|
76
|
-
@array ? @array : get_array_data(ptr)
|
77
|
-
end
|
78
|
-
private
|
79
|
-
def get_array_data(ptr)
|
80
|
-
@array = FFI::Struct::Array.new(ptr + @off, self.class.info, self.class.num)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
ArrayField_#{klass_name}_#{num}
|
84
|
-
code
|
85
|
-
self.module_eval(code)
|
86
|
-
end
|
87
|
-
|
88
|
-
class CallbackField < Field
|
89
|
-
def self.size
|
90
|
-
FFI::Type::POINTER.size
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.align
|
94
|
-
FFI::Type::POINTER.alignment
|
95
|
-
end
|
96
|
-
|
97
|
-
def put(ptr, proc)
|
98
|
-
ptr.put_callback(@off, proc, @info)
|
99
|
-
end
|
15
|
+
|
16
|
+
class Struct
|
100
17
|
|
101
|
-
|
102
|
-
|
103
|
-
end
|
18
|
+
def size
|
19
|
+
self.class.size
|
104
20
|
end
|
105
21
|
|
106
|
-
def
|
107
|
-
|
108
|
-
@fields = {}
|
109
|
-
@size = 0
|
110
|
-
@min_align = 1
|
22
|
+
def alignment
|
23
|
+
self.class.alignment
|
111
24
|
end
|
25
|
+
alias_method :align, :alignment
|
112
26
|
|
113
|
-
def
|
114
|
-
|
115
|
-
when :char, NativeType::INT8
|
116
|
-
Signed8
|
117
|
-
when :uchar, NativeType::UINT8
|
118
|
-
Unsigned8
|
119
|
-
when :short, NativeType::INT16
|
120
|
-
Signed16
|
121
|
-
when :ushort, NativeType::UINT16
|
122
|
-
Unsigned16
|
123
|
-
when :long, NativeType::LONG
|
124
|
-
FFI::Platform::LONG_SIZE == 32 ? Signed32 : Signed64
|
125
|
-
when :ulong, NativeType::ULONG
|
126
|
-
FFI::Platform::LONG_SIZE == 32 ? Unsigned32 : Unsigned64
|
127
|
-
when :int, NativeType::INT32
|
128
|
-
Signed32
|
129
|
-
when :uint, NativeType::UINT32
|
130
|
-
Unsigned32
|
131
|
-
when :long_long, NativeType::INT64
|
132
|
-
Signed64
|
133
|
-
when :ulong_long, NativeType::UINT64
|
134
|
-
Unsigned64
|
135
|
-
when :float, NativeType::FLOAT32
|
136
|
-
FloatField
|
137
|
-
when :double, NativeType::FLOAT64
|
138
|
-
DoubleField
|
139
|
-
when :pointer, NativeType::POINTER
|
140
|
-
PointerField
|
141
|
-
when :string, NativeType::STRING
|
142
|
-
StringField
|
143
|
-
end
|
27
|
+
def offset_of(name)
|
28
|
+
self.class.offset_of(name)
|
144
29
|
end
|
145
30
|
|
146
|
-
def
|
147
|
-
|
31
|
+
def members
|
32
|
+
self.class.members
|
148
33
|
end
|
149
34
|
|
150
|
-
def
|
151
|
-
|
35
|
+
def values
|
36
|
+
members.map { |m| self[m] }
|
152
37
|
end
|
153
38
|
|
154
|
-
def
|
155
|
-
self.class.
|
39
|
+
def offsets
|
40
|
+
self.class.offsets
|
156
41
|
end
|
157
42
|
|
158
|
-
def
|
159
|
-
|
160
|
-
|
161
|
-
array_field_class_from(type) ||
|
162
|
-
struct_field_class_from(type)
|
163
|
-
field_class or raise ArgumentError, "Unknown type: #{type}"
|
43
|
+
def clear
|
44
|
+
pointer.clear
|
45
|
+
self
|
164
46
|
end
|
165
47
|
|
166
|
-
def
|
167
|
-
|
168
|
-
off = calc_alignment_of(field_class, offset)
|
169
|
-
calc_current_size(off, field_class.size)
|
170
|
-
@field_names << name
|
171
|
-
@fields[name] = field_class.new(off, info)
|
172
|
-
@min_align = field_class.align if field_class.align > @min_align
|
48
|
+
def to_ptr
|
49
|
+
pointer
|
173
50
|
end
|
174
51
|
|
175
|
-
def
|
176
|
-
|
52
|
+
def self.size
|
53
|
+
defined?(@layout) ? @layout.size : defined?(@size) ? @size : 0
|
177
54
|
end
|
178
55
|
|
179
|
-
def
|
180
|
-
|
56
|
+
def self.size=(size)
|
57
|
+
raise ArgumentError, "Size already set" if defined?(@size) || defined?(@layout)
|
58
|
+
@size = size
|
181
59
|
end
|
182
60
|
|
183
|
-
|
184
|
-
|
185
|
-
offset ? offset.to_i : align(@size, field_class.align)
|
186
|
-
end
|
187
|
-
def calc_current_size(offset, size)
|
188
|
-
@size = offset + size
|
61
|
+
def self.alignment
|
62
|
+
@layout.alignment
|
189
63
|
end
|
190
|
-
end
|
191
64
|
|
192
|
-
|
193
|
-
|
194
|
-
include Enumerable
|
195
|
-
|
196
|
-
def initialize(ptr, type, num)
|
197
|
-
@pointer, @type, @num = ptr, type, num
|
198
|
-
end
|
199
|
-
|
200
|
-
def to_ptr
|
201
|
-
@pointer
|
202
|
-
end
|
203
|
-
|
204
|
-
def to_a
|
205
|
-
get_array_data(@pointer)
|
206
|
-
end
|
207
|
-
|
208
|
-
def size
|
209
|
-
@num * @type.size
|
210
|
-
end
|
211
|
-
|
212
|
-
def each(&blk)
|
213
|
-
to_a.each(&blk)
|
214
|
-
end
|
215
|
-
|
216
|
-
private
|
217
|
-
def get_array_data(ptr)
|
218
|
-
(0..@num - 1).inject([]) do |array, index|
|
219
|
-
array << @type.new(0).get(ptr + index * @type.size)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def self.size
|
225
|
-
@size
|
65
|
+
def self.align
|
66
|
+
@layout.alignment
|
226
67
|
end
|
227
68
|
|
228
69
|
def self.members
|
229
70
|
@layout.members
|
230
71
|
end
|
231
72
|
|
232
|
-
def self.align
|
233
|
-
@layout.align
|
234
|
-
end
|
235
|
-
|
236
73
|
def self.offsets
|
237
74
|
@layout.offsets
|
238
75
|
end
|
239
76
|
|
240
|
-
def self.offset_of(
|
241
|
-
@layout.offset_of(
|
77
|
+
def self.offset_of(name)
|
78
|
+
@layout.offset_of(name)
|
242
79
|
end
|
243
80
|
|
244
|
-
def
|
245
|
-
|
81
|
+
def self.in
|
82
|
+
:buffer_in
|
246
83
|
end
|
247
84
|
|
248
|
-
def
|
249
|
-
|
85
|
+
def self.out
|
86
|
+
:buffer_out
|
250
87
|
end
|
251
88
|
|
252
|
-
def
|
253
|
-
|
89
|
+
def self.by_value
|
90
|
+
::FFI::StructByValue.new(self)
|
254
91
|
end
|
255
92
|
|
256
|
-
def values
|
257
|
-
layout.members.map { |m| self[m] }
|
258
|
-
end
|
259
|
-
def offsets
|
260
|
-
self.class.offsets
|
261
|
-
end
|
262
93
|
|
263
|
-
def offset_of(field_name)
|
264
|
-
self.class.offset_of(field_name)
|
265
|
-
end
|
266
94
|
|
267
|
-
|
268
|
-
|
269
|
-
self
|
270
|
-
end
|
95
|
+
class << self
|
96
|
+
public
|
271
97
|
|
272
|
-
|
273
|
-
|
274
|
-
end
|
98
|
+
def layout(*spec)
|
99
|
+
return @layout if spec.size == 0
|
275
100
|
|
276
|
-
|
277
|
-
|
278
|
-
|
101
|
+
builder = FFI::StructLayoutBuilder.new
|
102
|
+
builder.union = self < Union
|
103
|
+
if spec[0].kind_of?(Hash)
|
104
|
+
hash_layout(builder, spec)
|
105
|
+
else
|
106
|
+
array_layout(builder, spec)
|
107
|
+
end
|
108
|
+
builder.size = @size if defined?(@size) && @size > builder.size
|
109
|
+
cspec = builder.build
|
110
|
+
@layout = cspec unless self == FFI::Struct
|
111
|
+
@size = cspec.size
|
112
|
+
return cspec
|
113
|
+
end
|
279
114
|
|
280
|
-
def self.out
|
281
|
-
:buffer_out
|
282
|
-
end
|
283
115
|
|
284
|
-
|
116
|
+
protected
|
285
117
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
118
|
+
def callback(params, ret)
|
119
|
+
mod = enclosing_module
|
120
|
+
FFI::CallbackInfo.new(find_type(ret, mod), params.map { |e| find_type(e, mod) })
|
121
|
+
end
|
290
122
|
|
291
|
-
private
|
292
123
|
|
293
|
-
|
294
|
-
|
295
|
-
|
124
|
+
def enclosing_module
|
125
|
+
begin
|
126
|
+
mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) }
|
127
|
+
mod.respond_to?(:find_type) ? mod : nil
|
128
|
+
rescue Exception => ex
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
end
|
296
132
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
133
|
+
def find_type(type, mod = nil)
|
134
|
+
if (type.kind_of?(Class) && type < FFI::Struct) || type.is_a?(::Array)
|
135
|
+
type
|
136
|
+
elsif mod
|
137
|
+
mod.find_type(type)
|
138
|
+
end || FFI.find_type(type)
|
303
139
|
end
|
304
|
-
end
|
305
140
|
|
306
|
-
def self.is_a_struct?(type)
|
307
|
-
type.is_a?(Class) and type < Struct
|
308
|
-
end
|
309
141
|
|
310
|
-
|
311
|
-
return type if is_a_struct?(type) or type.is_a?(::Array)
|
312
|
-
mod ? mod.find_type(type) : FFI.find_type(type)
|
313
|
-
end
|
142
|
+
private
|
314
143
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
144
|
+
def hash_layout(builder, spec)
|
145
|
+
raise "Ruby version not supported" if RUBY_VERSION =~ /1.8.*/
|
146
|
+
mod = enclosing_module
|
147
|
+
spec[0].each do |name,type|
|
148
|
+
if type.kind_of?(Class) && type < Struct
|
149
|
+
builder.add_struct(name, type)
|
150
|
+
elsif type.kind_of?(::Array)
|
151
|
+
builder.add_array(name, find_type(type[0], mod), type[1])
|
152
|
+
else
|
153
|
+
builder.add_field(name, find_type(type, mod))
|
154
|
+
end
|
155
|
+
end
|
321
156
|
end
|
322
|
-
builder.build
|
323
|
-
end
|
324
157
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
158
|
+
def array_layout(builder, spec)
|
159
|
+
mod = enclosing_module
|
160
|
+
i = 0
|
161
|
+
while i < spec.size
|
162
|
+
name, type = spec[i, 2]
|
163
|
+
i += 2
|
164
|
+
|
165
|
+
# If the next param is a Integer, it specifies the offset
|
166
|
+
if spec[i].kind_of?(Integer)
|
167
|
+
offset = spec[i]
|
168
|
+
i += 1
|
169
|
+
else
|
170
|
+
offset = nil
|
171
|
+
end
|
172
|
+
if type.kind_of?(Class) && type < Struct
|
173
|
+
builder.add_struct(name, type, offset)
|
174
|
+
elsif type.kind_of?(::Array)
|
175
|
+
builder.add_array(name, find_type(type[0], mod), type[1], offset)
|
176
|
+
else
|
177
|
+
builder.add_field(name, find_type(type, mod), offset)
|
178
|
+
end
|
340
179
|
end
|
341
180
|
end
|
342
|
-
builder.build
|
343
|
-
end
|
344
|
-
|
345
|
-
public
|
346
|
-
def self.layout(*spec)
|
347
|
-
return @layout if spec.size == 0
|
348
|
-
cspec = spec[0].kind_of?(Hash) ? hash_layout(spec) : array_layout(spec)
|
349
|
-
@layout = cspec unless self == FFI::Struct
|
350
|
-
@size = cspec.size
|
351
|
-
return cspec
|
352
181
|
end
|
353
182
|
end
|
354
183
|
end
|