ffi 0.3.0 → 0.4.0

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.
Files changed (76) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +47 -28
  3. data/ext/ffi_c/AbstractMemory.c +149 -65
  4. data/ext/ffi_c/AbstractMemory.h +34 -4
  5. data/ext/ffi_c/AutoPointer.c +15 -18
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +79 -44
  8. data/ext/ffi_c/Callback.c +133 -62
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +88 -24
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +154 -190
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +30 -20
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +67 -28
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +67 -30
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +202 -267
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +48 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +21 -44
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/gen/Rakefile +12 -0
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +79 -18
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/lib/ffi.rb +10 -1
  47. data/spec/ffi/bool_spec.rb +24 -0
  48. data/spec/ffi/callback_spec.rb +217 -17
  49. data/spec/ffi/enum_spec.rb +164 -0
  50. data/spec/ffi/managed_struct_spec.rb +6 -1
  51. data/spec/ffi/number_spec.rb +30 -0
  52. data/spec/ffi/pointer_spec.rb +33 -8
  53. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  54. data/spec/ffi/spec_helper.rb +5 -1
  55. data/spec/ffi/string_spec.rb +65 -4
  56. data/spec/ffi/struct_callback_spec.rb +41 -0
  57. data/spec/ffi/struct_initialize_spec.rb +30 -0
  58. data/spec/ffi/struct_spec.rb +44 -21
  59. metadata +31 -69
  60. data/ext/ffi_c/ffi.mk +0 -23
  61. data/nbproject/Makefile-Default.mk +0 -57
  62. data/nbproject/Makefile-impl.mk +0 -123
  63. data/nbproject/Package-Default.bash +0 -72
  64. data/nbproject/configurations.xml +0 -293
  65. data/nbproject/private/configurations.xml +0 -22
  66. data/nbproject/private/private.xml +0 -7
  67. data/nbproject/project.properties +0 -0
  68. data/nbproject/project.xml +0 -15
  69. data/samples/getlogin.rb +0 -7
  70. data/samples/getpid.rb +0 -7
  71. data/samples/gettimeofday.rb +0 -17
  72. data/samples/hello.rb +0 -6
  73. data/samples/inotify.rb +0 -59
  74. data/samples/pty.rb +0 -75
  75. data/samples/qsort.rb +0 -20
  76. data/samples/sample_helper.rb +0 -6
data/README.rdoc CHANGED
@@ -4,16 +4,66 @@ ruby-ffi
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- A Ruby foreign function interface
7
+ Ruby-FFI is a ruby extension for programmatically loading dynamic
8
+ libraries, binding functions within them, and calling those functions
9
+ from Ruby code. Moreover, a Ruby-FFI extension works without changes
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].
8
12
 
9
13
  == FEATURES/PROBLEMS:
10
14
 
15
+ * It has a very intuitive DSL
16
+ * It supports all C native types
17
+ * It supports C structs (also nested), enums and global variables
18
+ * It supports callbacks
19
+ * It has smart methods to handle memory management of pointers and structs
20
+
11
21
  == SYNOPSIS:
12
22
 
23
+ require 'ffi'
24
+
25
+ module MyLib
26
+ extend FFI::Library
27
+ attach_function :puts, [ :string ], :int
28
+ end
29
+
30
+ MyLib.puts 'Hello boys using libc!'
31
+
32
+ For less minimalistic and more sane examples you may look at:
33
+
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]
37
+
13
38
  == REQUIREMENTS:
14
39
 
40
+ * You need a sane building environment in order to compile the extension.
41
+
15
42
  == DOWNLOAD/INSTALL:
16
43
 
44
+ From rubyforge:
45
+
46
+ [sudo] gem install ffi
47
+
48
+ or from the mercurial repository on Kenai:
49
+
50
+ hg clone https://kenai.com/hg/ruby-ffi~mercurial ruby-ffi
51
+ cd ruby-ffi
52
+ rake gem:install
53
+
54
+ == CREDITS:
55
+
56
+ Special thanks to:
57
+
58
+ Yehuda Katz
59
+ Luc Heinrich
60
+ Andrea Fazzi
61
+ Mike Dalessio
62
+ Hongli Lai
63
+ Evan Phoenix
64
+ Aman Gupta
65
+ Beoran
66
+
17
67
  == LICENSE:
18
68
 
19
69
  See LICENSE file.
data/Rakefile CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'rubygems'
2
+ require 'rbconfig'
2
3
 
3
- USE_RAKE_COMPILER = (RUBY_VERSION =~ /1\.9.*/ || RUBY_PLATFORM =~ /java/) ? false : true
4
+ USE_RAKE_COMPILER = (RUBY_PLATFORM =~ /java/) ? false : true
4
5
  if USE_RAKE_COMPILER
5
- gem 'rake-compiler', '>=0.3.0'
6
+ gem 'rake-compiler', '>=0.6.0'
6
7
  require 'rake/extensiontask'
8
+ ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
7
9
  end
8
10
 
9
11
  require 'date'
@@ -24,34 +26,44 @@ end
24
26
  LIBEXT = Config::CONFIG['host_os'].downcase =~ /darwin/ ? "dylib" : "so"
25
27
  GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd/ ? "gmake" : "make"
26
28
  LIBTEST = "build/libtest.#{LIBEXT}"
27
- BUILD_DIR = "build/#{RUBY_VERSION}"
29
+ BUILD_DIR = "build"
30
+ BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_VERSION)
28
31
 
29
32
  # Project general information
30
33
  PROJ.name = 'ffi'
31
34
  PROJ.authors = 'Wayne Meissner'
32
35
  PROJ.email = 'wmeissner@gmail.com'
33
36
  PROJ.url = 'http://kenai.com/projects/ruby-ffi'
34
- PROJ.version = '0.3.0'
37
+ PROJ.version = '0.4.0'
35
38
  PROJ.rubyforge.name = 'ffi'
36
-
37
39
  PROJ.readme_file = 'README.rdoc'
38
40
 
39
41
  # Annoucement
40
- PROJ.ann.paragraphs
41
- PROJ.ann.email[:from] = 'wmeissner@gmail.com'
42
+ PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
43
+
44
+ PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
42
45
  PROJ.ann.email[:to] << 'dev@ruby-ffi.kenai.com' << 'users@ruby-ffi.kenai.com'
43
46
  PROJ.ann.email[:server] = 'smtp.gmail.com'
44
47
 
45
48
  # Gem specifications
46
49
  PROJ.gem.need_tar = false
47
- PROJ.gem.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{ext,lib,nbproject,samples,spec}/**/*")
50
+ PROJ.gem.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{ext,gen,lib,spec}/**/*")
48
51
  PROJ.gem.platform = Gem::Platform::RUBY
49
- PROJ.gem.extensions = %w(ext/ffi_c/extconf.rb gen/Rakefile)
52
+
53
+ # Override Mr. Bones autogenerated extensions and force ours in
54
+ PROJ.gem.extras['extensions'] = %w(ext/ffi_c/extconf.rb gen/Rakefile)
50
55
 
51
56
  # RDoc
52
57
  PROJ.rdoc.exclude << '^ext\/'
53
58
  PROJ.rdoc.opts << '-x' << 'ext'
54
59
 
60
+ # Ruby
61
+ PROJ.ruby_opts = []
62
+ PROJ.ruby_opts << '-I' << BUILD_EXT_DIR unless RUBY_PLATFORM == "java"
63
+
64
+ #RSpec
65
+ PROJ.spec.opts << '--color' << '-fs'
66
+
55
67
  TEST_DEPS = [ LIBTEST ]
56
68
  if RUBY_PLATFORM == "java"
57
69
  desc "Run all specs"
@@ -67,12 +79,12 @@ else
67
79
  desc "Run all specs"
68
80
  task :specs => TEST_DEPS do
69
81
  ENV["MRI_FFI"] = "1"
70
- sh %{#{Gem.ruby} -Ilib -I#{BUILD_DIR} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
82
+ sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
71
83
  end
72
84
  desc "Run rubinius specs"
73
85
  task :rbxspecs => TEST_DEPS do
74
86
  ENV["MRI_FFI"] = "1"
75
- sh %{#{Gem.ruby} -Ilib -I#{BUILD_DIR} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
87
+ sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
76
88
  end
77
89
  end
78
90
 
@@ -82,30 +94,31 @@ task :package => 'gem:package'
82
94
  desc "Install the gem locally"
83
95
  task :install => 'gem:install'
84
96
 
85
- unless USE_RAKE_COMPILER
86
- file "#{BUILD_DIR}/Makefile" do
87
- FileUtils.mkdir_p(BUILD_DIR) unless File.directory?(BUILD_DIR)
88
- sh %{cd "#{BUILD_DIR}" && #{Gem.ruby} #{Dir.pwd}/ext/ffi_c/extconf.rb}
89
- end
90
- desc "Compile the native module"
91
- task :compile => "#{BUILD_DIR}/Makefile" do
92
- sh %{cd "#{BUILD_DIR}"; make}
93
- end
94
- end
97
+
95
98
  desc "Clean all built files"
96
- task :clean do
97
- FileUtils.rm_rf("build")
98
- FileUtils.rm_rf("conftest.dSYM")
99
- FileUtils.rm_f(Dir["pkg/*.gem"])
99
+ task :distclean => :clobber do
100
+ FileUtils.rm_rf('build')
101
+ FileUtils.rm_rf(Dir['lib/**/ffi_c.so'])
102
+ FileUtils.rm_rf('lib/1.8')
103
+ FileUtils.rm_rf('lib/1.9')
104
+ FileUtils.rm_rf('conftest.dSYM')
105
+ FileUtils.rm_rf('pkg')
100
106
  end
107
+
108
+
109
+ desc "Build the native test lib"
101
110
  task "build/libtest.#{LIBEXT}" do
102
- sh %{#{GMAKE} -f libtest/GNUmakefile}
111
+ sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{Config::CONFIG['host_cpu']}}
103
112
  end
113
+
114
+
104
115
  desc "Build test helper lib"
105
116
  task :libtest => "build/libtest.#{LIBEXT}"
117
+
106
118
  desc "Test the extension"
107
- task :test => [ :specs, :rbxspecs ] do
108
- end
119
+ task :test => [ :specs, :rbxspecs ]
120
+
121
+
109
122
  namespace :bench do
110
123
  ITER = ENV['ITER'] ? ENV['ITER'].to_i : 100000
111
124
  bench_libs = "-Ilib -I#{BUILD_DIR}" unless RUBY_PLATFORM == "java"
@@ -121,3 +134,9 @@ namespace :bench do
121
134
  end
122
135
  end
123
136
  end
137
+
138
+ task 'spec:run' => TEST_DEPS
139
+ task 'spec:specdoc' => TEST_DEPS
140
+
141
+ task :default => :specs
142
+
@@ -9,41 +9,60 @@
9
9
  #include "Pointer.h"
10
10
  #include "Callback.h"
11
11
 
12
- static VALUE memory_put_float32(VALUE self, VALUE offset, VALUE value);
13
- static VALUE memory_get_float32(VALUE self, VALUE offset);
14
- static VALUE memory_put_float64(VALUE self, VALUE offset, VALUE value);
15
- static VALUE memory_get_float64(VALUE self, VALUE offset);
16
- static VALUE memory_put_pointer(VALUE self, VALUE offset, VALUE value);
17
- static VALUE memory_get_pointer(VALUE self, VALUE offset);
18
12
 
19
13
  static inline char* memory_address(VALUE self);
20
- VALUE rb_FFI_AbstractMemory_class = Qnil;
21
- static VALUE classMemory = Qnil;
22
- static ID to_ptr = 0;
14
+ VALUE rbffi_AbstractMemoryClass = Qnil;
15
+ static ID id_to_ptr = 0;
16
+ static ID id_call = 0;
17
+
18
+ static VALUE
19
+ memory_allocate(VALUE klass)
20
+ {
21
+ AbstractMemory* memory;
22
+ VALUE obj;
23
+ obj = Data_Make_Struct(klass, AbstractMemory, NULL, -1, memory);
24
+ memory->ops = &rbffi_AbstractMemoryOps;
25
+
26
+ return obj;
27
+ }
23
28
 
24
29
  #define NUM_OP(name, type, toNative, fromNative) \
25
- static VALUE memory_put_##name(VALUE self, VALUE offset, VALUE value); \
26
- static VALUE \
27
- memory_put_##name(VALUE self, VALUE offset, VALUE value) \
30
+ static void memory_op_put_##name(AbstractMemory* memory, long off, VALUE value); \
31
+ static void \
32
+ memory_op_put_##name(AbstractMemory* memory, long off, VALUE value) \
28
33
  { \
29
- long off = NUM2LONG(offset); \
30
- AbstractMemory* memory = MEMORY(self); \
31
34
  type tmp = (type) toNative(value); \
32
35
  checkBounds(memory, off, sizeof(type)); \
33
36
  memcpy(memory->address + off, &tmp, sizeof(tmp)); \
37
+ } \
38
+ static VALUE memory_put_##name(VALUE self, VALUE offset, VALUE value); \
39
+ static VALUE \
40
+ memory_put_##name(VALUE self, VALUE offset, VALUE value) \
41
+ { \
42
+ AbstractMemory* memory; \
43
+ Data_Get_Struct(self, AbstractMemory, memory); \
44
+ memory_op_put_##name(memory, NUM2LONG(offset), value); \
34
45
  return self; \
35
46
  } \
36
- static VALUE memory_get_##name(VALUE self, VALUE offset); \
47
+ static VALUE memory_op_get_##name(AbstractMemory* memory, long off); \
37
48
  static VALUE \
38
- memory_get_##name(VALUE self, VALUE offset) \
49
+ memory_op_get_##name(AbstractMemory* memory, long off) \
39
50
  { \
40
- long off = NUM2LONG(offset); \
41
- AbstractMemory* memory = MEMORY(self); \
42
51
  type tmp; \
43
52
  checkBounds(memory, off, sizeof(type)); \
44
53
  memcpy(&tmp, memory->address + off, sizeof(tmp)); \
45
54
  return fromNative(tmp); \
46
55
  } \
56
+ static VALUE memory_get_##name(VALUE self, VALUE offset); \
57
+ static VALUE \
58
+ memory_get_##name(VALUE self, VALUE offset) \
59
+ { \
60
+ AbstractMemory* memory; \
61
+ Data_Get_Struct(self, AbstractMemory, memory); \
62
+ return memory_op_get_##name(memory, NUM2LONG(offset)); \
63
+ } \
64
+ static MemoryOp memory_op_##name = { memory_op_get_##name, memory_op_put_##name }; \
65
+ \
47
66
  static VALUE memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary); \
48
67
  static VALUE \
49
68
  memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary) \
@@ -88,46 +107,26 @@ NUM_OP(uint64, uint64_t, NUM2ULL, ULL2NUM);
88
107
  NUM_OP(float32, float, NUM2DBL, rb_float_new);
89
108
  NUM_OP(float64, double, NUM2DBL, rb_float_new);
90
109
 
91
- static VALUE
92
- memory_put_pointer(VALUE self, VALUE offset, VALUE value)
93
- {
94
- AbstractMemory* memory = MEMORY(self);
95
- long off = NUM2LONG(offset);
110
+ static inline void*
111
+ get_pointer_value(VALUE value)
112
+ {
96
113
  const int type = TYPE(value);
97
- checkBounds(memory, off, sizeof(void *));
98
-
99
- if (rb_obj_is_kind_of(value, rb_FFI_Pointer_class) && type == T_DATA) {
100
- void* tmp = memory_address(value);
101
- memcpy(memory->address + off, &tmp, sizeof(tmp));
114
+ if (type == T_DATA && rb_obj_is_kind_of(value, rbffi_PointerClass)) {
115
+ return memory_address(value);
102
116
  } else if (type == T_NIL) {
103
- void* tmp = NULL;
104
- memcpy(memory->address + off, &tmp, sizeof(tmp));
117
+ return NULL;
105
118
  } else if (type == T_FIXNUM) {
106
- uintptr_t tmp = (uintptr_t) FIX2INT(value);
107
- memcpy(memory->address + off, &tmp, sizeof(tmp));
119
+ return (void *) (uintptr_t) FIX2INT(value);
108
120
  } else if (type == T_BIGNUM) {
109
- uintptr_t tmp = (uintptr_t) NUM2ULL(value);
110
- memcpy(memory->address + off, &tmp, sizeof(tmp));
111
- } else if (rb_respond_to(value, to_ptr)) {
112
- VALUE ptr = rb_funcall2(value, to_ptr, 0, NULL);
113
- void* tmp = MEMORY_PTR(ptr);
114
- memcpy(memory->address + off, &tmp, sizeof(tmp));
121
+ return (void *) (uintptr_t) NUM2ULL(value);
122
+ } else if (rb_respond_to(value, id_to_ptr)) {
123
+ return MEMORY_PTR(rb_funcall2(value, id_to_ptr, 0, NULL));
115
124
  } else {
116
125
  rb_raise(rb_eArgError, "value is not a pointer");
117
126
  }
118
- return self;
119
127
  }
120
128
 
121
- static VALUE
122
- memory_get_pointer(VALUE self, VALUE offset)
123
- {
124
- AbstractMemory* memory = MEMORY(self);
125
- long off = NUM2LONG(offset);
126
- void* tmp;
127
- checkBounds(memory, off, sizeof(tmp));
128
- memcpy(&tmp, memory->address + off, sizeof(tmp));
129
- return rb_FFI_Pointer_new(tmp);
130
- }
129
+ NUM_OP(pointer, void *, get_pointer_value, rbffi_Pointer_NewInstance);
131
130
 
132
131
  static VALUE
133
132
  memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
@@ -136,8 +135,8 @@ memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
136
135
  long off = NUM2LONG(offset);
137
136
  checkBounds(memory, off, sizeof(void *));
138
137
 
139
- if (rb_obj_is_kind_of(proc, rb_cProc)) {
140
- VALUE callback = rb_FFI_NativeCallback_for_proc(proc, cbInfo);
138
+ if (rb_obj_is_kind_of(proc, rb_cProc) || rb_respond_to(proc, id_call)) {
139
+ VALUE callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
141
140
  void* code = ((NativeCallback *) DATA_PTR(callback))->code;
142
141
  memcpy(memory->address + off, &code, sizeof(code));
143
142
  } else {
@@ -178,15 +177,56 @@ memory_get_string(int argc, VALUE* argv, VALUE self)
178
177
  (end != NULL ? end - ptr->address - off : len));
179
178
  }
180
179
 
180
+ static VALUE
181
+ memory_get_array_of_string(int argc, VALUE* argv, VALUE self)
182
+ {
183
+ VALUE offset = Qnil, countnum = Qnil, retVal = Qnil;
184
+ AbstractMemory* ptr;
185
+ long off;
186
+ int count;
187
+
188
+ rb_scan_args(argc, argv, "11", &offset, &countnum);
189
+ off = NUM2LONG(offset);
190
+ count = (countnum == Qnil ? 0 : NUM2INT(countnum));
191
+ retVal = rb_ary_new2(count);
192
+
193
+ Data_Get_Struct(self, AbstractMemory, ptr);
194
+
195
+ if (countnum != Qnil) {
196
+ int i;
197
+
198
+ checkBounds(ptr, off, count * sizeof (char*));
199
+
200
+ for (i = 0; i < count; ++i) {
201
+ const char* strptr = *((const char**) (ptr->address + off) + i);
202
+ rb_ary_push(retVal, (strptr == NULL ? Qnil : rb_tainted_str_new2(strptr)));
203
+ }
204
+
205
+ } else {
206
+ checkBounds(ptr, off, sizeof (char*));
207
+ for ( ; off < ptr->size - sizeof (void *); off += sizeof (void *)) {
208
+ const char* strptr = *(const char**) (ptr->address + off);
209
+ if (strptr == NULL) {
210
+ break;
211
+ }
212
+ rb_ary_push(retVal, rb_tainted_str_new2(strptr));
213
+ }
214
+ }
215
+
216
+ return retVal;
217
+ }
218
+
181
219
  static VALUE
182
220
  memory_put_string(VALUE self, VALUE offset, VALUE str)
183
221
  {
184
222
  AbstractMemory* ptr = MEMORY(self);
185
223
  long off, len;
186
224
 
225
+ Check_Type(str, T_STRING);
187
226
  off = NUM2LONG(offset);
188
227
  len = RSTRING_LEN(str);
189
- checkBounds(ptr, off, len);
228
+
229
+ checkBounds(ptr, off, len + 1);
190
230
  if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
191
231
  rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
192
232
  }
@@ -215,6 +255,8 @@ memory_put_bytes(int argc, VALUE* argv, VALUE self)
215
255
  long off, len, idx;
216
256
  int nargs = rb_scan_args(argc, argv, "22", &offset, &str, &rbIndex, &rbLength);
217
257
 
258
+ Check_Type(str, T_STRING);
259
+
218
260
  off = NUM2LONG(offset);
219
261
  idx = nargs > 2 ? NUM2LONG(rbIndex) : 0;
220
262
  if (idx < 0) {
@@ -239,21 +281,64 @@ memory_address(VALUE obj)
239
281
  }
240
282
 
241
283
  AbstractMemory*
242
- rb_FFI_AbstractMemory_cast(VALUE obj, VALUE klass)
284
+ rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass)
243
285
  {
244
286
  if (rb_obj_is_kind_of(obj, klass)) {
245
287
  AbstractMemory* memory;
246
288
  Data_Get_Struct(obj, AbstractMemory, memory);
247
289
  return memory;
248
290
  }
291
+
249
292
  rb_raise(rb_eArgError, "Invalid Memory object");
293
+ return NULL;
294
+ }
295
+
296
+ static VALUE
297
+ memory_op_get_strptr(AbstractMemory* ptr, long offset)
298
+ {
299
+ void* tmp = NULL;
300
+
301
+ if (ptr != NULL && ptr->address != NULL) {
302
+ checkBounds(ptr, offset, sizeof(tmp));
303
+ memcpy(&tmp, ptr->address + offset, sizeof(tmp));
304
+ }
305
+
306
+ return tmp != NULL ? rb_tainted_str_new2(tmp) : Qnil;
250
307
  }
251
308
 
309
+ static void
310
+ memory_op_put_strptr(AbstractMemory* ptr, long offset, VALUE value)
311
+ {
312
+ rb_raise(rb_eArgError, "Cannot set :string fields");
313
+ }
314
+
315
+ static MemoryOp memory_op_strptr = { memory_op_get_strptr, memory_op_put_strptr };
316
+
317
+ //static MemoryOp memory_op_pointer = { memory_op_get_pointer, memory_op_put_pointer };
318
+
319
+ MemoryOps rbffi_AbstractMemoryOps = {
320
+ .int8 = &memory_op_int8,
321
+ .uint8 = &memory_op_uint8,
322
+ .int16 = &memory_op_int16,
323
+ .uint16 = &memory_op_uint16,
324
+ .int32 = &memory_op_int32,
325
+ .uint32 = &memory_op_uint32,
326
+ .int64 = &memory_op_int64,
327
+ .uint64 = &memory_op_uint64,
328
+ .float32 = &memory_op_float32,
329
+ .float64 = &memory_op_float64,
330
+ .pointer = &memory_op_pointer,
331
+ .strptr = &memory_op_strptr,
332
+ };
333
+
252
334
  void
253
- rb_FFI_AbstractMemory_Init()
335
+ rbffi_AbstractMemory_Init(VALUE moduleFFI)
254
336
  {
255
- VALUE moduleFFI = rb_define_module("FFI");
256
- rb_FFI_AbstractMemory_class = classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
337
+ VALUE classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
338
+ rbffi_AbstractMemoryClass = classMemory;
339
+ rb_global_variable(&rbffi_AbstractMemoryClass);
340
+
341
+ rb_define_alloc_func(classMemory, memory_allocate);
257
342
  #undef INT
258
343
  #define INT(type) \
259
344
  rb_define_method(classMemory, "put_" #type, memory_put_##type, 2); \
@@ -286,16 +371,11 @@ rb_FFI_AbstractMemory_Init()
286
371
  ALIAS(long_long, int64);
287
372
 
288
373
  if (sizeof(long) == 4) {
289
- rb_define_alias(classMemory, "put_long", "put_int32");
290
- rb_define_alias(classMemory, "put_ulong", "put_uint32");
291
- rb_define_alias(classMemory, "get_long", "get_int32");
292
- rb_define_alias(classMemory, "get_ulong", "get_uint32");
374
+ ALIAS(long, int32);
293
375
  } else {
294
- rb_define_alias(classMemory, "put_long", "put_int64");
295
- rb_define_alias(classMemory, "put_ulong", "put_uint64");
296
- rb_define_alias(classMemory, "get_long", "get_int64");
297
- rb_define_alias(classMemory, "get_ulong", "get_uint64");
376
+ ALIAS(long, int64);
298
377
  }
378
+
299
379
  rb_define_method(classMemory, "put_float32", memory_put_float32, 2);
300
380
  rb_define_method(classMemory, "get_float32", memory_get_float32, 1);
301
381
  rb_define_alias(classMemory, "put_float", "put_float32");
@@ -314,15 +394,19 @@ rb_FFI_AbstractMemory_Init()
314
394
  rb_define_alias(classMemory, "get_array_of_double", "get_array_of_float64");
315
395
  rb_define_method(classMemory, "put_pointer", memory_put_pointer, 2);
316
396
  rb_define_method(classMemory, "get_pointer", memory_get_pointer, 1);
397
+ rb_define_method(classMemory, "put_array_of_pointer", memory_put_array_of_pointer, 2);
398
+ rb_define_method(classMemory, "get_array_of_pointer", memory_get_array_of_pointer, 2);
317
399
  rb_define_method(classMemory, "put_callback", memory_put_callback, 3);
318
400
  rb_define_method(classMemory, "get_string", memory_get_string, -1);
319
401
  rb_define_method(classMemory, "put_string", memory_put_string, 2);
320
402
  rb_define_method(classMemory, "get_bytes", memory_get_bytes, 2);
321
403
  rb_define_method(classMemory, "put_bytes", memory_put_bytes, -1);
404
+ rb_define_method(classMemory, "get_array_of_string", memory_get_array_of_string, -1);
322
405
 
323
406
  rb_define_method(classMemory, "clear", memory_clear, 0);
324
407
  rb_define_method(classMemory, "total", memory_size, 0);
325
408
 
326
- to_ptr = rb_intern("to_ptr");
409
+ id_to_ptr = rb_intern("to_ptr");
410
+ id_call = rb_intern("call");
327
411
  }
328
412
 
@@ -5,14 +5,40 @@
5
5
  #include <sys/types.h>
6
6
  #include <stdint.h>
7
7
 
8
+ #include "compat.h"
9
+
8
10
  #ifdef __cplusplus
9
11
  extern "C" {
10
12
  #endif
11
13
 
14
+ typedef struct AbstractMemory_ AbstractMemory;
15
+
16
+ typedef struct {
17
+ VALUE (*get)(AbstractMemory* ptr, long offset);
18
+ void (*put)(AbstractMemory* ptr, long offset, VALUE value);
19
+ } MemoryOp;
20
+
12
21
  typedef struct {
22
+ MemoryOp* int8;
23
+ MemoryOp* uint8;
24
+ MemoryOp* int16;
25
+ MemoryOp* uint16;
26
+ MemoryOp* int32;
27
+ MemoryOp* uint32;
28
+ MemoryOp* int64;
29
+ MemoryOp* uint64;
30
+ MemoryOp* float32;
31
+ MemoryOp* float64;
32
+ MemoryOp* pointer;
33
+ MemoryOp* strptr;
34
+ } MemoryOps;
35
+
36
+ struct AbstractMemory_ {
13
37
  char* address; // Use char* instead of void* to ensure adding to it works correctly
14
38
  long size;
15
- } AbstractMemory;
39
+ MemoryOps* ops;
40
+ };
41
+
16
42
 
17
43
  static inline void
18
44
  checkBounds(AbstractMemory* mem, long off, long len)
@@ -23,13 +49,17 @@ checkBounds(AbstractMemory* mem, long off, long len)
23
49
  }
24
50
  }
25
51
 
26
- #define MEMORY(obj) rb_FFI_AbstractMemory_cast((obj), rb_FFI_AbstractMemory_class)
52
+ #define MEMORY(obj) rbffi_AbstractMemory_Cast((obj), rbffi_AbstractMemoryClass)
27
53
  #define MEMORY_PTR(obj) MEMORY((obj))->address
28
54
  #define MEMORY_LEN(obj) MEMORY((obj))->size
29
55
 
30
- extern AbstractMemory* rb_FFI_AbstractMemory_cast(VALUE obj, VALUE klass);
56
+ extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
57
+
58
+ extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
59
+
60
+ extern VALUE rbffi_AbstractMemoryClass;
61
+ extern MemoryOps rbffi_AbstractMemoryOps;
31
62
 
32
- extern VALUE rb_FFI_AbstractMemory_class;
33
63
  #ifdef __cplusplus
34
64
  }
35
65
  #endif
@@ -13,17 +13,20 @@ typedef struct AutoPointer {
13
13
  VALUE parent;
14
14
  } AutoPointer;
15
15
 
16
- VALUE rb_FFI_AutoPointer_class;
17
- static VALUE classAutoPointer = Qnil;
18
16
  static void autoptr_mark(AutoPointer* ptr);
19
- static void autoptr_free(AutoPointer* ptr);
17
+ static VALUE autoptr_allocate(VALUE klass);
18
+ static VALUE autoptr_set_parent(VALUE self, VALUE parent);
19
+
20
+ VALUE rbffi_AutoPointerClass = Qnil;
20
21
 
21
22
  static VALUE
22
23
  autoptr_allocate(VALUE klass)
23
24
  {
24
25
  AutoPointer* p;
25
- VALUE obj = Data_Make_Struct(klass, AutoPointer, autoptr_mark, autoptr_free, p);
26
+ VALUE obj = Data_Make_Struct(klass, AutoPointer, autoptr_mark, -1, p);
26
27
  p->parent = Qnil;
28
+ p->memory.ops = &rbffi_AbstractMemoryOps;
29
+
27
30
  return obj;
28
31
  }
29
32
 
@@ -31,7 +34,7 @@ static VALUE
31
34
  autoptr_set_parent(VALUE self, VALUE parent)
32
35
  {
33
36
  AutoPointer* p;
34
- AbstractMemory* ptr = rb_FFI_AbstractMemory_cast(parent, rb_FFI_Pointer_class);
37
+ AbstractMemory* ptr = rbffi_AbstractMemory_Cast(parent, rbffi_PointerClass);
35
38
 
36
39
  Data_Get_Struct(self, AutoPointer, p);
37
40
  p->memory = *ptr;
@@ -43,21 +46,15 @@ autoptr_set_parent(VALUE self, VALUE parent)
43
46
  static void
44
47
  autoptr_mark(AutoPointer* ptr)
45
48
  {
46
- if (ptr->parent != Qnil) {
47
- rb_gc_mark(ptr->parent);
48
- }
49
- }
50
- static void
51
- autoptr_free(AutoPointer* ptr)
52
- {
53
- xfree(ptr);
49
+ rb_gc_mark(ptr->parent);
54
50
  }
55
51
 
56
52
  void
57
- rb_FFI_AutoPointer_Init()
53
+ rbffi_AutoPointer_Init(VALUE moduleFFI)
58
54
  {
59
- VALUE moduleFFI = rb_define_module("FFI");
60
- rb_FFI_AutoPointer_class = classAutoPointer = rb_define_class_under(moduleFFI, "AutoPointer", rb_FFI_Pointer_class);
61
- rb_define_alloc_func(classAutoPointer, autoptr_allocate);
62
- rb_define_protected_method(classAutoPointer, "parent=", autoptr_set_parent, 1);
55
+ rbffi_AutoPointerClass = rb_define_class_under(moduleFFI, "AutoPointer", rbffi_PointerClass);
56
+ rb_global_variable(&rbffi_AutoPointerClass);
57
+
58
+ rb_define_alloc_func(rbffi_AutoPointerClass, autoptr_allocate);
59
+ rb_define_protected_method(rbffi_AutoPointerClass, "parent=", autoptr_set_parent, 1);
63
60
  }
@@ -6,8 +6,8 @@
6
6
  extern "C" {
7
7
  #endif
8
8
 
9
- extern void rb_FFI_AutoPointer_Init(void);
10
- extern VALUE rb_FFI_AutoPointer_class;
9
+ extern void rbffi_AutoPointer_Init(VALUE ffiModule);
10
+ extern VALUE rbffi_AutoPointerClass;
11
11
 
12
12
 
13
13
  #ifdef __cplusplus