ffi 0.6.4 → 1.0.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.

Files changed (92) hide show
  1. data/History.txt +7 -0
  2. data/LICENSE +10 -21
  3. data/README.rdoc +70 -0
  4. data/Rakefile +56 -84
  5. data/ext/ffi_c/AbstractMemory.c +56 -38
  6. data/ext/ffi_c/AbstractMemory.h +15 -22
  7. data/ext/ffi_c/Buffer.c +61 -22
  8. data/ext/ffi_c/Call.c +52 -540
  9. data/ext/ffi_c/Call.h +1 -1
  10. data/ext/ffi_c/DataConverter.c +62 -0
  11. data/ext/ffi_c/DynamicLibrary.c +21 -1
  12. data/ext/ffi_c/Function.c +252 -30
  13. data/ext/ffi_c/MappedType.c +146 -0
  14. data/{libtest/FunctionTest.c → ext/ffi_c/MappedType.h} +32 -25
  15. data/ext/ffi_c/MemoryPointer.c +12 -33
  16. data/ext/ffi_c/Platform.c +2 -0
  17. data/ext/ffi_c/Pointer.c +66 -28
  18. data/ext/ffi_c/Struct.c +19 -306
  19. data/ext/ffi_c/Struct.h +6 -0
  20. data/ext/ffi_c/StructByReference.c +150 -0
  21. data/{libtest/LastErrorTest.c → ext/ffi_c/StructByReference.h} +30 -21
  22. data/ext/ffi_c/StructLayout.c +26 -16
  23. data/ext/ffi_c/Type.c +39 -68
  24. data/ext/ffi_c/Type.h +12 -22
  25. data/ext/ffi_c/Types.c +20 -5
  26. data/ext/ffi_c/Types.h +7 -7
  27. data/ext/ffi_c/Variadic.c +21 -17
  28. data/ext/ffi_c/extconf.rb +4 -0
  29. data/ext/ffi_c/ffi.c +8 -2
  30. data/ext/ffi_c/rbffi.h +1 -0
  31. data/lib/ffi/autopointer.rb +23 -22
  32. data/lib/ffi/enum.rb +36 -21
  33. data/lib/ffi/errno.rb +20 -0
  34. data/lib/ffi/ffi.rb +13 -80
  35. data/lib/ffi/io.rb +12 -20
  36. data/lib/ffi/library.rb +109 -92
  37. data/lib/ffi/managedstruct.rb +1 -1
  38. data/lib/ffi/memorypointer.rb +15 -21
  39. data/lib/ffi/platform.rb +27 -33
  40. data/lib/ffi/pointer.rb +14 -21
  41. data/lib/ffi/struct.rb +98 -49
  42. data/lib/ffi/struct_layout_builder.rb +158 -0
  43. data/lib/ffi/types.rb +99 -128
  44. data/lib/ffi/union.rb +20 -0
  45. data/lib/ffi/variadic.rb +33 -22
  46. data/spec/ffi/async_callback_spec.rb +23 -0
  47. data/spec/ffi/callback_spec.rb +62 -0
  48. data/spec/ffi/custom_param_type.rb +31 -0
  49. data/spec/ffi/custom_type_spec.rb +73 -0
  50. data/spec/ffi/enum_spec.rb +19 -0
  51. data/spec/ffi/ffi_spec.rb +24 -0
  52. data/spec/ffi/pointer_spec.rb +15 -0
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +7 -1
  54. data/spec/ffi/strptr_spec.rb +36 -0
  55. data/spec/ffi/struct_packed_spec.rb +46 -0
  56. data/spec/ffi/struct_spec.rb +19 -5
  57. data/spec/ffi/typedef_spec.rb +14 -0
  58. data/tasks/ann.rake +80 -0
  59. data/tasks/extension.rake +25 -0
  60. data/tasks/gem.rake +200 -0
  61. data/tasks/git.rake +41 -0
  62. data/tasks/notes.rake +27 -0
  63. data/tasks/post_load.rake +34 -0
  64. data/tasks/rdoc.rake +50 -0
  65. data/tasks/rubyforge.rake +55 -0
  66. data/tasks/setup.rb +301 -0
  67. data/tasks/spec.rake +54 -0
  68. data/tasks/svn.rake +47 -0
  69. data/tasks/test.rake +40 -0
  70. metadata +139 -131
  71. data/README.md +0 -109
  72. data/ext/ffi_c/AutoPointer.c +0 -60
  73. data/ext/ffi_c/AutoPointer.h +0 -18
  74. data/ext/ffi_c/Ffi_c.iml +0 -12
  75. data/ffi.gemspec +0 -18
  76. data/gen/log +0 -1
  77. data/lib/Lib.iml +0 -21
  78. data/libtest/Benchmark.c +0 -73
  79. data/libtest/BoolTest.c +0 -52
  80. data/libtest/BufferTest.c +0 -52
  81. data/libtest/ClosureTest.c +0 -173
  82. data/libtest/EnumTest.c +0 -55
  83. data/libtest/GNUmakefile +0 -141
  84. data/libtest/GlobalVariable.c +0 -56
  85. data/libtest/NumberTest.c +0 -145
  86. data/libtest/PointerTest.c +0 -84
  87. data/libtest/ReferenceTest.c +0 -44
  88. data/libtest/StringTest.c +0 -55
  89. data/libtest/StructTest.c +0 -247
  90. data/libtest/UnionTest.c +0 -64
  91. data/libtest/VariadicTest.c +0 -57
  92. data/spec/ffi/Ffi.iml +0 -12
data/lib/ffi/pointer.rb CHANGED
@@ -3,28 +3,20 @@
3
3
  # Copyright (c) 2007, 2008 Evan Phoenix
4
4
  # All rights reserved.
5
5
  #
6
- # Redistribution and use in source and binary forms, with or without
7
- # modification, are permitted provided that the following conditions are met:
6
+ # This file is part of ruby-ffi.
8
7
  #
9
- # * Redistributions of source code must retain the above copyright notice, this
10
- # list of conditions and the following disclaimer.
11
- # * Redistributions in binary form must reproduce the above copyright notice
12
- # this list of conditions and the following disclaimer in the documentation
13
- # and/or other materials provided with the distribution.
14
- # * Neither the name of the Evan Phoenix nor the names of its contributors
15
- # may be used to endorse or promote products derived from this software
16
- # without specific prior written permission.
8
+ # This code is free software: you can redistribute it and/or modify it under
9
+ # the terms of the GNU Lesser General Public License version 3 only, as
10
+ # published by the Free Software Foundation.
11
+ #
12
+ # This code is distributed in the hope that it will be useful, but WITHOUT
13
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15
+ # version 3 for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
17
19
  #
18
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
20
 
29
21
  require 'ffi/platform'
30
22
  module FFI
@@ -95,10 +87,11 @@ module FFI
95
87
  put_bytes(0, str, 0, len)
96
88
  end
97
89
  def write_string(str, len=nil)
98
- len = str.size unless len
90
+ len = str.bytesize unless len
99
91
  # Write the string data without NUL termination
100
92
  put_bytes(0, str, 0, len)
101
93
  end
94
+
102
95
  def read_array_of_type(type, reader, length)
103
96
  ary = []
104
97
  size = FFI.type_size(type)
data/lib/ffi/struct.rb CHANGED
@@ -1,34 +1,28 @@
1
1
  #
2
- # Copyright (C) 2008, 2009 Wayne Meissner
2
+ # Copyright (C) 2008-2010 Wayne Meissner
3
3
  # Copyright (C) 2008, 2009 Andrea Fazzi
4
4
  # Copyright (C) 2008, 2009 Luc Heinrich
5
5
  #
6
6
  # All rights reserved.
7
7
  #
8
- # Redistribution and use in source and binary forms, with or without
9
- # modification, are permitted provided that the following conditions are met:
8
+ # This file is part of ruby-ffi.
10
9
  #
11
- # * Redistributions of source code must retain the above copyright notice, this
12
- # list of conditions and the following disclaimer.
13
- # * Redistributions in binary form must reproduce the above copyright notice
14
- # this list of conditions and the following disclaimer in the documentation
15
- # and/or other materials provided with the distribution.
16
- # * Neither the name of the Evan Phoenix nor the names of its contributors
17
- # may be used to endorse or promote products derived from this software
18
- # without specific prior written permission.
10
+ # This code is free software: you can redistribute it and/or modify it under
11
+ # the terms of the GNU Lesser General Public License version 3 only, as
12
+ # published by the Free Software Foundation.
13
+ #
14
+ # This code is distributed in the hope that it will be useful, but WITHOUT
15
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
17
+ # version 3 for more details.
18
+ #
19
+ # You should have received a copy of the GNU Lesser General Public License
20
+ # version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
19
21
  #
20
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
22
 
31
23
  require 'ffi/platform'
24
+ require 'ffi/struct_layout_builder'
25
+
32
26
  module FFI
33
27
 
34
28
  class StructLayout
@@ -53,7 +47,7 @@ module FFI
53
47
 
54
48
  end
55
49
 
56
- class InlineStruct < Field
50
+ class InnerStruct < Field
57
51
  def get(ptr)
58
52
  type.struct_class.new(ptr.slice(self.offset, self.size))
59
53
  end
@@ -62,6 +56,21 @@ module FFI
62
56
  # raise TypeError, "wrong value type (expected #{type.struct_class}" unless value.is_a(type.struct_class)
63
57
  # end
64
58
  end
59
+
60
+ class Mapped < Field
61
+ def initialize(name, offset, type, orig_field)
62
+ super(name, offset, type)
63
+ @orig_field = orig_field
64
+ end
65
+
66
+ def get(ptr)
67
+ type.from_native(@orig_field.get(ptr), nil)
68
+ end
69
+
70
+ def put(ptr, value)
71
+ @orig_field.put(ptr, type.to_native(value, nil))
72
+ end
73
+ end
65
74
  end
66
75
 
67
76
 
@@ -131,27 +140,60 @@ module FFI
131
140
  end
132
141
 
133
142
  def self.in
134
- :buffer_in
143
+ ptr(:in)
135
144
  end
136
145
 
137
146
  def self.out
138
- :buffer_out
147
+ ptr(:out)
148
+ end
149
+
150
+ def self.ptr(flags = :inout)
151
+ @ref_data_type ||= Type::Mapped.new(StructByReference.new(self))
152
+ end
153
+
154
+ def self.val
155
+ @val_data_type ||= StructByValue.new(self)
139
156
  end
140
157
 
141
158
  def self.by_value
142
- ::FFI::StructByValue.new(self)
159
+ self.val
160
+ end
161
+
162
+ def self.by_ref(flags = :inout)
163
+ self.ptr(flags)
164
+ end
165
+
166
+ class ManagedStructConverter < StructByReference
167
+
168
+ def initialize(struct_class)
169
+ super(struct_class)
170
+
171
+ raise NoMethodError, "release() not implemented for class #{struct_class}" unless struct_class.respond_to? :release
172
+ @method = struct_class.method(:release)
173
+ end
174
+
175
+ def from_native(ptr, ctx)
176
+ struct_class.new(AutoPointer.new(ptr, @method))
177
+ end
143
178
  end
144
179
 
180
+ def self.auto_ptr
181
+ @managed_type ||= Type::Mapped.new(ManagedStructConverter.new(self))
182
+ end
145
183
 
146
184
 
147
185
  class << self
148
186
  public
149
187
 
150
188
  def layout(*spec)
189
+ # raise RuntimeError, "struct layout already defined for #{self.inspect}" if defined?(@layout)
151
190
  return @layout if spec.size == 0
152
191
 
153
- builder = FFI::StructLayoutBuilder.new
192
+ builder = StructLayoutBuilder.new
154
193
  builder.union = self < Union
194
+ builder.packed = @packed if defined?(@packed)
195
+ builder.alignment = @min_alignment if defined?(@min_alignment)
196
+
155
197
  if spec[0].kind_of?(Hash)
156
198
  hash_layout(builder, spec)
157
199
  else
@@ -159,7 +201,7 @@ module FFI
159
201
  end
160
202
  builder.size = @size if defined?(@size) && @size > builder.size
161
203
  cspec = builder.build
162
- @layout = cspec unless self == FFI::Struct
204
+ @layout = cspec unless self == Struct
163
205
  @size = cspec.size
164
206
  return cspec
165
207
  end
@@ -172,6 +214,15 @@ module FFI
172
214
  FFI::CallbackInfo.new(find_type(ret, mod), params.map { |e| find_type(e, mod) })
173
215
  end
174
216
 
217
+ def packed(packed = 1)
218
+ @packed = packed
219
+ end
220
+ alias :pack :packed
221
+
222
+ def aligned(alignment = 1)
223
+ @min_alignment = alignment
224
+ end
225
+ alias :align :aligned
175
226
 
176
227
  def enclosing_module
177
228
  begin
@@ -182,35 +233,38 @@ module FFI
182
233
  end
183
234
  end
184
235
 
185
- def find_type(type, mod = nil)
186
- if type.kind_of?(Class) && type < FFI::Struct
236
+
237
+ def find_field_type(type, mod = enclosing_module)
238
+ if type.kind_of?(Class) && type < Struct
187
239
  FFI::Type::Struct.new(type)
188
- elsif type.is_a?(::Array)
240
+
241
+ elsif type.kind_of?(Class) && type < FFI::StructLayout::Field
189
242
  type
190
- elsif mod
243
+
244
+ elsif type.kind_of?(::Array)
245
+ FFI::Type::Array.new(find_field_type(type[0]), type[1])
246
+
247
+ else
248
+ find_type(type, mod)
249
+ end
250
+ end
251
+
252
+ def find_type(type, mod = enclosing_module)
253
+ if mod
191
254
  mod.find_type(type)
192
255
  end || FFI.find_type(type)
193
256
  end
194
257
 
195
-
196
258
  private
197
259
 
198
260
  def hash_layout(builder, spec)
199
261
  raise "Ruby version not supported" if RUBY_VERSION =~ /1.8.*/
200
- mod = enclosing_module
201
- spec[0].each do |name,type|
202
- if type.kind_of?(Class) && type < Struct
203
- builder.add_struct(name, type)
204
- elsif type.kind_of?(::Array)
205
- builder.add_array(name, find_type(type[0], mod), type[1])
206
- else
207
- builder.add_field(name, find_type(type, mod))
208
- end
262
+ spec[0].each do |name, type|
263
+ builder.add name, find_field_type(type), nil
209
264
  end
210
265
  end
211
266
 
212
267
  def array_layout(builder, spec)
213
- mod = enclosing_module
214
268
  i = 0
215
269
  while i < spec.size
216
270
  name, type = spec[i, 2]
@@ -223,13 +277,8 @@ module FFI
223
277
  else
224
278
  offset = nil
225
279
  end
226
- if type.kind_of?(Class) && type < Struct
227
- builder.add_struct(name, type, offset)
228
- elsif type.kind_of?(::Array)
229
- builder.add_array(name, find_type(type[0], mod), type[1], offset)
230
- else
231
- builder.add_field(name, find_type(type, mod), offset)
232
- end
280
+
281
+ builder.add name, find_field_type(type), offset
233
282
  end
234
283
  end
235
284
  end
@@ -0,0 +1,158 @@
1
+ #
2
+ # Copyright (C) 2008-2010 Wayne Meissner
3
+ #
4
+ # All rights reserved.
5
+ #
6
+ # This file is part of ruby-ffi.
7
+ #
8
+ # This code is free software: you can redistribute it and/or modify it under
9
+ # the terms of the GNU Lesser General Public License version 3 only, as
10
+ # published by the Free Software Foundation.
11
+ #
12
+ # This code is distributed in the hope that it will be useful, but WITHOUT
13
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15
+ # version 3 for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # version 3 along with this work. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ module FFI
22
+ class StructLayoutBuilder
23
+ attr_reader :size, :alignment
24
+
25
+ def initialize
26
+ @size = 0
27
+ @alignment = 1
28
+ @min_alignment = 1
29
+ @packed = false
30
+ @union = false
31
+ @fields = Array.new
32
+ end
33
+
34
+ def size=(size)
35
+ @size = size if size > @size
36
+ end
37
+
38
+ def alignment=(align)
39
+ @alignment = align if align > @alignment
40
+ @min_alignment = align
41
+ end
42
+
43
+ def union=(is_union)
44
+ @union = is_union
45
+ end
46
+
47
+ def union?
48
+ @union
49
+ end
50
+
51
+ def packed=(packed)
52
+ if packed.is_a?(Fixnum)
53
+ @alignment = packed
54
+ @packed = packed
55
+ else
56
+ @packed = packed ? 1 : 0
57
+ end
58
+ end
59
+
60
+
61
+ NUMBER_TYPES = [
62
+ Type::INT8,
63
+ Type::UINT8,
64
+ Type::INT16,
65
+ Type::UINT16,
66
+ Type::INT32,
67
+ Type::UINT32,
68
+ Type::LONG,
69
+ Type::ULONG,
70
+ Type::INT64,
71
+ Type::UINT64,
72
+ Type::FLOAT32,
73
+ Type::FLOAT64,
74
+ ]
75
+
76
+ def add(name, type, offset = nil)
77
+
78
+ if offset.nil? || offset == -1
79
+ offset = @union ? 0 : align(@size, @packed ? [ @packed, type.alignment ].min : [ @min_alignment, type.alignment ].max)
80
+ end
81
+
82
+ #
83
+ # If a FFI::Type type was passed in as the field arg, try and convert to a StructLayout::Field instance
84
+ #
85
+ field = type.is_a?(StructLayout::Field) ? type : field_for_type(name, offset, type)
86
+ @fields << field
87
+ @alignment = [ @alignment, field.alignment ].max unless @packed
88
+ @size = [ @size, field.size + (@union ? 0 : field.offset) ].max
89
+
90
+ return self
91
+ end
92
+
93
+ def add_field(name, type, offset = nil)
94
+ add(name, type, offset)
95
+ end
96
+
97
+ def add_struct(name, type, offset = nil)
98
+ add(name, Type::Struct.new(type), offset)
99
+ end
100
+
101
+ def add_array(name, type, count, offset = nil)
102
+ add(name, Type::Array.new(type, count), offset)
103
+ end
104
+
105
+ def build
106
+ # Add tail padding if the struct is not packed
107
+ size = @packed ? @size : align(@size, @alignment)
108
+
109
+ StructLayout.new(@fields, size, @alignment)
110
+ end
111
+
112
+ private
113
+
114
+ def align(offset, align)
115
+ align + ((offset - 1) & ~(align - 1));
116
+ end
117
+
118
+ def field_for_type(name, offset, type)
119
+ field_class = case
120
+ when type.is_a?(Type::Function)
121
+ StructLayout::Function
122
+
123
+ when type.is_a?(Type::Struct)
124
+ StructLayout::InnerStruct
125
+
126
+ when type.is_a?(Type::Array)
127
+ StructLayout::Array
128
+
129
+ when type.is_a?(FFI::Enum)
130
+ StructLayout::Enum
131
+
132
+ when NUMBER_TYPES.include?(type)
133
+ StructLayout::Number
134
+
135
+ when type == Type::POINTER
136
+ StructLayout::Pointer
137
+
138
+ when type == Type::STRING
139
+ StructLayout::String
140
+
141
+ when type.is_a?(Class) && type < StructLayout::Field
142
+ type
143
+
144
+ when type.is_a?(DataConverter)
145
+ return StructLayout::Mapped.new(name, offset, Type::Mapped.new(type), field_for_type(name, offset, type.native_type))
146
+
147
+ when type.is_a?(Type::Mapped)
148
+ return StructLayout::Mapped.new(name, offset, type, field_for_type(name, offset, type.native_type))
149
+
150
+ else
151
+ raise TypeError, "invalid struct field type #{type.inspect}"
152
+ end
153
+
154
+ field_class.new(name, offset, type)
155
+ end
156
+ end
157
+
158
+ end