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.

Files changed (55) hide show
  1. data/README.rdoc +15 -15
  2. data/Rakefile +57 -8
  3. data/ext/ffi_c/AbstractMemory.c +101 -24
  4. data/ext/ffi_c/AbstractMemory.h +98 -6
  5. data/ext/ffi_c/ArrayType.c +129 -0
  6. data/ext/ffi_c/ArrayType.h +58 -0
  7. data/ext/ffi_c/AutoPointer.c +1 -0
  8. data/ext/ffi_c/Buffer.c +59 -43
  9. data/ext/ffi_c/Call.c +853 -0
  10. data/ext/ffi_c/Call.h +86 -0
  11. data/ext/ffi_c/ClosurePool.c +302 -0
  12. data/ext/ffi_c/ClosurePool.h +29 -0
  13. data/ext/ffi_c/DynamicLibrary.c +3 -0
  14. data/ext/ffi_c/Function.c +478 -0
  15. data/ext/ffi_c/Function.h +80 -0
  16. data/ext/ffi_c/FunctionInfo.c +221 -0
  17. data/ext/ffi_c/LastError.c +30 -6
  18. data/ext/ffi_c/MemoryPointer.c +50 -28
  19. data/ext/ffi_c/MethodHandle.c +346 -0
  20. data/ext/ffi_c/MethodHandle.h +53 -0
  21. data/ext/ffi_c/Pointer.c +73 -13
  22. data/ext/ffi_c/Pointer.h +31 -7
  23. data/ext/ffi_c/Struct.c +517 -224
  24. data/ext/ffi_c/Struct.h +60 -6
  25. data/ext/ffi_c/StructByValue.c +140 -0
  26. data/ext/ffi_c/StructByValue.h +53 -0
  27. data/ext/ffi_c/StructLayout.c +450 -0
  28. data/ext/ffi_c/Type.c +121 -22
  29. data/ext/ffi_c/Type.h +37 -8
  30. data/ext/ffi_c/Types.c +46 -61
  31. data/ext/ffi_c/Types.h +38 -7
  32. data/ext/ffi_c/Variadic.c +260 -0
  33. data/ext/ffi_c/compat.h +53 -3
  34. data/ext/ffi_c/extconf.rb +6 -7
  35. data/ext/ffi_c/ffi.c +45 -39
  36. data/ext/ffi_c/libffi.darwin.mk +2 -2
  37. data/ext/ffi_c/rbffi.h +3 -0
  38. data/lib/ffi/ffi.rb +7 -4
  39. data/lib/ffi/library.rb +34 -59
  40. data/lib/ffi/platform.rb +14 -4
  41. data/lib/ffi/struct.rb +110 -281
  42. data/lib/ffi/union.rb +4 -9
  43. data/lib/ffi/variadic.rb +1 -6
  44. data/spec/ffi/buffer_spec.rb +6 -0
  45. data/spec/ffi/callback_spec.rb +34 -3
  46. data/spec/ffi/function_spec.rb +73 -0
  47. data/spec/ffi/library_spec.rb +56 -52
  48. data/spec/ffi/pointer_spec.rb +3 -3
  49. data/spec/ffi/struct_callback_spec.rb +26 -3
  50. data/spec/ffi/struct_spec.rb +56 -3
  51. metadata +42 -11
  52. data/ext/ffi_c/Callback.c +0 -374
  53. data/ext/ffi_c/Callback.h +0 -47
  54. data/ext/ffi_c/Invoker.c +0 -962
  55. data/ext/ffi_c/NullPointer.c +0 -143
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  ruby-ffi
2
2
  by Wayne Meissner
3
- http://kenai.com/projects/ruby-ffi
3
+ http://wiki.github.com/ffi/ffi
4
4
 
5
5
  == DESCRIPTION:
6
6
 
@@ -8,7 +8,7 @@ Ruby-FFI is a ruby extension for programmatically loading dynamic
8
8
  libraries, binding functions within them, and calling those functions
9
9
  from Ruby code. Moreover, a Ruby-FFI extension works without changes
10
10
  on Ruby and JRuby. Discover why should you write your next extension
11
- using Ruby-FFI {here}[http://kenai.com/projects/ruby-ffi/pages/WhyUseFFI].
11
+ using Ruby-FFI here[http://wiki.github.com/ffi/ffi/why-use-ffi].
12
12
 
13
13
  == FEATURES/PROBLEMS:
14
14
 
@@ -32,8 +32,8 @@ using Ruby-FFI {here}[http://kenai.com/projects/ruby-ffi/pages/WhyUseFFI].
32
32
  For less minimalistic and more sane examples you may look at:
33
33
 
34
34
  * the samples/ folder
35
- * the examples on the Kenai {wiki}[http://kenai.com/projects/ruby-ffi/pages/Home]
36
- * the projects using FFI listed on this {page}[http://kenai.com/projects/ruby-ffi/pages/ProjectsUsingFFI]
35
+ * the examples on the wiki[http://wiki.github.com/ffi/ffi]
36
+ * the projects using FFI listed on this page[http://wiki.github.com/ffi/ffi/projects-using-ffi]
37
37
 
38
38
  == REQUIREMENTS:
39
39
 
@@ -45,24 +45,24 @@ From rubyforge:
45
45
 
46
46
  [sudo] gem install ffi
47
47
 
48
- or from the mercurial repository on Kenai:
48
+ or from the git repository on github:
49
49
 
50
- hg clone https://kenai.com/hg/ruby-ffi~mercurial ruby-ffi
51
- cd ruby-ffi
50
+ git clone git://github.com/ffi/ffi.git
51
+ cd ffi
52
52
  rake gem:install
53
53
 
54
54
  == CREDITS:
55
55
 
56
56
  Special thanks to:
57
57
 
58
- Yehuda Katz
59
- Luc Heinrich
60
- Andrea Fazzi
61
- Mike Dalessio
62
- Hongli Lai
63
- Evan Phoenix
64
- Aman Gupta
65
- Beoran
58
+ * Yehuda Katz
59
+ * Luc Heinrich
60
+ * Andrea Fazzi
61
+ * Mike Dalessio
62
+ * Hongli Lai
63
+ * Evan Phoenix
64
+ * Aman Gupta
65
+ * Beoran
66
66
 
67
67
  == LICENSE:
68
68
 
data/Rakefile CHANGED
@@ -23,8 +23,52 @@ rescue LoadError
23
23
  end
24
24
  end
25
25
 
26
- LIBEXT = Config::CONFIG['host_os'].downcase =~ /darwin/ ? "dylib" : "so"
27
- GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd/ ? "gmake" : "make"
26
+ LIBEXT = case Config::CONFIG['host_os'].downcase
27
+ when /darwin/
28
+ "dylib"
29
+ when /mswin|mingw/
30
+ "dll"
31
+ else
32
+ Config::CONFIG['DLEXT']
33
+ end
34
+
35
+ CPU = case Config::CONFIG['host_cpu'].downcase
36
+ when /i[3456]86/
37
+ # Darwin always reports i686, even when running in 64bit mode
38
+ if Config::CONFIG['host_os'] =~ /darwin/ && 0xfee1deadbeef.is_a?(Fixnum)
39
+ "x86_64"
40
+ else
41
+ "i386"
42
+ end
43
+ when /amd64|x86_64/
44
+ "x86_64"
45
+ when /ppc|powerpc/
46
+ "powerpc"
47
+ else
48
+ Config::CONFIG['host_cpu']
49
+ end
50
+
51
+ OS = case Config::CONFIG['host_os'].downcase
52
+ when /linux/
53
+ "linux"
54
+ when /darwin/
55
+ "darwin"
56
+ when /freebsd/
57
+ "freebsd"
58
+ when /openbsd/
59
+ "openbsd"
60
+ when /sunos|solaris/
61
+ "solaris"
62
+ when /mswin|mingw/
63
+ "win32"
64
+ else
65
+ Config::CONFIG['host_os'].downcase
66
+ end
67
+
68
+ CC=ENV['CC'] || Config::CONFIG['CC'] || "gcc"
69
+
70
+ GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd|solaris/ ? "gmake" : "make"
71
+
28
72
  LIBTEST = "build/libtest.#{LIBEXT}"
29
73
  BUILD_DIR = "build"
30
74
  BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_VERSION)
@@ -33,8 +77,8 @@ BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_
33
77
  PROJ.name = 'ffi'
34
78
  PROJ.authors = 'Wayne Meissner'
35
79
  PROJ.email = 'wmeissner@gmail.com'
36
- PROJ.url = 'http://kenai.com/projects/ruby-ffi'
37
- PROJ.version = '0.4.0'
80
+ PROJ.url = 'http://wiki.github.com/ffi/ffi'
81
+ PROJ.version = '0.5.0'
38
82
  PROJ.rubyforge.name = 'ffi'
39
83
  PROJ.readme_file = 'README.rdoc'
40
84
 
@@ -42,7 +86,7 @@ PROJ.readme_file = 'README.rdoc'
42
86
  PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
43
87
 
44
88
  PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
45
- PROJ.ann.email[:to] << 'dev@ruby-ffi.kenai.com' << 'users@ruby-ffi.kenai.com'
89
+ PROJ.ann.email[:to] << 'ruby-ffi@groups.google.com'
46
90
  PROJ.ann.email[:server] = 'smtp.gmail.com'
47
91
 
48
92
  # Gem specifications
@@ -61,9 +105,14 @@ PROJ.rdoc.opts << '-x' << 'ext'
61
105
  PROJ.ruby_opts = []
62
106
  PROJ.ruby_opts << '-I' << BUILD_EXT_DIR unless RUBY_PLATFORM == "java"
63
107
 
64
- #RSpec
108
+ # RSpec
109
+ PROJ.spec.files.exclude /rbx/
65
110
  PROJ.spec.opts << '--color' << '-fs'
66
111
 
112
+ # Dependencies
113
+
114
+ depend_on 'rake', '>=0.8.7'
115
+
67
116
  TEST_DEPS = [ LIBTEST ]
68
117
  if RUBY_PLATFORM == "java"
69
118
  desc "Run all specs"
@@ -98,7 +147,7 @@ task :install => 'gem:install'
98
147
  desc "Clean all built files"
99
148
  task :distclean => :clobber do
100
149
  FileUtils.rm_rf('build')
101
- FileUtils.rm_rf(Dir['lib/**/ffi_c.so'])
150
+ FileUtils.rm_rf(Dir["lib/**/ffi_c.#{Config::CONFIG['DLEXT']}"])
102
151
  FileUtils.rm_rf('lib/1.8')
103
152
  FileUtils.rm_rf('lib/1.9')
104
153
  FileUtils.rm_rf('conftest.dSYM')
@@ -108,7 +157,7 @@ end
108
157
 
109
158
  desc "Build the native test lib"
110
159
  task "build/libtest.#{LIBEXT}" do
111
- sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{Config::CONFIG['host_cpu']}}
160
+ sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{CPU} OS=#{OS} }
112
161
  end
113
162
 
114
163
 
@@ -1,3 +1,31 @@
1
+ /*
2
+ * Copyright (c) 2008, 2009, Wayne Meissner
3
+ *
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
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
+ * * The name of the author or authors may not be used to endorse or promote
15
+ * products derived from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
1
29
  #include <sys/types.h>
2
30
  #include <sys/param.h>
3
31
  #include <stdint.h>
@@ -7,13 +35,13 @@
7
35
  #include "compat.h"
8
36
  #include "AbstractMemory.h"
9
37
  #include "Pointer.h"
10
- #include "Callback.h"
38
+ #include "Function.h"
11
39
 
12
40
 
13
41
  static inline char* memory_address(VALUE self);
14
42
  VALUE rbffi_AbstractMemoryClass = Qnil;
15
- static ID id_to_ptr = 0;
16
- static ID id_call = 0;
43
+ static VALUE NullPointerErrorClass = Qnil;
44
+ static ID id_to_ptr = 0, id_plus = 0, id_call = 0;
17
45
 
18
46
  static VALUE
19
47
  memory_allocate(VALUE klass)
@@ -22,6 +50,7 @@ memory_allocate(VALUE klass)
22
50
  VALUE obj;
23
51
  obj = Data_Make_Struct(klass, AbstractMemory, NULL, -1, memory);
24
52
  memory->ops = &rbffi_AbstractMemoryOps;
53
+ memory->access = MEM_RD | MEM_WR;
25
54
 
26
55
  return obj;
27
56
  }
@@ -32,6 +61,7 @@ static void \
32
61
  memory_op_put_##name(AbstractMemory* memory, long off, VALUE value) \
33
62
  { \
34
63
  type tmp = (type) toNative(value); \
64
+ checkWrite(memory); \
35
65
  checkBounds(memory, off, sizeof(type)); \
36
66
  memcpy(memory->address + off, &tmp, sizeof(tmp)); \
37
67
  } \
@@ -49,6 +79,7 @@ static VALUE \
49
79
  memory_op_get_##name(AbstractMemory* memory, long off) \
50
80
  { \
51
81
  type tmp; \
82
+ checkRead(memory); \
52
83
  checkBounds(memory, off, sizeof(type)); \
53
84
  memcpy(&tmp, memory->address + off, sizeof(tmp)); \
54
85
  return fromNative(tmp); \
@@ -71,6 +102,7 @@ memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary) \
71
102
  long off = NUM2LONG(offset); \
72
103
  AbstractMemory* memory = MEMORY(self); \
73
104
  long i; \
105
+ checkWrite(memory); \
74
106
  checkBounds(memory, off, count * sizeof(type)); \
75
107
  for (i = 0; i < count; i++) { \
76
108
  type tmp = (type) toNative(RARRAY_PTR(ary)[i]); \
@@ -86,6 +118,7 @@ memory_get_array_of_##name(VALUE self, VALUE offset, VALUE length) \
86
118
  long off = NUM2LONG(offset); \
87
119
  AbstractMemory* memory = MEMORY(self); \
88
120
  long i; \
121
+ checkRead(memory); \
89
122
  checkBounds(memory, off, count * sizeof(type)); \
90
123
  VALUE retVal = rb_ary_new2(count); \
91
124
  for (i = 0; i < count; ++i) { \
@@ -128,24 +161,6 @@ get_pointer_value(VALUE value)
128
161
 
129
162
  NUM_OP(pointer, void *, get_pointer_value, rbffi_Pointer_NewInstance);
130
163
 
131
- static VALUE
132
- memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
133
- {
134
- AbstractMemory* memory = MEMORY(self);
135
- long off = NUM2LONG(offset);
136
- checkBounds(memory, off, sizeof(void *));
137
-
138
- if (rb_obj_is_kind_of(proc, rb_cProc) || rb_respond_to(proc, id_call)) {
139
- VALUE callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
140
- void* code = ((NativeCallback *) DATA_PTR(callback))->code;
141
- memcpy(memory->address + off, &code, sizeof(code));
142
- } else {
143
- rb_raise(rb_eArgError, "parameter is not a proc");
144
- }
145
-
146
- return self;
147
- }
148
-
149
164
  static VALUE
150
165
  memory_clear(VALUE self)
151
166
  {
@@ -157,7 +172,11 @@ memory_clear(VALUE self)
157
172
  static VALUE
158
173
  memory_size(VALUE self)
159
174
  {
160
- return LONG2FIX((MEMORY(self))->size);
175
+ AbstractMemory* ptr;
176
+
177
+ Data_Get_Struct(self, AbstractMemory, ptr);
178
+
179
+ return LONG2NUM(ptr->size);
161
180
  }
162
181
 
163
182
  static VALUE
@@ -171,7 +190,9 @@ memory_get_string(int argc, VALUE* argv, VALUE self)
171
190
 
172
191
  off = NUM2LONG(offset);
173
192
  len = nargs > 1 && length != Qnil ? NUM2LONG(length) : (ptr->size - off);
193
+ checkRead(ptr);
174
194
  checkBounds(ptr, off, len);
195
+
175
196
  end = memchr(ptr->address + off, 0, len);
176
197
  return rb_tainted_str_new((char *) ptr->address + off,
177
198
  (end != NULL ? end - ptr->address - off : len));
@@ -191,6 +212,7 @@ memory_get_array_of_string(int argc, VALUE* argv, VALUE self)
191
212
  retVal = rb_ary_new2(count);
192
213
 
193
214
  Data_Get_Struct(self, AbstractMemory, ptr);
215
+ checkRead(ptr);
194
216
 
195
217
  if (countnum != Qnil) {
196
218
  int i;
@@ -226,12 +248,16 @@ memory_put_string(VALUE self, VALUE offset, VALUE str)
226
248
  off = NUM2LONG(offset);
227
249
  len = RSTRING_LEN(str);
228
250
 
251
+ checkWrite(ptr);
229
252
  checkBounds(ptr, off, len + 1);
253
+
230
254
  if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
231
255
  rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
232
256
  }
257
+
233
258
  memcpy(ptr->address + off, RSTRING_PTR(str), len);
234
259
  *((char *) ptr->address + off + len) = '\0';
260
+
235
261
  return self;
236
262
  }
237
263
 
@@ -243,7 +269,10 @@ memory_get_bytes(VALUE self, VALUE offset, VALUE length)
243
269
 
244
270
  off = NUM2LONG(offset);
245
271
  len = NUM2LONG(length);
272
+
273
+ checkRead(ptr);
246
274
  checkBounds(ptr, off, len);
275
+
247
276
  return rb_tainted_str_new((char *) ptr->address + off, len);
248
277
  }
249
278
 
@@ -266,14 +295,41 @@ memory_put_bytes(int argc, VALUE* argv, VALUE self)
266
295
  if ((idx + len) > RSTRING_LEN(str)) {
267
296
  rb_raise(rb_eRangeError, "index+length is greater than size of string");
268
297
  }
298
+
299
+ checkWrite(ptr);
269
300
  checkBounds(ptr, off, len);
301
+
270
302
  if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
271
303
  rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
272
304
  }
273
305
  memcpy(ptr->address + off, RSTRING_PTR(str) + idx, len);
306
+
274
307
  return self;
275
308
  }
276
309
 
310
+ static VALUE
311
+ memory_type_size(VALUE self)
312
+ {
313
+ AbstractMemory* ptr;
314
+
315
+ Data_Get_Struct(self, AbstractMemory, ptr);
316
+
317
+ return INT2NUM(ptr->typeSize);
318
+ }
319
+
320
+ static VALUE
321
+ memory_aref(VALUE self, VALUE idx)
322
+ {
323
+ AbstractMemory* ptr;
324
+ VALUE rbOffset = Qnil;
325
+
326
+ Data_Get_Struct(self, AbstractMemory, ptr);
327
+
328
+ rbOffset = ULONG2NUM(NUM2ULONG(idx) * ptr->typeSize);
329
+
330
+ return rb_funcall2(self, id_plus, 1, &rbOffset);
331
+ }
332
+
277
333
  static inline char*
278
334
  memory_address(VALUE obj)
279
335
  {
@@ -293,12 +349,26 @@ rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass)
293
349
  return NULL;
294
350
  }
295
351
 
352
+ void
353
+ rbffi_AbstractMemory_Error(AbstractMemory *mem, int op)
354
+ {
355
+ VALUE rbErrorClass = mem->address == NULL ? NullPointerErrorClass : rb_eRuntimeError;
356
+ if (op == MEM_RD) {
357
+ rb_raise(rbErrorClass, "invalid memory read at address=%p", mem->address);
358
+ } else if (op == MEM_WR) {
359
+ rb_raise(rbErrorClass, "invalid memory write at address=%p", mem->address);
360
+ } else {
361
+ rb_raise(rbErrorClass, "invalid memory access at address=%p", mem->address);
362
+ }
363
+ }
364
+
296
365
  static VALUE
297
366
  memory_op_get_strptr(AbstractMemory* ptr, long offset)
298
367
  {
299
368
  void* tmp = NULL;
300
369
 
301
370
  if (ptr != NULL && ptr->address != NULL) {
371
+ checkRead(ptr);
302
372
  checkBounds(ptr, offset, sizeof(tmp));
303
373
  memcpy(&tmp, ptr->address + offset, sizeof(tmp));
304
374
  }
@@ -337,8 +407,12 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
337
407
  VALUE classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
338
408
  rbffi_AbstractMemoryClass = classMemory;
339
409
  rb_global_variable(&rbffi_AbstractMemoryClass);
340
-
341
410
  rb_define_alloc_func(classMemory, memory_allocate);
411
+
412
+ NullPointerErrorClass = rb_define_class_under(moduleFFI, "NullPointerError", rb_eRuntimeError);
413
+ rb_global_variable(&NullPointerErrorClass);
414
+
415
+
342
416
  #undef INT
343
417
  #define INT(type) \
344
418
  rb_define_method(classMemory, "put_" #type, memory_put_##type, 2); \
@@ -396,7 +470,6 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
396
470
  rb_define_method(classMemory, "get_pointer", memory_get_pointer, 1);
397
471
  rb_define_method(classMemory, "put_array_of_pointer", memory_put_array_of_pointer, 2);
398
472
  rb_define_method(classMemory, "get_array_of_pointer", memory_get_array_of_pointer, 2);
399
- rb_define_method(classMemory, "put_callback", memory_put_callback, 3);
400
473
  rb_define_method(classMemory, "get_string", memory_get_string, -1);
401
474
  rb_define_method(classMemory, "put_string", memory_put_string, 2);
402
475
  rb_define_method(classMemory, "get_bytes", memory_get_bytes, 2);
@@ -405,8 +478,12 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
405
478
 
406
479
  rb_define_method(classMemory, "clear", memory_clear, 0);
407
480
  rb_define_method(classMemory, "total", memory_size, 0);
481
+ rb_define_alias(classMemory, "size", "total");
482
+ rb_define_method(classMemory, "type_size", memory_type_size, 0);
483
+ rb_define_method(classMemory, "[]", memory_aref, 1);
408
484
 
409
485
  id_to_ptr = rb_intern("to_ptr");
410
486
  id_call = rb_intern("call");
487
+ id_plus = rb_intern("+");
411
488
  }
412
489
 
@@ -1,16 +1,50 @@
1
- #ifndef _ABSTRACTMEMORY_H
2
- #define _ABSTRACTMEMORY_H
1
+ /*
2
+ * Copyright (c) 2008, 2009, Wayne Meissner
3
+ *
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
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
+ * * The name of the author or authors may not be used to endorse or promote
15
+ * products derived from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #ifndef RBFFI_ABSTRACTMEMORY_H
30
+ #define RBFFI_ABSTRACTMEMORY_H
3
31
 
4
32
  #include <sys/param.h>
5
33
  #include <sys/types.h>
6
34
  #include <stdint.h>
7
35
 
8
36
  #include "compat.h"
37
+ #include "Types.h"
9
38
 
10
39
  #ifdef __cplusplus
11
40
  extern "C" {
12
41
  #endif
13
42
 
43
+
44
+ #define MEM_RD 0x01
45
+ #define MEM_WR 0x02
46
+ #define MEM_CODE 0x04
47
+
14
48
  typedef struct AbstractMemory_ AbstractMemory;
15
49
 
16
50
  typedef struct {
@@ -36,33 +70,91 @@ typedef struct {
36
70
  struct AbstractMemory_ {
37
71
  char* address; // Use char* instead of void* to ensure adding to it works correctly
38
72
  long size;
73
+ int access;
74
+ int typeSize;
39
75
  MemoryOps* ops;
40
76
  };
41
77
 
78
+ extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
79
+
80
+ extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
81
+
82
+ extern void rbffi_AbstractMemory_Error(AbstractMemory *, int op);
42
83
 
43
84
  static inline void
44
85
  checkBounds(AbstractMemory* mem, long off, long len)
45
86
  {
46
- if ((off | len | (off + len) | (mem->size - (off + len))) < 0) {
87
+ if (unlikely((off | len | (off + len) | (mem->size - (off + len))) < 0)) {
47
88
  rb_raise(rb_eIndexError, "Memory access offset=%ld size=%ld is out of bounds",
48
89
  off, len);
49
90
  }
50
91
  }
51
92
 
93
+ static inline void
94
+ checkRead(AbstractMemory* mem)
95
+ {
96
+ if (unlikely((mem->access & MEM_RD) == 0)) {
97
+ rbffi_AbstractMemory_Error(mem, MEM_RD);
98
+ }
99
+ }
100
+
101
+ static inline void
102
+ checkWrite(AbstractMemory* mem)
103
+ {
104
+ if (unlikely((mem->access & MEM_WR) == 0)) {
105
+ rbffi_AbstractMemory_Error(mem, MEM_WR);
106
+ }
107
+ }
108
+
109
+ static inline MemoryOp*
110
+ memory_get_op(AbstractMemory* ptr, Type* type)
111
+ {
112
+ if (ptr == NULL || ptr->ops == NULL || type == NULL) {
113
+ return NULL;
114
+ }
115
+ switch (type->nativeType) {
116
+ case NATIVE_INT8:
117
+ return ptr->ops->int8;
118
+ case NATIVE_UINT8:
119
+ return ptr->ops->uint8;
120
+ case NATIVE_INT16:
121
+ return ptr->ops->int16;
122
+ case NATIVE_UINT16:
123
+ return ptr->ops->uint16;
124
+ case NATIVE_INT32:
125
+ return ptr->ops->int32;
126
+ case NATIVE_UINT32:
127
+ return ptr->ops->uint32;
128
+ case NATIVE_INT64:
129
+ return ptr->ops->int64;
130
+ case NATIVE_UINT64:
131
+ return ptr->ops->uint64;
132
+ case NATIVE_FLOAT32:
133
+ return ptr->ops->float32;
134
+ case NATIVE_FLOAT64:
135
+ return ptr->ops->float64;
136
+ case NATIVE_POINTER:
137
+ return ptr->ops->pointer;
138
+ case NATIVE_STRING:
139
+ return ptr->ops->strptr;
140
+ default:
141
+ return NULL;
142
+ }
143
+ }
144
+
52
145
  #define MEMORY(obj) rbffi_AbstractMemory_Cast((obj), rbffi_AbstractMemoryClass)
53
146
  #define MEMORY_PTR(obj) MEMORY((obj))->address
54
147
  #define MEMORY_LEN(obj) MEMORY((obj))->size
55
148
 
56
- extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
57
149
 
58
- extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
59
150
 
60
151
  extern VALUE rbffi_AbstractMemoryClass;
61
152
  extern MemoryOps rbffi_AbstractMemoryOps;
62
153
 
154
+
63
155
  #ifdef __cplusplus
64
156
  }
65
157
  #endif
66
158
 
67
- #endif /* _ABSTRACTMEMORY_H */
159
+ #endif /* RBFFI_ABSTRACTMEMORY_H */
68
160