From b3eb0f3df668448656e7807085570341fa2d0aa5 Mon Sep 17 00:00:00 2001 From: furunkel Date: Thu, 14 Jul 2016 17:28:19 +0200 Subject: Add AbstractMemory#get and AbstractMemory#put --- ext/ffi_c/AbstractMemory.c | 71 ++++++++++++++++++++++++++++++++++++- lib/ffi/pointer.rb | 21 +++++++++++ spec/ffi/rbx/memory_pointer_spec.rb | 66 +++++++++++++++++++++++++++++++++- 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; @@ -319,6 +319,72 @@ memory_size(VALUE self) return LONG2NUM(ptr->size); } +/* + * 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. @@ -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 bfd9406..a1d72e5 100644 --- a/lib/ffi/pointer.rb +++ b/lib/ffi/pointer.rb @@ -130,5 +130,26 @@ module FFI } 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 -- cgit v1.2.1