summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortduehr <tduehr@gmail.com>2016-07-25 11:22:07 -0500
committertduehr <tduehr@gmail.com>2016-07-25 11:22:07 -0500
commitc52ceb173288073a321a94b401243ff40110d910 (patch)
tree9f27b2474d3dfbfae63f79bc064bd40a40519cc5
parent5212d3b2b5de98969748766ea4454d92428a9eea (diff)
parentb3eb0f3df668448656e7807085570341fa2d0aa5 (diff)
downloadffi-c52ceb173288073a321a94b401243ff40110d910.tar.gz
Merge branch 'memory_get_set' of https://github.com/furunkel/ffi into furunkel-memory_get_set
-rw-r--r--ext/ffi_c/AbstractMemory.c71
-rw-r--r--lib/ffi/pointer.rb21
-rw-r--r--spec/ffi/rbx/memory_pointer_spec.rb66
3 files changed, 156 insertions, 2 deletions
diff --git a/ext/ffi_c/AbstractMemory.c b/ext/ffi_c/AbstractMemory.c
index 144199c..971d244 100644
--- a/ext/ffi_c/AbstractMemory.c
+++ b/ext/ffi_c/AbstractMemory.c
@@ -310,7 +310,7 @@ memory_clear(VALUE self)
* @return [Numeric]
*/
static VALUE
-memory_size(VALUE self)
+memory_size(VALUE self)
{
AbstractMemory* ptr;
@@ -320,6 +320,72 @@ memory_size(VALUE self)
}
/*
+ * call-seq: memory.get(type, offset)
+ * Return data of given type contained in memory.
+ * @param [Symbol, Type] type_name type of data to get
+ * @param [Numeric] offset point in buffer to start from
+ * @return [Object]
+ * @raise {ArgumentError} if type is not supported
+ */
+static VALUE
+memory_get(VALUE self, VALUE type_name, VALUE offset)
+{
+ AbstractMemory* ptr;
+ VALUE nType;
+ Type *type;
+
+ nType = rbffi_Type_Lookup(type_name);
+ if(NIL_P(nType)) goto undefined_type;
+
+ Data_Get_Struct(self, AbstractMemory, ptr);
+ Data_Get_Struct(nType, Type, type);
+
+ MemoryOp *op = get_memory_op(type);
+ if(op == NULL) goto undefined_type;
+
+ return op->get(ptr, NUM2LONG(offset));
+
+undefined_type: {
+ VALUE msg = rb_sprintf("undefined type '%" PRIsVALUE "'", type_name);
+ rb_exc_raise(rb_exc_new3(rb_eArgError, msg));
+ return Qnil;
+ }
+}
+
+/*
+ * call-seq: memory.put(type, offset, value)
+ * @param [Symbol, Type] type_name type of data to put
+ * @param [Numeric] offset point in buffer to start from
+ * @return [nil]
+ * @raise {ArgumentError} if type is not supported
+ */
+static VALUE
+memory_put(VALUE self, VALUE type_name, VALUE offset, VALUE value)
+{
+ AbstractMemory* ptr;
+ VALUE nType;
+ Type *type;
+
+ nType = rbffi_Type_Lookup(type_name);
+ if(NIL_P(nType)) goto undefined_type;
+
+ Data_Get_Struct(self, AbstractMemory, ptr);
+ Data_Get_Struct(nType, Type, type);
+
+ MemoryOp *op = get_memory_op(type);
+ if(op == NULL) goto undefined_type;
+
+ op->put(ptr, NUM2LONG(offset), value);
+ return Qnil;
+
+undefined_type: {
+ VALUE msg = rb_sprintf("unsupported type '%" PRIsVALUE "'", type_name);
+ rb_exc_raise(rb_exc_new3(rb_eArgError, msg));
+ return Qnil;
+ }
+}
+
+/*
* call-seq: memory.get_string(offset, length=nil)
* Return string contained in memory.
* @param [Numeric] offset point in buffer to start from
@@ -1018,6 +1084,9 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
rb_define_method(classMemory, "write_bytes", memory_write_bytes, -1);
rb_define_method(classMemory, "get_array_of_string", memory_get_array_of_string, -1);
+ rb_define_method(classMemory, "get", memory_get, 2);
+ rb_define_method(classMemory, "put", memory_put, 3);
+
rb_define_method(classMemory, "clear", memory_clear, 0);
rb_define_method(classMemory, "total", memory_size, 0);
rb_define_alias(classMemory, "size", "total");
diff --git a/lib/ffi/pointer.rb b/lib/ffi/pointer.rb
index 81859b1..de4f91f 100644
--- a/lib/ffi/pointer.rb
+++ b/lib/ffi/pointer.rb
@@ -135,5 +135,26 @@ module FFI
def to_ptr
self
end
+
+ # @param [Symbol,Type] type of data to read
+ # @return [Object]
+ # Read pointer's contents as +type+
+ #
+ # Same as:
+ # ptr.get(type, 0)
+ def read(type)
+ get(type, 0)
+ end
+
+ # @param [Symbol,Type] type of data to read
+ # @param [Object] value to write
+ # @return [nil]
+ # Write +value+ of type +type+ to pointer's content
+ #
+ # Same as:
+ # ptr.put(type, 0)
+ def write(type, value)
+ put(type, 0, value)
+ end
end
end
diff --git a/spec/ffi/rbx/memory_pointer_spec.rb b/spec/ffi/rbx/memory_pointer_spec.rb
index 0fe3597..a869d8c 100644
--- a/spec/ffi/rbx/memory_pointer_spec.rb
+++ b/spec/ffi/rbx/memory_pointer_spec.rb
@@ -52,12 +52,76 @@ describe "MemoryPointer" do
m = FFI::MemoryPointer.new(:int)
m.write_int(1)
expect(m.read_int).to eq(1)
+ expect(m.read :int).to eq(1)
+ expect(m.read FFI::Type::INT).to eq(1)
end
-
+
+ it "allows writing as a sized int" do
+ m = FFI::MemoryPointer.new(:uint32)
+ m.write_uint32(1)
+ expect(m.read_uint32).to eq(1)
+ expect(m.read :uint32).to eq(1)
+ expect(m.read FFI::Type::UINT32).to eq(1)
+
+ m = FFI::MemoryPointer.new(:uint32)
+ m.write :uint32, 1
+ expect(m.read :uint32).to eq(1)
+
+ m = FFI::MemoryPointer.new(:int64)
+ m.write_int64(1)
+ expect(m.read_int64).to eq(1)
+ expect(m.read :int64).to eq(1)
+ expect(m.read FFI::Type::INT64).to eq(1)
+
+ m = FFI::MemoryPointer.new(:int64)
+ m.write :int64, 1
+ expect(m.read :int64).to eq(1)
+ end
+
it "allows writing as a long" do
m = FFI::MemoryPointer.new(:long)
m.write_long(10)
expect(m.read_long).to eq(10)
+ expect(m.read :long).to eq(10)
+ expect(m.read FFI::Type::LONG).to eq(10)
+
+ m.write :long, 10
+ expect(m.read :long).to eq(10)
+ end
+
+ it "allows writing as a size_t" do
+ m = FFI::MemoryPointer.new(:size_t)
+ m.write(:size_t, 10)
+ expect(m.read :size_t).to eq(10)
+ end
+
+ it "allows writing as a bool" do
+ m = FFI::MemoryPointer.new(:bool)
+ m.write(:bool, true)
+ expect(m.read :bool).to eq(true)
+ expect(m.read FFI::Type::BOOL).to eq(true)
+
+ m.write(:bool, false)
+ expect(m.read :bool).to eq(false)
+ expect(m.read FFI::Type::BOOL).to eq(false)
+ end
+
+ it "allows writing a custom typedef" do
+ FFI.typedef :uint, :fubar_t
+ FFI.typedef :size_t, :fubar2_t
+
+ m = FFI::MemoryPointer.new(:fubar_t)
+ m.write(:fubar_t, 10)
+ expect(m.read :fubar_t).to eq(10)
+
+ m = FFI::MemoryPointer.new(:fubar2_t)
+ m.write(:fubar2_t, 10)
+ expect(m.read :fubar2_t).to eq(10)
+ end
+
+ it "raises an error if you try to read an undefined type" do
+ m = FFI::MemoryPointer.new(:long)
+ expect { m.read(:undefined_type) }.to raise_error(ArgumentError)
end
it "raises an error if you try putting a long into a pointer of size 1" do