fiddle 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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), &block)
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
- super(size, func) do |struct|
296
- struct.set_ctypes types
297
- yield struct
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
@@ -1,3 +1,3 @@
1
1
  module Fiddle
2
- VERSION = "1.1.2"
2
+ VERSION = "1.1.3"
3
3
  end