fiddle 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +9 -4
- data/ext/fiddle/closure.c +2 -2
- data/ext/fiddle/conversions.c +0 -2
- data/ext/fiddle/extconf.rb +7 -0
- data/ext/fiddle/fiddle.c +0 -1
- data/ext/fiddle/fiddle.h +10 -1
- data/ext/fiddle/function.c +5 -3
- data/ext/fiddle/handle.c +2 -3
- data/ext/fiddle/memory_view.c +7 -2
- data/ext/fiddle/pinned.c +7 -3
- data/ext/fiddle/pointer.c +2 -2
- data/fiddle.gemspec +2 -4
- data/lib/fiddle/ffi_backend.rb +613 -0
- data/lib/fiddle/pack.rb +6 -0
- data/lib/fiddle/struct.rb +27 -6
- data/lib/fiddle/version.rb +1 -1
- data/lib/fiddle.rb +39 -8
- metadata +5 -10
- data/ext/fiddle/win32/fficonfig.h +0 -29
- data/ext/fiddle/win32/libffi-3.2.1-mswin.patch +0 -191
- data/ext/fiddle/win32/libffi-config.rb +0 -48
- data/ext/fiddle/win32/libffi.mk.tmpl +0 -96
@@ -0,0 +1,613 @@
|
|
1
|
+
# This is based on JRuby's FFI-based fiddle implementation.
|
2
|
+
|
3
|
+
require 'ffi'
|
4
|
+
|
5
|
+
module Fiddle
|
6
|
+
def self.malloc(size)
|
7
|
+
Fiddle::Pointer.malloc(size)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.free(ptr)
|
11
|
+
Fiddle::Pointer::LibC::FREE.call(ptr)
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.dlwrap(val)
|
16
|
+
Pointer.to_ptr(val)
|
17
|
+
end
|
18
|
+
|
19
|
+
module Types
|
20
|
+
VOID = 0
|
21
|
+
VOIDP = 1
|
22
|
+
CHAR = 2
|
23
|
+
UCHAR = -CHAR
|
24
|
+
SHORT = 3
|
25
|
+
USHORT = -SHORT
|
26
|
+
INT = 4
|
27
|
+
UINT = -INT
|
28
|
+
LONG = 5
|
29
|
+
ULONG = -LONG
|
30
|
+
LONG_LONG = 6
|
31
|
+
ULONG_LONG = -LONG_LONG
|
32
|
+
FLOAT = 7
|
33
|
+
DOUBLE = 8
|
34
|
+
VARIADIC = 9
|
35
|
+
CONST_STRING = 10
|
36
|
+
BOOL = 11
|
37
|
+
INT8_T = CHAR
|
38
|
+
UINT8_T = UCHAR
|
39
|
+
if FFI::Type::Builtin::SHORT.size == 2
|
40
|
+
INT16_T = SHORT
|
41
|
+
UINT16_T = USHORT
|
42
|
+
elsif FFI::Type::Builtin::INT.size == 2
|
43
|
+
INT16_T = INT
|
44
|
+
UINT16_T = UINT
|
45
|
+
end
|
46
|
+
if FFI::Type::Builtin::SHORT.size == 4
|
47
|
+
INT32_T = SHORT
|
48
|
+
UINT32_T = USHORT
|
49
|
+
elsif FFI::Type::Builtin::INT.size == 4
|
50
|
+
INT32_T = INT
|
51
|
+
UINT32_T = UINT
|
52
|
+
elsif FFI::Type::Builtin::LONG.size == 4
|
53
|
+
INT32_T = LONG
|
54
|
+
UINT32_T = ULONG
|
55
|
+
end
|
56
|
+
if FFI::Type::Builtin::INT.size == 8
|
57
|
+
INT64_T = INT
|
58
|
+
UINT64_T = UINT
|
59
|
+
elsif FFI::Type::Builtin::LONG.size == 8
|
60
|
+
INT64_T = LONG
|
61
|
+
UINT64_T = ULONG
|
62
|
+
else
|
63
|
+
INT64_T = LONG_LONG
|
64
|
+
UINT64_T = ULONG_LONG
|
65
|
+
end
|
66
|
+
|
67
|
+
# FIXME: platform specific values
|
68
|
+
SSIZE_T = INT64_T
|
69
|
+
SIZE_T = -SSIZE_T
|
70
|
+
PTRDIFF_T = SSIZE_T
|
71
|
+
INTPTR_T = INT64_T
|
72
|
+
UINTPTR_T = -INTPTR_T
|
73
|
+
end
|
74
|
+
|
75
|
+
WINDOWS = FFI::Platform.windows?
|
76
|
+
|
77
|
+
module FFIBackend
|
78
|
+
FFITypes = {
|
79
|
+
'c' => FFI::Type::INT8,
|
80
|
+
'h' => FFI::Type::INT16,
|
81
|
+
'i' => FFI::Type::INT32,
|
82
|
+
'l' => FFI::Type::LONG,
|
83
|
+
'f' => FFI::Type::FLOAT32,
|
84
|
+
'd' => FFI::Type::FLOAT64,
|
85
|
+
'p' => FFI::Type::POINTER,
|
86
|
+
's' => FFI::Type::STRING,
|
87
|
+
|
88
|
+
Types::VOID => FFI::Type::Builtin::VOID,
|
89
|
+
Types::VOIDP => FFI::Type::Builtin::POINTER,
|
90
|
+
Types::CHAR => FFI::Type::Builtin::CHAR,
|
91
|
+
Types::UCHAR => FFI::Type::Builtin::UCHAR,
|
92
|
+
Types::SHORT => FFI::Type::Builtin::SHORT,
|
93
|
+
Types::USHORT => FFI::Type::Builtin::USHORT,
|
94
|
+
Types::INT => FFI::Type::Builtin::INT,
|
95
|
+
Types::UINT => FFI::Type::Builtin::UINT,
|
96
|
+
Types::LONG => FFI::Type::Builtin::LONG,
|
97
|
+
Types::ULONG => FFI::Type::Builtin::ULONG,
|
98
|
+
Types::LONG_LONG => FFI::Type::Builtin::LONG_LONG,
|
99
|
+
Types::ULONG_LONG => FFI::Type::Builtin::ULONG_LONG,
|
100
|
+
Types::FLOAT => FFI::Type::Builtin::FLOAT,
|
101
|
+
Types::DOUBLE => FFI::Type::Builtin::DOUBLE,
|
102
|
+
Types::BOOL => FFI::Type::Builtin::BOOL,
|
103
|
+
Types::CONST_STRING => FFI::Type::Builtin::POINTER,
|
104
|
+
Types::VARIADIC => FFI::Type::Builtin::VARARGS,
|
105
|
+
}
|
106
|
+
|
107
|
+
def self.to_ffi_type(fiddle_type)
|
108
|
+
if fiddle_type.is_a?(Symbol)
|
109
|
+
fiddle_type = Types.const_get(fiddle_type.to_s.upcase)
|
110
|
+
end
|
111
|
+
if !fiddle_type.is_a?(Integer) && fiddle_type.respond_to?(:to_int)
|
112
|
+
fiddle_type = fiddle_type.to_int
|
113
|
+
end
|
114
|
+
ffi_type = FFITypes[fiddle_type]
|
115
|
+
ffi_type = FFITypes[-fiddle_type] if ffi_type.nil? && fiddle_type.is_a?(Integer) && fiddle_type < 0
|
116
|
+
raise TypeError.new("cannot convert #{fiddle_type} to ffi") unless ffi_type
|
117
|
+
ffi_type
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Function
|
122
|
+
DEFAULT = "default"
|
123
|
+
STDCALL = "stdcall"
|
124
|
+
|
125
|
+
def initialize(ptr, args, return_type, abi = DEFAULT, kwargs = nil)
|
126
|
+
if kwargs.nil?
|
127
|
+
if abi.kind_of? Hash
|
128
|
+
kwargs = abi
|
129
|
+
abi = DEFAULT
|
130
|
+
end
|
131
|
+
end
|
132
|
+
@name = kwargs[:name] if kwargs.kind_of? Hash
|
133
|
+
@ptr, @args, @return_type, @abi = ptr, args, return_type, abi
|
134
|
+
raise TypeError.new "invalid argument types" unless args.is_a?(Array)
|
135
|
+
|
136
|
+
ffi_return_type = Fiddle::FFIBackend.to_ffi_type(@return_type)
|
137
|
+
ffi_args = @args.map { |t| Fiddle::FFIBackend.to_ffi_type(t) }
|
138
|
+
pointer = FFI::Pointer.new(ptr.to_i)
|
139
|
+
options = {convention: @abi}
|
140
|
+
if ffi_args.last == FFI::Type::Builtin::VARARGS
|
141
|
+
@function = FFI::VariadicInvoker.new(
|
142
|
+
pointer,
|
143
|
+
ffi_args,
|
144
|
+
ffi_return_type,
|
145
|
+
options
|
146
|
+
)
|
147
|
+
else
|
148
|
+
@function = FFI::Function.new(ffi_return_type, ffi_args, pointer, options)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def call(*args, &block)
|
153
|
+
if @function.is_a?(FFI::VariadicInvoker)
|
154
|
+
n_fixed_args = @args.size - 1
|
155
|
+
n_fixed_args.step(args.size - 1, 2) do |i|
|
156
|
+
if args[i] == :const_string || args[i] == Types::CONST_STRING
|
157
|
+
args[i + 1] = String.try_convert(args[i + 1]) || args[i + 1]
|
158
|
+
end
|
159
|
+
args[i] = Fiddle::FFIBackend.to_ffi_type(args[i])
|
160
|
+
end
|
161
|
+
else
|
162
|
+
args.map! do |arg|
|
163
|
+
if arg.respond_to?(:to_ptr)
|
164
|
+
begin
|
165
|
+
arg = arg.to_ptr
|
166
|
+
end until arg.is_a?(FFI::Pointer) || !arg.respond_to?(:to_ptr)
|
167
|
+
arg
|
168
|
+
else
|
169
|
+
arg
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
result = @function.call(*args, &block)
|
174
|
+
result = Pointer.new(result) if result.is_a?(FFI::Pointer)
|
175
|
+
result
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class Closure
|
180
|
+
def initialize(ret, args, abi = Function::DEFAULT)
|
181
|
+
raise TypeError.new "invalid argument types" unless args.is_a?(Array)
|
182
|
+
|
183
|
+
@ctype, @args = ret, args
|
184
|
+
ffi_args = @args.map { |t| Fiddle::FFIBackend.to_ffi_type(t) }
|
185
|
+
if ffi_args.size == 1 && ffi_args[0] == FFI::Type::Builtin::VOID
|
186
|
+
ffi_args = []
|
187
|
+
end
|
188
|
+
return_type = Fiddle::FFIBackend.to_ffi_type(@ctype)
|
189
|
+
raise "#{self.class} must implement #call" unless respond_to?(:call)
|
190
|
+
callable = method(:call)
|
191
|
+
@function = FFI::Function.new(return_type, ffi_args, callable, convention: abi)
|
192
|
+
@freed = false
|
193
|
+
end
|
194
|
+
|
195
|
+
def to_ptr
|
196
|
+
@function
|
197
|
+
end
|
198
|
+
|
199
|
+
def to_i
|
200
|
+
@function.to_i
|
201
|
+
end
|
202
|
+
|
203
|
+
def free
|
204
|
+
return if @freed
|
205
|
+
@function.free
|
206
|
+
@freed = true
|
207
|
+
end
|
208
|
+
|
209
|
+
def freed?
|
210
|
+
@freed
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class Error < StandardError; end
|
215
|
+
class DLError < Error; end
|
216
|
+
class ClearedReferenceError < Error; end
|
217
|
+
|
218
|
+
class Pointer
|
219
|
+
attr_reader :ffi_ptr
|
220
|
+
extend FFI::DataConverter
|
221
|
+
native_type FFI::Type::Builtin::POINTER
|
222
|
+
|
223
|
+
def self.to_native(value, ctx)
|
224
|
+
if value.is_a?(Pointer)
|
225
|
+
value.ffi_ptr
|
226
|
+
|
227
|
+
elsif value.is_a?(Integer)
|
228
|
+
FFI::Pointer.new(value)
|
229
|
+
|
230
|
+
elsif value.is_a?(String)
|
231
|
+
value
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.from_native(value, ctx)
|
236
|
+
self.new(value)
|
237
|
+
end
|
238
|
+
|
239
|
+
def self.to_ptr(value)
|
240
|
+
if value.is_a?(String)
|
241
|
+
cptr = Pointer.malloc(value.bytesize)
|
242
|
+
cptr.ffi_ptr.put_string(0, value)
|
243
|
+
cptr
|
244
|
+
|
245
|
+
elsif value.is_a?(Array)
|
246
|
+
raise NotImplementedError, "array ptr"
|
247
|
+
|
248
|
+
elsif value.respond_to?(:to_ptr)
|
249
|
+
ptr = value.to_ptr
|
250
|
+
case ptr
|
251
|
+
when Pointer
|
252
|
+
ptr
|
253
|
+
when FFI::Pointer
|
254
|
+
Pointer.new(ptr)
|
255
|
+
else
|
256
|
+
raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{ptr.class}")
|
257
|
+
end
|
258
|
+
|
259
|
+
else
|
260
|
+
Pointer.new(value)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
class << self
|
265
|
+
alias [] to_ptr
|
266
|
+
end
|
267
|
+
|
268
|
+
def []=(*args, value)
|
269
|
+
if args.size == 2
|
270
|
+
if value.is_a?(Integer)
|
271
|
+
value = self.class.new(value)
|
272
|
+
end
|
273
|
+
if value.is_a?(Fiddle::Pointer)
|
274
|
+
value = value.to_str(args[1])
|
275
|
+
end
|
276
|
+
|
277
|
+
@ffi_ptr.put_bytes(args[0], value, 0, args[1])
|
278
|
+
elsif args.size == 1
|
279
|
+
if value.is_a?(Fiddle::Pointer)
|
280
|
+
value = value.to_str(args[0] + 1)
|
281
|
+
else
|
282
|
+
value = value.chr
|
283
|
+
end
|
284
|
+
|
285
|
+
@ffi_ptr.put_bytes(args[0], value, 0, 1)
|
286
|
+
end
|
287
|
+
rescue FFI::NullPointerError
|
288
|
+
raise DLError.new("NULL pointer access")
|
289
|
+
end
|
290
|
+
|
291
|
+
def initialize(addr, size = nil, free = nil)
|
292
|
+
ptr = if addr.is_a?(FFI::Pointer)
|
293
|
+
addr
|
294
|
+
|
295
|
+
elsif addr.is_a?(Integer)
|
296
|
+
FFI::Pointer.new(addr)
|
297
|
+
|
298
|
+
elsif addr.respond_to?(:to_ptr)
|
299
|
+
fiddle_ptr = addr.to_ptr
|
300
|
+
if fiddle_ptr.is_a?(Pointer)
|
301
|
+
fiddle_ptr.ffi_ptr
|
302
|
+
elsif fiddle_ptr.is_a?(FFI::AutoPointer)
|
303
|
+
addr.ffi_ptr
|
304
|
+
elsif fiddle_ptr.is_a?(FFI::Pointer)
|
305
|
+
fiddle_ptr
|
306
|
+
else
|
307
|
+
raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{fiddle_ptr.class}")
|
308
|
+
end
|
309
|
+
elsif addr.is_a?(IO)
|
310
|
+
raise NotImplementedError, "IO ptr isn't supported"
|
311
|
+
end
|
312
|
+
|
313
|
+
@size = size ? size : ptr.size
|
314
|
+
@free = free
|
315
|
+
@ffi_ptr = ptr
|
316
|
+
@freed = false
|
317
|
+
end
|
318
|
+
|
319
|
+
module LibC
|
320
|
+
extend FFI::Library
|
321
|
+
ffi_lib FFI::Library::LIBC
|
322
|
+
MALLOC = attach_function :malloc, [ :size_t ], :pointer
|
323
|
+
REALLOC = attach_function :realloc, [ :pointer, :size_t ], :pointer
|
324
|
+
FREE = attach_function :free, [ :pointer ], :void
|
325
|
+
end
|
326
|
+
|
327
|
+
def self.malloc(size, free = nil)
|
328
|
+
if block_given? and free.nil?
|
329
|
+
message = "a free function must be supplied to #{self}.malloc " +
|
330
|
+
"when it is called with a block"
|
331
|
+
raise ArgumentError, message
|
332
|
+
end
|
333
|
+
|
334
|
+
pointer = new(LibC.malloc(size), size, free)
|
335
|
+
if block_given?
|
336
|
+
begin
|
337
|
+
yield(pointer)
|
338
|
+
ensure
|
339
|
+
pointer.call_free
|
340
|
+
end
|
341
|
+
else
|
342
|
+
pointer
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def null?
|
347
|
+
@ffi_ptr.null?
|
348
|
+
end
|
349
|
+
|
350
|
+
def to_ptr
|
351
|
+
@ffi_ptr
|
352
|
+
end
|
353
|
+
|
354
|
+
def size
|
355
|
+
defined?(@layout) ? @layout.size : @size
|
356
|
+
end
|
357
|
+
|
358
|
+
def free
|
359
|
+
@free
|
360
|
+
end
|
361
|
+
|
362
|
+
def free=(free)
|
363
|
+
@free = free
|
364
|
+
end
|
365
|
+
|
366
|
+
def call_free
|
367
|
+
return if @free.nil?
|
368
|
+
return if @freed
|
369
|
+
if @free == RUBY_FREE
|
370
|
+
LibC::FREE.call(@ffi_ptr)
|
371
|
+
else
|
372
|
+
@free.call(@ffi_ptr)
|
373
|
+
end
|
374
|
+
@freed = true
|
375
|
+
end
|
376
|
+
|
377
|
+
def freed?
|
378
|
+
@freed
|
379
|
+
end
|
380
|
+
|
381
|
+
def size=(size)
|
382
|
+
@size = size
|
383
|
+
end
|
384
|
+
|
385
|
+
def [](index, length = nil)
|
386
|
+
if length
|
387
|
+
ffi_ptr.get_bytes(index, length)
|
388
|
+
else
|
389
|
+
ffi_ptr.get_char(index)
|
390
|
+
end
|
391
|
+
rescue FFI::NullPointerError
|
392
|
+
raise DLError.new("NULL pointer dereference")
|
393
|
+
end
|
394
|
+
|
395
|
+
def to_i
|
396
|
+
ffi_ptr.to_i
|
397
|
+
end
|
398
|
+
alias to_int to_i
|
399
|
+
|
400
|
+
# without \0
|
401
|
+
def to_s(len = nil)
|
402
|
+
if len
|
403
|
+
ffi_ptr.get_string(0, len)
|
404
|
+
else
|
405
|
+
ffi_ptr.get_string(0)
|
406
|
+
end
|
407
|
+
rescue FFI::NullPointerError
|
408
|
+
raise DLError.new("NULL pointer access")
|
409
|
+
end
|
410
|
+
|
411
|
+
def to_str(len = nil)
|
412
|
+
if len
|
413
|
+
ffi_ptr.read_string(len)
|
414
|
+
else
|
415
|
+
ffi_ptr.read_string(@size)
|
416
|
+
end
|
417
|
+
rescue FFI::NullPointerError
|
418
|
+
raise DLError.new("NULL pointer access")
|
419
|
+
end
|
420
|
+
|
421
|
+
def to_value
|
422
|
+
raise NotImplementedError, "to_value isn't supported"
|
423
|
+
end
|
424
|
+
|
425
|
+
def inspect
|
426
|
+
"#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
|
427
|
+
end
|
428
|
+
|
429
|
+
def +(delta)
|
430
|
+
self.class.new(to_i + delta, @size - delta)
|
431
|
+
end
|
432
|
+
|
433
|
+
def -(delta)
|
434
|
+
self.class.new(to_i - delta, @size + delta)
|
435
|
+
end
|
436
|
+
|
437
|
+
def <=>(other)
|
438
|
+
return unless other.is_a?(Pointer)
|
439
|
+
diff = self.to_i - other.to_i
|
440
|
+
return 0 if diff == 0
|
441
|
+
diff > 0 ? 1 : -1
|
442
|
+
end
|
443
|
+
|
444
|
+
def eql?(other)
|
445
|
+
return unless other.is_a?(Pointer)
|
446
|
+
self.to_i == other.to_i
|
447
|
+
end
|
448
|
+
|
449
|
+
def ==(other)
|
450
|
+
eql?(other)
|
451
|
+
end
|
452
|
+
|
453
|
+
def ptr
|
454
|
+
Pointer.new(ffi_ptr.get_pointer(0))
|
455
|
+
end
|
456
|
+
|
457
|
+
def +@
|
458
|
+
ptr
|
459
|
+
end
|
460
|
+
|
461
|
+
def -@
|
462
|
+
ref
|
463
|
+
end
|
464
|
+
|
465
|
+
def ref
|
466
|
+
cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE)
|
467
|
+
cptr.ffi_ptr.put_pointer(0, ffi_ptr)
|
468
|
+
cptr
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
class Handle
|
473
|
+
RTLD_GLOBAL = FFI::DynamicLibrary::RTLD_GLOBAL
|
474
|
+
RTLD_LAZY = FFI::DynamicLibrary::RTLD_LAZY
|
475
|
+
RTLD_NOW = FFI::DynamicLibrary::RTLD_NOW
|
476
|
+
|
477
|
+
def initialize(libname = nil, flags = RTLD_LAZY | RTLD_GLOBAL)
|
478
|
+
@lib = FFI::DynamicLibrary.open(libname, flags) rescue LoadError
|
479
|
+
raise DLError.new("Could not open #{libname}") unless @lib
|
480
|
+
|
481
|
+
@open = true
|
482
|
+
|
483
|
+
begin
|
484
|
+
yield(self)
|
485
|
+
ensure
|
486
|
+
self.close
|
487
|
+
end if block_given?
|
488
|
+
end
|
489
|
+
|
490
|
+
def close
|
491
|
+
raise DLError.new("closed handle") unless @open
|
492
|
+
@open = false
|
493
|
+
0
|
494
|
+
end
|
495
|
+
|
496
|
+
def self.sym(func)
|
497
|
+
DEFAULT.sym(func)
|
498
|
+
end
|
499
|
+
|
500
|
+
def sym(func)
|
501
|
+
raise TypeError.new("invalid function name") unless func.is_a?(String)
|
502
|
+
raise DLError.new("closed handle") unless @open
|
503
|
+
address = @lib.find_function(func)
|
504
|
+
raise DLError.new("unknown symbol #{func}") if address.nil? || address.null?
|
505
|
+
address.to_i
|
506
|
+
end
|
507
|
+
|
508
|
+
def self.sym_defined?(func)
|
509
|
+
DEFAULT.sym_defined?(func)
|
510
|
+
end
|
511
|
+
|
512
|
+
def sym_defined?(func)
|
513
|
+
raise TypeError.new("invalid function name") unless func.is_a?(String)
|
514
|
+
raise DLError.new("closed handle") unless @open
|
515
|
+
address = @lib.find_function(func)
|
516
|
+
!address.nil? && !address.null?
|
517
|
+
end
|
518
|
+
|
519
|
+
def self.[](func)
|
520
|
+
self.sym(func)
|
521
|
+
end
|
522
|
+
|
523
|
+
def [](func)
|
524
|
+
sym(func)
|
525
|
+
end
|
526
|
+
|
527
|
+
def enable_close
|
528
|
+
@enable_close = true
|
529
|
+
end
|
530
|
+
|
531
|
+
def close_enabled?
|
532
|
+
@enable_close
|
533
|
+
end
|
534
|
+
|
535
|
+
def disable_close
|
536
|
+
@enable_close = false
|
537
|
+
end
|
538
|
+
|
539
|
+
DEFAULT = new
|
540
|
+
end
|
541
|
+
|
542
|
+
class Pinned
|
543
|
+
def initialize(object)
|
544
|
+
@object = object
|
545
|
+
end
|
546
|
+
|
547
|
+
def ref
|
548
|
+
if @object.nil?
|
549
|
+
raise ClearedReferenceError, "`ref` called on a cleared object"
|
550
|
+
end
|
551
|
+
@object
|
552
|
+
end
|
553
|
+
|
554
|
+
def clear
|
555
|
+
@object = nil
|
556
|
+
end
|
557
|
+
|
558
|
+
def cleared?
|
559
|
+
@object.nil?
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
RUBY_FREE = Fiddle::Pointer::LibC::FREE.address
|
564
|
+
NULL = Fiddle::Pointer.new(0)
|
565
|
+
|
566
|
+
ALIGN_VOIDP = Fiddle::FFIBackend::FFITypes[Types::VOIDP].alignment
|
567
|
+
ALIGN_CHAR = Fiddle::FFIBackend::FFITypes[Types::CHAR].alignment
|
568
|
+
ALIGN_SHORT = Fiddle::FFIBackend::FFITypes[Types::SHORT].alignment
|
569
|
+
ALIGN_INT = Fiddle::FFIBackend::FFITypes[Types::INT].alignment
|
570
|
+
ALIGN_LONG = Fiddle::FFIBackend::FFITypes[Types::LONG].alignment
|
571
|
+
ALIGN_LONG_LONG = Fiddle::FFIBackend::FFITypes[Types::LONG_LONG].alignment
|
572
|
+
ALIGN_INT8_T = Fiddle::FFIBackend::FFITypes[Types::INT8_T].alignment
|
573
|
+
ALIGN_INT16_T = Fiddle::FFIBackend::FFITypes[Types::INT16_T].alignment
|
574
|
+
ALIGN_INT32_T = Fiddle::FFIBackend::FFITypes[Types::INT32_T].alignment
|
575
|
+
ALIGN_INT64_T = Fiddle::FFIBackend::FFITypes[Types::INT64_T].alignment
|
576
|
+
ALIGN_FLOAT = Fiddle::FFIBackend::FFITypes[Types::FLOAT].alignment
|
577
|
+
ALIGN_DOUBLE = Fiddle::FFIBackend::FFITypes[Types::DOUBLE].alignment
|
578
|
+
ALIGN_BOOL = Fiddle::FFIBackend::FFITypes[Types::BOOL].alignment
|
579
|
+
ALIGN_SIZE_T = Fiddle::FFIBackend::FFITypes[Types::SIZE_T].alignment
|
580
|
+
ALIGN_SSIZE_T = ALIGN_SIZE_T
|
581
|
+
ALIGN_PTRDIFF_T = Fiddle::FFIBackend::FFITypes[Types::PTRDIFF_T].alignment
|
582
|
+
ALIGN_INTPTR_T = Fiddle::FFIBackend::FFITypes[Types::INTPTR_T].alignment
|
583
|
+
ALIGN_UINTPTR_T = Fiddle::FFIBackend::FFITypes[Types::UINTPTR_T].alignment
|
584
|
+
|
585
|
+
SIZEOF_VOIDP = Fiddle::FFIBackend::FFITypes[Types::VOIDP].size
|
586
|
+
SIZEOF_CHAR = Fiddle::FFIBackend::FFITypes[Types::CHAR].size
|
587
|
+
SIZEOF_UCHAR = Fiddle::FFIBackend::FFITypes[Types::UCHAR].size
|
588
|
+
SIZEOF_SHORT = Fiddle::FFIBackend::FFITypes[Types::SHORT].size
|
589
|
+
SIZEOF_USHORT = Fiddle::FFIBackend::FFITypes[Types::USHORT].size
|
590
|
+
SIZEOF_INT = Fiddle::FFIBackend::FFITypes[Types::INT].size
|
591
|
+
SIZEOF_UINT = Fiddle::FFIBackend::FFITypes[Types::UINT].size
|
592
|
+
SIZEOF_LONG = Fiddle::FFIBackend::FFITypes[Types::LONG].size
|
593
|
+
SIZEOF_ULONG = Fiddle::FFIBackend::FFITypes[Types::ULONG].size
|
594
|
+
SIZEOF_LONG_LONG = Fiddle::FFIBackend::FFITypes[Types::LONG_LONG].size
|
595
|
+
SIZEOF_ULONG_LONG = Fiddle::FFIBackend::FFITypes[Types::ULONG_LONG].size
|
596
|
+
SIZEOF_INT8_T = Fiddle::FFIBackend::FFITypes[Types::INT8_T].size
|
597
|
+
SIZEOF_UINT8_T = Fiddle::FFIBackend::FFITypes[Types::UINT8_T].size
|
598
|
+
SIZEOF_INT16_T = Fiddle::FFIBackend::FFITypes[Types::INT16_T].size
|
599
|
+
SIZEOF_UINT16_T = Fiddle::FFIBackend::FFITypes[Types::UINT16_T].size
|
600
|
+
SIZEOF_INT32_T = Fiddle::FFIBackend::FFITypes[Types::INT32_T].size
|
601
|
+
SIZEOF_UINT32_T = Fiddle::FFIBackend::FFITypes[Types::UINT32_T].size
|
602
|
+
SIZEOF_INT64_T = Fiddle::FFIBackend::FFITypes[Types::INT64_T].size
|
603
|
+
SIZEOF_UINT64_T = Fiddle::FFIBackend::FFITypes[Types::UINT64_T].size
|
604
|
+
SIZEOF_FLOAT = Fiddle::FFIBackend::FFITypes[Types::FLOAT].size
|
605
|
+
SIZEOF_DOUBLE = Fiddle::FFIBackend::FFITypes[Types::DOUBLE].size
|
606
|
+
SIZEOF_BOOL = Fiddle::FFIBackend::FFITypes[Types::BOOL].size
|
607
|
+
SIZEOF_SIZE_T = Fiddle::FFIBackend::FFITypes[Types::SIZE_T].size
|
608
|
+
SIZEOF_SSIZE_T = SIZEOF_SIZE_T
|
609
|
+
SIZEOF_PTRDIFF_T = Fiddle::FFIBackend::FFITypes[Types::PTRDIFF_T].size
|
610
|
+
SIZEOF_INTPTR_T = Fiddle::FFIBackend::FFITypes[Types::INTPTR_T].size
|
611
|
+
SIZEOF_UINTPTR_T = Fiddle::FFIBackend::FFITypes[Types::UINTPTR_T].size
|
612
|
+
SIZEOF_CONST_STRING = Fiddle::FFIBackend::FFITypes[Types::VOIDP].size
|
613
|
+
end
|
data/lib/fiddle/pack.rb
CHANGED
@@ -41,6 +41,12 @@ module Fiddle
|
|
41
41
|
when SIZEOF_LONG
|
42
42
|
PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_ULONG]
|
43
43
|
end
|
44
|
+
if RUBY_ENGINE == "jruby" and WINDOWS and [0].pack("l!").size == 8
|
45
|
+
# JRuby's 'l!' pack string doesn't use 32-bit on Windows.
|
46
|
+
# See https://github.com/jruby/jruby/issues/8357 for details
|
47
|
+
PACK_MAP[TYPE_LONG] = PACK_MAP[TYPE_INT]
|
48
|
+
PACK_MAP[TYPE_ULONG] = PACK_MAP[TYPE_UINT]
|
49
|
+
end
|
44
50
|
|
45
51
|
SIZE_MAP = {
|
46
52
|
TYPE_VOIDP => SIZEOF_VOIDP,
|
data/lib/fiddle/struct.rb
CHANGED
@@ -290,15 +290,28 @@ module Fiddle
|
|
290
290
|
# Allocates a C struct with the +types+ provided.
|
291
291
|
#
|
292
292
|
# See Fiddle::Pointer.malloc for memory management issues.
|
293
|
-
def CStructEntity.malloc(types, func = nil, size = size(types)
|
293
|
+
def CStructEntity.malloc(types, func = nil, size = size(types))
|
294
|
+
if block_given? and func.nil?
|
295
|
+
message = "a free function must be supplied to #{self}.malloc " +
|
296
|
+
"when it is called with a block"
|
297
|
+
raise ArgumentError, message
|
298
|
+
end
|
299
|
+
|
300
|
+
pointer = Pointer.malloc(size)
|
301
|
+
begin
|
302
|
+
struct = new(pointer, types, func)
|
303
|
+
rescue
|
304
|
+
pointer.free = func
|
305
|
+
pointer.call_free
|
306
|
+
raise
|
307
|
+
end
|
294
308
|
if block_given?
|
295
|
-
|
296
|
-
struct
|
297
|
-
|
309
|
+
begin
|
310
|
+
yield(struct)
|
311
|
+
ensure
|
312
|
+
struct.call_free
|
298
313
|
end
|
299
314
|
else
|
300
|
-
struct = super(size, func)
|
301
|
-
struct.set_ctypes types
|
302
315
|
struct
|
303
316
|
end
|
304
317
|
end
|
@@ -505,6 +518,14 @@ module Fiddle
|
|
505
518
|
def to_s() # :nodoc:
|
506
519
|
super(@size)
|
507
520
|
end
|
521
|
+
|
522
|
+
def +(delta)
|
523
|
+
Pointer.new(to_i + delta, @size - delta)
|
524
|
+
end
|
525
|
+
|
526
|
+
def -(delta)
|
527
|
+
Pointer.new(to_i - delta, @size + delta)
|
528
|
+
end
|
508
529
|
end
|
509
530
|
|
510
531
|
# A pointer to a C union
|
data/lib/fiddle/version.rb
CHANGED