ffi 0.3.1 → 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.
- data/README.rdoc +51 -1
- data/Rakefile +38 -28
- data/ext/ffi_c/AbstractMemory.c +74 -70
- data/ext/ffi_c/AbstractMemory.h +8 -4
- data/ext/ffi_c/AutoPointer.c +8 -9
- data/ext/ffi_c/AutoPointer.h +2 -2
- data/ext/ffi_c/Buffer.c +42 -24
- data/ext/ffi_c/Callback.c +85 -33
- data/ext/ffi_c/Callback.h +11 -5
- data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
- data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
- data/ext/ffi_c/Invoker.c +152 -192
- data/ext/ffi_c/LastError.c +135 -0
- data/ext/ffi_c/LastError.h +18 -0
- data/ext/ffi_c/MemoryPointer.c +27 -20
- data/ext/ffi_c/MemoryPointer.h +3 -3
- data/ext/ffi_c/NullPointer.c +51 -47
- data/ext/ffi_c/Platform.c +9 -10
- data/ext/ffi_c/Platform.h +1 -1
- data/ext/ffi_c/Pointer.c +52 -21
- data/ext/ffi_c/Pointer.h +8 -6
- data/ext/ffi_c/Struct.c +70 -61
- data/ext/ffi_c/Struct.h +2 -2
- data/ext/ffi_c/Type.c +230 -0
- data/ext/ffi_c/Type.h +28 -0
- data/ext/ffi_c/Types.c +48 -6
- data/ext/ffi_c/Types.h +8 -2
- data/ext/ffi_c/endian.h +40 -0
- data/ext/ffi_c/extconf.rb +6 -5
- data/ext/ffi_c/ffi.c +21 -44
- data/ext/ffi_c/libffi.bsd.mk +34 -0
- data/ext/ffi_c/libffi.darwin.mk +30 -10
- data/ext/ffi_c/libffi.gnu.mk +29 -0
- data/ext/ffi_c/libffi.mk +4 -2
- data/ext/ffi_c/rbffi.h +6 -8
- data/gen/Rakefile +12 -0
- data/lib/ffi/autopointer.rb +1 -1
- data/lib/ffi/enum.rb +78 -0
- data/lib/ffi/ffi.rb +5 -6
- data/lib/ffi/io.rb +15 -1
- data/lib/ffi/library.rb +79 -18
- data/lib/ffi/pointer.rb +2 -2
- data/lib/ffi/struct.rb +68 -14
- data/lib/ffi/types.rb +6 -3
- data/lib/ffi/variadic.rb +2 -2
- data/lib/ffi.rb +10 -1
- data/spec/ffi/bool_spec.rb +24 -0
- data/spec/ffi/callback_spec.rb +217 -17
- data/spec/ffi/enum_spec.rb +164 -0
- data/spec/ffi/managed_struct_spec.rb +6 -1
- data/spec/ffi/number_spec.rb +30 -0
- data/spec/ffi/pointer_spec.rb +33 -8
- data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
- data/spec/ffi/spec_helper.rb +5 -1
- data/spec/ffi/string_spec.rb +65 -4
- data/spec/ffi/struct_callback_spec.rb +41 -0
- data/spec/ffi/struct_initialize_spec.rb +30 -0
- data/spec/ffi/struct_spec.rb +44 -21
- metadata +31 -69
- data/ext/ffi_c/ffi.mk +0 -23
- data/nbproject/Makefile-Default.mk +0 -57
- data/nbproject/Makefile-impl.mk +0 -123
- data/nbproject/Package-Default.bash +0 -72
- data/nbproject/configurations.xml +0 -293
- data/nbproject/private/configurations.xml +0 -22
- data/nbproject/private/private.xml +0 -7
- data/nbproject/project.properties +0 -0
- data/nbproject/project.xml +0 -15
- data/samples/getlogin.rb +0 -7
- data/samples/getpid.rb +0 -7
- data/samples/gettimeofday.rb +0 -17
- data/samples/hello.rb +0 -6
- data/samples/inotify.rb +0 -59
- data/samples/pty.rb +0 -75
- data/samples/qsort.rb +0 -20
- 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
|
-
|
|
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 = (
|
|
4
|
+
USE_RAKE_COMPILER = (RUBY_PLATFORM =~ /java/) ? false : true
|
|
4
5
|
if USE_RAKE_COMPILER
|
|
5
|
-
gem 'rake-compiler', '>=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,28 +26,32 @@ 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
|
|
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.
|
|
37
|
+
PROJ.version = '0.4.0'
|
|
35
38
|
PROJ.rubyforge.name = 'ffi'
|
|
36
39
|
PROJ.readme_file = 'README.rdoc'
|
|
37
40
|
|
|
38
41
|
# Annoucement
|
|
39
|
-
PROJ.ann.paragraphs
|
|
40
|
-
|
|
42
|
+
PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
|
|
43
|
+
|
|
44
|
+
PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
|
|
41
45
|
PROJ.ann.email[:to] << 'dev@ruby-ffi.kenai.com' << 'users@ruby-ffi.kenai.com'
|
|
42
46
|
PROJ.ann.email[:server] = 'smtp.gmail.com'
|
|
43
47
|
|
|
44
48
|
# Gem specifications
|
|
45
49
|
PROJ.gem.need_tar = false
|
|
46
|
-
PROJ.gem.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{ext,lib,
|
|
50
|
+
PROJ.gem.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{ext,gen,lib,spec}/**/*")
|
|
47
51
|
PROJ.gem.platform = Gem::Platform::RUBY
|
|
48
|
-
|
|
52
|
+
|
|
53
|
+
# Override Mr. Bones autogenerated extensions and force ours in
|
|
54
|
+
PROJ.gem.extras['extensions'] = %w(ext/ffi_c/extconf.rb gen/Rakefile)
|
|
49
55
|
|
|
50
56
|
# RDoc
|
|
51
57
|
PROJ.rdoc.exclude << '^ext\/'
|
|
@@ -53,7 +59,7 @@ PROJ.rdoc.opts << '-x' << 'ext'
|
|
|
53
59
|
|
|
54
60
|
# Ruby
|
|
55
61
|
PROJ.ruby_opts = []
|
|
56
|
-
PROJ.ruby_opts << '-I' <<
|
|
62
|
+
PROJ.ruby_opts << '-I' << BUILD_EXT_DIR unless RUBY_PLATFORM == "java"
|
|
57
63
|
|
|
58
64
|
#RSpec
|
|
59
65
|
PROJ.spec.opts << '--color' << '-fs'
|
|
@@ -73,12 +79,12 @@ else
|
|
|
73
79
|
desc "Run all specs"
|
|
74
80
|
task :specs => TEST_DEPS do
|
|
75
81
|
ENV["MRI_FFI"] = "1"
|
|
76
|
-
sh %{#{Gem.ruby} -Ilib -I#{
|
|
82
|
+
sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
|
|
77
83
|
end
|
|
78
84
|
desc "Run rubinius specs"
|
|
79
85
|
task :rbxspecs => TEST_DEPS do
|
|
80
86
|
ENV["MRI_FFI"] = "1"
|
|
81
|
-
sh %{#{Gem.ruby} -Ilib -I#{
|
|
87
|
+
sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
|
|
82
88
|
end
|
|
83
89
|
end
|
|
84
90
|
|
|
@@ -88,30 +94,31 @@ task :package => 'gem:package'
|
|
|
88
94
|
desc "Install the gem locally"
|
|
89
95
|
task :install => 'gem:install'
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
file "#{BUILD_DIR}/Makefile" do
|
|
93
|
-
FileUtils.mkdir_p(BUILD_DIR) unless File.directory?(BUILD_DIR)
|
|
94
|
-
sh %{cd "#{BUILD_DIR}" && #{Gem.ruby} #{Dir.pwd}/ext/ffi_c/extconf.rb}
|
|
95
|
-
end
|
|
96
|
-
desc "Compile the native module"
|
|
97
|
-
task :compile => "#{BUILD_DIR}/Makefile" do
|
|
98
|
-
sh %{cd "#{BUILD_DIR}"; make}
|
|
99
|
-
end
|
|
100
|
-
end
|
|
97
|
+
|
|
101
98
|
desc "Clean all built files"
|
|
102
|
-
task :
|
|
103
|
-
FileUtils.rm_rf(
|
|
104
|
-
FileUtils.rm_rf(
|
|
105
|
-
FileUtils.
|
|
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')
|
|
106
106
|
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
desc "Build the native test lib"
|
|
107
110
|
task "build/libtest.#{LIBEXT}" do
|
|
108
|
-
sh %{#{GMAKE} -f libtest/GNUmakefile}
|
|
111
|
+
sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{Config::CONFIG['host_cpu']}}
|
|
109
112
|
end
|
|
113
|
+
|
|
114
|
+
|
|
110
115
|
desc "Build test helper lib"
|
|
111
116
|
task :libtest => "build/libtest.#{LIBEXT}"
|
|
117
|
+
|
|
112
118
|
desc "Test the extension"
|
|
113
|
-
task :test => [ :specs, :rbxspecs ]
|
|
114
|
-
|
|
119
|
+
task :test => [ :specs, :rbxspecs ]
|
|
120
|
+
|
|
121
|
+
|
|
115
122
|
namespace :bench do
|
|
116
123
|
ITER = ENV['ITER'] ? ENV['ITER'].to_i : 100000
|
|
117
124
|
bench_libs = "-Ilib -I#{BUILD_DIR}" unless RUBY_PLATFORM == "java"
|
|
@@ -130,3 +137,6 @@ end
|
|
|
130
137
|
|
|
131
138
|
task 'spec:run' => TEST_DEPS
|
|
132
139
|
task 'spec:specdoc' => TEST_DEPS
|
|
140
|
+
|
|
141
|
+
task :default => :specs
|
|
142
|
+
|
data/ext/ffi_c/AbstractMemory.c
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
static inline char* memory_address(VALUE self);
|
|
14
|
-
VALUE
|
|
15
|
-
static
|
|
16
|
-
static ID
|
|
14
|
+
VALUE rbffi_AbstractMemoryClass = Qnil;
|
|
15
|
+
static ID id_to_ptr = 0;
|
|
16
|
+
static ID id_call = 0;
|
|
17
17
|
|
|
18
18
|
static VALUE
|
|
19
19
|
memory_allocate(VALUE klass)
|
|
@@ -21,7 +21,7 @@ memory_allocate(VALUE klass)
|
|
|
21
21
|
AbstractMemory* memory;
|
|
22
22
|
VALUE obj;
|
|
23
23
|
obj = Data_Make_Struct(klass, AbstractMemory, NULL, -1, memory);
|
|
24
|
-
memory->ops = &
|
|
24
|
+
memory->ops = &rbffi_AbstractMemoryOps;
|
|
25
25
|
|
|
26
26
|
return obj;
|
|
27
27
|
}
|
|
@@ -107,63 +107,26 @@ NUM_OP(uint64, uint64_t, NUM2ULL, ULL2NUM);
|
|
|
107
107
|
NUM_OP(float32, float, NUM2DBL, rb_float_new);
|
|
108
108
|
NUM_OP(float64, double, NUM2DBL, rb_float_new);
|
|
109
109
|
|
|
110
|
-
static void
|
|
111
|
-
|
|
112
|
-
{
|
|
110
|
+
static inline void*
|
|
111
|
+
get_pointer_value(VALUE value)
|
|
112
|
+
{
|
|
113
113
|
const int type = TYPE(value);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (rb_obj_is_kind_of(value, rb_FFI_Pointer_class) && type == T_DATA) {
|
|
117
|
-
void* tmp = memory_address(value);
|
|
118
|
-
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);
|
|
119
116
|
} else if (type == T_NIL) {
|
|
120
|
-
|
|
121
|
-
memcpy(memory->address + off, &tmp, sizeof(tmp));
|
|
117
|
+
return NULL;
|
|
122
118
|
} else if (type == T_FIXNUM) {
|
|
123
|
-
|
|
124
|
-
memcpy(memory->address + off, &tmp, sizeof(tmp));
|
|
119
|
+
return (void *) (uintptr_t) FIX2INT(value);
|
|
125
120
|
} else if (type == T_BIGNUM) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
VALUE ptr = rb_funcall2(value, to_ptr, 0, NULL);
|
|
130
|
-
void* tmp = MEMORY_PTR(ptr);
|
|
131
|
-
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));
|
|
132
124
|
} else {
|
|
133
125
|
rb_raise(rb_eArgError, "value is not a pointer");
|
|
134
126
|
}
|
|
135
127
|
}
|
|
136
128
|
|
|
137
|
-
|
|
138
|
-
memory_op_get_pointer(AbstractMemory* memory, long off)
|
|
139
|
-
{
|
|
140
|
-
void* tmp;
|
|
141
|
-
|
|
142
|
-
checkBounds(memory, off, sizeof(tmp));
|
|
143
|
-
memcpy(&tmp, memory->address + off, sizeof(tmp));
|
|
144
|
-
return rb_FFI_Pointer_new(tmp);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
static VALUE
|
|
148
|
-
memory_put_pointer(VALUE self, VALUE offset, VALUE value)
|
|
149
|
-
{
|
|
150
|
-
AbstractMemory* memory;
|
|
151
|
-
|
|
152
|
-
Data_Get_Struct(self, AbstractMemory, memory);
|
|
153
|
-
memory_op_put_pointer(memory, NUM2LONG(offset), value);
|
|
154
|
-
|
|
155
|
-
return self;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
static VALUE
|
|
159
|
-
memory_get_pointer(VALUE self, VALUE offset)
|
|
160
|
-
{
|
|
161
|
-
AbstractMemory* memory;
|
|
162
|
-
|
|
163
|
-
Data_Get_Struct(self, AbstractMemory, memory);
|
|
164
|
-
|
|
165
|
-
return memory_op_get_pointer(memory, NUM2LONG(offset));
|
|
166
|
-
}
|
|
129
|
+
NUM_OP(pointer, void *, get_pointer_value, rbffi_Pointer_NewInstance);
|
|
167
130
|
|
|
168
131
|
static VALUE
|
|
169
132
|
memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
|
|
@@ -172,8 +135,8 @@ memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
|
|
|
172
135
|
long off = NUM2LONG(offset);
|
|
173
136
|
checkBounds(memory, off, sizeof(void *));
|
|
174
137
|
|
|
175
|
-
if (rb_obj_is_kind_of(proc, rb_cProc)) {
|
|
176
|
-
VALUE callback =
|
|
138
|
+
if (rb_obj_is_kind_of(proc, rb_cProc) || rb_respond_to(proc, id_call)) {
|
|
139
|
+
VALUE callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
|
|
177
140
|
void* code = ((NativeCallback *) DATA_PTR(callback))->code;
|
|
178
141
|
memcpy(memory->address + off, &code, sizeof(code));
|
|
179
142
|
} else {
|
|
@@ -214,6 +177,45 @@ memory_get_string(int argc, VALUE* argv, VALUE self)
|
|
|
214
177
|
(end != NULL ? end - ptr->address - off : len));
|
|
215
178
|
}
|
|
216
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
|
+
|
|
217
219
|
static VALUE
|
|
218
220
|
memory_put_string(VALUE self, VALUE offset, VALUE str)
|
|
219
221
|
{
|
|
@@ -224,7 +226,7 @@ memory_put_string(VALUE self, VALUE offset, VALUE str)
|
|
|
224
226
|
off = NUM2LONG(offset);
|
|
225
227
|
len = RSTRING_LEN(str);
|
|
226
228
|
|
|
227
|
-
checkBounds(ptr, off, len);
|
|
229
|
+
checkBounds(ptr, off, len + 1);
|
|
228
230
|
if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
|
|
229
231
|
rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
|
|
230
232
|
}
|
|
@@ -279,14 +281,16 @@ memory_address(VALUE obj)
|
|
|
279
281
|
}
|
|
280
282
|
|
|
281
283
|
AbstractMemory*
|
|
282
|
-
|
|
284
|
+
rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass)
|
|
283
285
|
{
|
|
284
286
|
if (rb_obj_is_kind_of(obj, klass)) {
|
|
285
287
|
AbstractMemory* memory;
|
|
286
288
|
Data_Get_Struct(obj, AbstractMemory, memory);
|
|
287
289
|
return memory;
|
|
288
290
|
}
|
|
291
|
+
|
|
289
292
|
rb_raise(rb_eArgError, "Invalid Memory object");
|
|
293
|
+
return NULL;
|
|
290
294
|
}
|
|
291
295
|
|
|
292
296
|
static VALUE
|
|
@@ -310,9 +314,9 @@ memory_op_put_strptr(AbstractMemory* ptr, long offset, VALUE value)
|
|
|
310
314
|
|
|
311
315
|
static MemoryOp memory_op_strptr = { memory_op_get_strptr, memory_op_put_strptr };
|
|
312
316
|
|
|
313
|
-
static MemoryOp memory_op_pointer = { memory_op_get_pointer, memory_op_put_pointer };
|
|
317
|
+
//static MemoryOp memory_op_pointer = { memory_op_get_pointer, memory_op_put_pointer };
|
|
314
318
|
|
|
315
|
-
MemoryOps
|
|
319
|
+
MemoryOps rbffi_AbstractMemoryOps = {
|
|
316
320
|
.int8 = &memory_op_int8,
|
|
317
321
|
.uint8 = &memory_op_uint8,
|
|
318
322
|
.int16 = &memory_op_int16,
|
|
@@ -328,10 +332,11 @@ MemoryOps rb_FFI_AbstractMemory_ops = {
|
|
|
328
332
|
};
|
|
329
333
|
|
|
330
334
|
void
|
|
331
|
-
|
|
335
|
+
rbffi_AbstractMemory_Init(VALUE moduleFFI)
|
|
332
336
|
{
|
|
333
|
-
VALUE
|
|
334
|
-
|
|
337
|
+
VALUE classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
|
|
338
|
+
rbffi_AbstractMemoryClass = classMemory;
|
|
339
|
+
rb_global_variable(&rbffi_AbstractMemoryClass);
|
|
335
340
|
|
|
336
341
|
rb_define_alloc_func(classMemory, memory_allocate);
|
|
337
342
|
#undef INT
|
|
@@ -366,16 +371,11 @@ rb_FFI_AbstractMemory_Init()
|
|
|
366
371
|
ALIAS(long_long, int64);
|
|
367
372
|
|
|
368
373
|
if (sizeof(long) == 4) {
|
|
369
|
-
|
|
370
|
-
rb_define_alias(classMemory, "put_ulong", "put_uint32");
|
|
371
|
-
rb_define_alias(classMemory, "get_long", "get_int32");
|
|
372
|
-
rb_define_alias(classMemory, "get_ulong", "get_uint32");
|
|
374
|
+
ALIAS(long, int32);
|
|
373
375
|
} else {
|
|
374
|
-
|
|
375
|
-
rb_define_alias(classMemory, "put_ulong", "put_uint64");
|
|
376
|
-
rb_define_alias(classMemory, "get_long", "get_int64");
|
|
377
|
-
rb_define_alias(classMemory, "get_ulong", "get_uint64");
|
|
376
|
+
ALIAS(long, int64);
|
|
378
377
|
}
|
|
378
|
+
|
|
379
379
|
rb_define_method(classMemory, "put_float32", memory_put_float32, 2);
|
|
380
380
|
rb_define_method(classMemory, "get_float32", memory_get_float32, 1);
|
|
381
381
|
rb_define_alias(classMemory, "put_float", "put_float32");
|
|
@@ -394,15 +394,19 @@ rb_FFI_AbstractMemory_Init()
|
|
|
394
394
|
rb_define_alias(classMemory, "get_array_of_double", "get_array_of_float64");
|
|
395
395
|
rb_define_method(classMemory, "put_pointer", memory_put_pointer, 2);
|
|
396
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);
|
|
397
399
|
rb_define_method(classMemory, "put_callback", memory_put_callback, 3);
|
|
398
400
|
rb_define_method(classMemory, "get_string", memory_get_string, -1);
|
|
399
401
|
rb_define_method(classMemory, "put_string", memory_put_string, 2);
|
|
400
402
|
rb_define_method(classMemory, "get_bytes", memory_get_bytes, 2);
|
|
401
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);
|
|
402
405
|
|
|
403
406
|
rb_define_method(classMemory, "clear", memory_clear, 0);
|
|
404
407
|
rb_define_method(classMemory, "total", memory_size, 0);
|
|
405
408
|
|
|
406
|
-
|
|
409
|
+
id_to_ptr = rb_intern("to_ptr");
|
|
410
|
+
id_call = rb_intern("call");
|
|
407
411
|
}
|
|
408
412
|
|
data/ext/ffi_c/AbstractMemory.h
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
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
|
|
@@ -47,14 +49,16 @@ checkBounds(AbstractMemory* mem, long off, long len)
|
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
#define MEMORY(obj)
|
|
52
|
+
#define MEMORY(obj) rbffi_AbstractMemory_Cast((obj), rbffi_AbstractMemoryClass)
|
|
51
53
|
#define MEMORY_PTR(obj) MEMORY((obj))->address
|
|
52
54
|
#define MEMORY_LEN(obj) MEMORY((obj))->size
|
|
53
55
|
|
|
54
|
-
extern
|
|
56
|
+
extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
|
|
57
|
+
|
|
58
|
+
extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
|
|
55
59
|
|
|
56
|
-
extern VALUE
|
|
57
|
-
extern MemoryOps
|
|
60
|
+
extern VALUE rbffi_AbstractMemoryClass;
|
|
61
|
+
extern MemoryOps rbffi_AbstractMemoryOps;
|
|
58
62
|
|
|
59
63
|
#ifdef __cplusplus
|
|
60
64
|
}
|
data/ext/ffi_c/AutoPointer.c
CHANGED
|
@@ -17,7 +17,7 @@ static void autoptr_mark(AutoPointer* ptr);
|
|
|
17
17
|
static VALUE autoptr_allocate(VALUE klass);
|
|
18
18
|
static VALUE autoptr_set_parent(VALUE self, VALUE parent);
|
|
19
19
|
|
|
20
|
-
VALUE
|
|
20
|
+
VALUE rbffi_AutoPointerClass = Qnil;
|
|
21
21
|
|
|
22
22
|
static VALUE
|
|
23
23
|
autoptr_allocate(VALUE klass)
|
|
@@ -25,7 +25,7 @@ autoptr_allocate(VALUE klass)
|
|
|
25
25
|
AutoPointer* p;
|
|
26
26
|
VALUE obj = Data_Make_Struct(klass, AutoPointer, autoptr_mark, -1, p);
|
|
27
27
|
p->parent = Qnil;
|
|
28
|
-
p->memory.ops = &
|
|
28
|
+
p->memory.ops = &rbffi_AbstractMemoryOps;
|
|
29
29
|
|
|
30
30
|
return obj;
|
|
31
31
|
}
|
|
@@ -34,7 +34,7 @@ static VALUE
|
|
|
34
34
|
autoptr_set_parent(VALUE self, VALUE parent)
|
|
35
35
|
{
|
|
36
36
|
AutoPointer* p;
|
|
37
|
-
AbstractMemory* ptr =
|
|
37
|
+
AbstractMemory* ptr = rbffi_AbstractMemory_Cast(parent, rbffi_PointerClass);
|
|
38
38
|
|
|
39
39
|
Data_Get_Struct(self, AutoPointer, p);
|
|
40
40
|
p->memory = *ptr;
|
|
@@ -50,12 +50,11 @@ autoptr_mark(AutoPointer* ptr)
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
void
|
|
53
|
-
|
|
53
|
+
rbffi_AutoPointer_Init(VALUE moduleFFI)
|
|
54
54
|
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
rb_global_variable(&rb_FFI_AutoPointer_class);
|
|
55
|
+
rbffi_AutoPointerClass = rb_define_class_under(moduleFFI, "AutoPointer", rbffi_PointerClass);
|
|
56
|
+
rb_global_variable(&rbffi_AutoPointerClass);
|
|
58
57
|
|
|
59
|
-
rb_define_alloc_func(
|
|
60
|
-
rb_define_protected_method(
|
|
58
|
+
rb_define_alloc_func(rbffi_AutoPointerClass, autoptr_allocate);
|
|
59
|
+
rb_define_protected_method(rbffi_AutoPointerClass, "parent=", autoptr_set_parent, 1);
|
|
61
60
|
}
|
data/ext/ffi_c/AutoPointer.h
CHANGED
data/ext/ffi_c/Buffer.c
CHANGED
|
@@ -18,8 +18,8 @@ static void buffer_release(Buffer* ptr);
|
|
|
18
18
|
static void buffer_mark(Buffer* ptr);
|
|
19
19
|
static VALUE buffer_free(VALUE self);
|
|
20
20
|
|
|
21
|
-
static VALUE
|
|
22
|
-
#define BUFFER(obj) ((Buffer *)
|
|
21
|
+
static VALUE BufferClass = Qnil;
|
|
22
|
+
#define BUFFER(obj) ((Buffer *) rbffi_AbstractMemory_Cast((obj), BufferClass))
|
|
23
23
|
|
|
24
24
|
static VALUE
|
|
25
25
|
buffer_allocate(VALUE klass)
|
|
@@ -29,7 +29,7 @@ buffer_allocate(VALUE klass)
|
|
|
29
29
|
|
|
30
30
|
obj = Data_Make_Struct(klass, Buffer, NULL, buffer_release, buffer);
|
|
31
31
|
buffer->parent = Qnil;
|
|
32
|
-
buffer->memory.ops = &
|
|
32
|
+
buffer->memory.ops = &rbffi_AbstractMemoryOps;
|
|
33
33
|
|
|
34
34
|
return obj;
|
|
35
35
|
}
|
|
@@ -50,24 +50,23 @@ buffer_initialize(int argc, VALUE* argv, VALUE self)
|
|
|
50
50
|
{
|
|
51
51
|
VALUE size = Qnil, count = Qnil, clear = Qnil;
|
|
52
52
|
Buffer* p;
|
|
53
|
-
unsigned long msize;
|
|
54
53
|
int nargs;
|
|
55
|
-
|
|
56
|
-
nargs = rb_scan_args(argc, argv, "12", &size, &count, &clear);
|
|
57
|
-
msize = rb_FFI_type_size(size) * (nargs > 1 ? NUM2LONG(count) : 1);
|
|
58
54
|
|
|
59
55
|
Data_Get_Struct(self, Buffer, p);
|
|
60
|
-
p->memory.size = msize;
|
|
61
56
|
|
|
62
|
-
|
|
57
|
+
nargs = rb_scan_args(argc, argv, "12", &size, &count, &clear);
|
|
58
|
+
p->type_size = rbffi_type_size(size);
|
|
59
|
+
p->memory.size = p->type_size * (nargs > 1 ? NUM2LONG(count) : 1);
|
|
60
|
+
|
|
61
|
+
p->storage = malloc(p->memory.size + 7);
|
|
63
62
|
if (p->storage == NULL) {
|
|
64
|
-
rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes",
|
|
63
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", p->memory.size);
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
/* ensure the memory is aligned on at least a 8 byte boundary */
|
|
68
67
|
p->memory.address = (void *) (((uintptr_t) p->storage + 0x7) & (uintptr_t) ~0x7UL);
|
|
69
68
|
|
|
70
|
-
if (nargs > 2 && RTEST(clear) && p->memory.size > 0) {
|
|
69
|
+
if (nargs > 2 && (RTEST(clear) || clear == Qnil) && p->memory.size > 0) {
|
|
71
70
|
memset(p->memory.address, 0, p->memory.size);
|
|
72
71
|
}
|
|
73
72
|
|
|
@@ -94,15 +93,33 @@ buffer_plus(VALUE self, VALUE offset)
|
|
|
94
93
|
|
|
95
94
|
checkBounds(&ptr->memory, off, 1);
|
|
96
95
|
|
|
97
|
-
retval = Data_Make_Struct(
|
|
96
|
+
retval = Data_Make_Struct(BufferClass, Buffer, buffer_mark, -1, p);
|
|
98
97
|
p->memory.address = ptr->memory.address + off;
|
|
99
98
|
p->memory.size = ptr->memory.size - off;
|
|
100
|
-
p->memory.ops = &
|
|
99
|
+
p->memory.ops = &rbffi_AbstractMemoryOps;
|
|
101
100
|
p->parent = self;
|
|
102
101
|
|
|
103
102
|
return retval;
|
|
104
103
|
}
|
|
105
104
|
|
|
105
|
+
static VALUE
|
|
106
|
+
buffer_aref(VALUE self, VALUE offset)
|
|
107
|
+
{
|
|
108
|
+
Buffer* ptr;
|
|
109
|
+
|
|
110
|
+
Data_Get_Struct(self, Buffer, ptr);
|
|
111
|
+
return buffer_plus(self, INT2FIX(ptr->type_size * NUM2INT(offset)));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static VALUE
|
|
115
|
+
buffer_type_size(VALUE self)
|
|
116
|
+
{
|
|
117
|
+
Buffer* ptr;
|
|
118
|
+
|
|
119
|
+
Data_Get_Struct(self, Buffer, ptr);
|
|
120
|
+
return INT2NUM(ptr->type_size);
|
|
121
|
+
}
|
|
122
|
+
|
|
106
123
|
static VALUE
|
|
107
124
|
buffer_inspect(VALUE self)
|
|
108
125
|
{
|
|
@@ -135,19 +152,20 @@ buffer_mark(Buffer* ptr)
|
|
|
135
152
|
}
|
|
136
153
|
|
|
137
154
|
void
|
|
138
|
-
|
|
155
|
+
rbffi_Buffer_Init(VALUE moduleFFI)
|
|
139
156
|
{
|
|
140
|
-
|
|
141
|
-
classBuffer = rb_define_class_under(moduleFFI, "Buffer", rb_FFI_AbstractMemory_class);
|
|
157
|
+
BufferClass = rb_define_class_under(moduleFFI, "Buffer", rbffi_AbstractMemoryClass);
|
|
142
158
|
|
|
143
|
-
rb_global_variable(&
|
|
144
|
-
rb_define_alloc_func(
|
|
159
|
+
rb_global_variable(&BufferClass);
|
|
160
|
+
rb_define_alloc_func(BufferClass, buffer_allocate);
|
|
145
161
|
|
|
146
|
-
rb_define_singleton_method(
|
|
147
|
-
rb_define_singleton_method(
|
|
148
|
-
rb_define_singleton_method(
|
|
162
|
+
rb_define_singleton_method(BufferClass, "alloc_inout", buffer_alloc_inout, -1);
|
|
163
|
+
rb_define_singleton_method(BufferClass, "alloc_out", buffer_alloc_inout, -1);
|
|
164
|
+
rb_define_singleton_method(BufferClass, "alloc_in", buffer_alloc_inout, -1);
|
|
149
165
|
|
|
150
|
-
rb_define_method(
|
|
151
|
-
rb_define_method(
|
|
152
|
-
rb_define_method(
|
|
166
|
+
rb_define_method(BufferClass, "initialize", buffer_initialize, -1);
|
|
167
|
+
rb_define_method(BufferClass, "inspect", buffer_inspect, 0);
|
|
168
|
+
rb_define_method(BufferClass, "type_size", buffer_type_size, 0);
|
|
169
|
+
rb_define_method(BufferClass, "[]", buffer_aref, 1);
|
|
170
|
+
rb_define_method(BufferClass, "+", buffer_plus, 1);
|
|
153
171
|
}
|