FFI::AbstractMemory
Pointer class is used to manage C pointers with ease. A {Pointer} object is defined by his {address} (as a C pointer). It permits additions with an integer for pointer arithmetic.
A pointer object may autorelease his contents when freed (by default). This behaviour may be changed with {autorelease=} method.
@overload initialize(pointer)
@param [Pointer] pointer another pointer to initialize from Create a new pointer from another {Pointer}.
@overload initialize(type, address)
@param [Type] type type for pointer @param [Integer] address base address for pointer Create a new pointer from a {Type} and a base adresse
@return [self] A new instance of Pointer.
static VALUE ptr_initialize(int argc, VALUE* argv, VALUE self) { Pointer* p; VALUE rbType = Qnil, rbAddress = Qnil; int typeSize = 1; Data_Get_Struct(self, Pointer, p); switch (rb_scan_args(argc, argv, "11", &rbType, &rbAddress)) { case 1: rbAddress = rbType; typeSize = 1; break; case 2: typeSize = rbffi_type_size(rbType); break; default: rb_raise(rb_eArgError, "Invalid arguments"); } switch (TYPE(rbAddress)) { case T_FIXNUM: case T_BIGNUM: p->memory.address = (void*) (uintptr_t) NUM2LL(rbAddress); p->memory.size = LONG_MAX; if (p->memory.address == NULL) { p->memory.flags = 0; } break; default: if (rb_obj_is_kind_of(rbAddress, rbffi_PointerClass)) { Pointer* orig; p->rbParent = rbAddress; Data_Get_Struct(rbAddress, Pointer, orig); p->memory = orig->memory; } else { rb_raise(rb_eTypeError, "wrong argument type, expected Integer or FFI::Pointer"); } break; } p->memory.typeSize = typeSize; return self; }
static VALUE ptr_plus(VALUE self, VALUE offset) { AbstractMemory* ptr; long off = NUM2LONG(offset); Data_Get_Struct(self, AbstractMemory, ptr); return slice(self, off, ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off); }
static VALUE ptr_equals(VALUE self, VALUE other) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); if (NIL_P(other)) { return ptr->memory.address == NULL ? Qtrue : Qfalse; } return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse; }
static VALUE ptr_address(VALUE self) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); return ULL2NUM((uintptr_t) ptr->memory.address); }
static VALUE ptr_autorelease(VALUE self, VALUE autorelease) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); ptr->autorelease = autorelease == Qtrue; return autorelease; }
static VALUE ptr_autorelease_p(VALUE self) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); return ptr->autorelease ? Qtrue : Qfalse; }
static VALUE ptr_free(VALUE self) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); if (ptr->allocated) { if (ptr->storage != NULL) { xfree(ptr->storage); ptr->storage = NULL; } ptr->allocated = false; } else { VALUE caller = rb_funcall(rb_funcall(Qnil, rb_intern("caller"), 0), rb_intern("first"), 0); rb_warn("calling free on non allocated pointer %s from %s", RSTRING_PTR(ptr_inspect(self)), RSTRING_PTR(rb_str_to_str(caller))); } return self; }
This method is internally used by dup and clone. Memory contents is copied from other.
static VALUE ptr_initialize_copy(VALUE self, VALUE other) { AbstractMemory* src; Pointer* dst; Data_Get_Struct(self, Pointer, dst); src = POINTER(other); if (src->size == LONG_MAX) { rb_raise(rb_eRuntimeError, "cannot duplicate unbounded memory area"); return Qnil; } if ((dst->memory.flags & (MEM_RD | MEM_WR)) != (MEM_RD | MEM_WR)) { rb_raise(rb_eRuntimeError, "cannot duplicate unreadable/unwritable memory area"); return Qnil; } if (dst->storage != NULL) { xfree(dst->storage); dst->storage = NULL; } dst->storage = xmalloc(src->size + 7); if (dst->storage == NULL) { rb_raise(rb_eNoMemError, "failed to allocate memory size=%lu bytes", src->size); return Qnil; } dst->allocated = true; dst->autorelease = true; dst->memory.address = (void *) (((uintptr_t) dst->storage + 0x7) & (uintptr_t) ~0x7UL); dst->memory.size = src->size; dst->memory.typeSize = src->typeSize; /* finally, copy the actual memory contents */ memcpy(dst->memory.address, src->address, src->size); return self; }
static VALUE ptr_inspect(VALUE self) { char buf[100]; Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); if (ptr->memory.size != LONG_MAX) { snprintf(buf, sizeof(buf), "#<%s address=%p size=%lu>", rb_obj_classname(self), ptr->memory.address, ptr->memory.size); } else { snprintf(buf, sizeof(buf), "#<%s address=%p>", rb_obj_classname(self), ptr->memory.address); } return rb_str_new2(buf); }
static VALUE ptr_null_p(VALUE self) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); return ptr->memory.address == NULL ? Qtrue : Qfalse; }
Get or set self‘s endianness @overload order
@return [:big, :little] endianness of +self+
@overload order(order)
@param [Symbol] order endianness to set (+:little+, +:big+ or +:network+). +:big+ and +:network+ are synonymous. @return [self]
static VALUE ptr_order(int argc, VALUE* argv, VALUE self) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); if (argc == 0) { int order = (ptr->memory.flags & MEM_SWAP) == 0 ? BYTE_ORDER : SWAPPED_ORDER; return order == BIG_ENDIAN ? ID2SYM(rb_intern("big")) : ID2SYM(rb_intern("little")); } else { VALUE rbOrder = Qnil; int order = BYTE_ORDER; if (rb_scan_args(argc, argv, "1", &rbOrder) < 1) { rb_raise(rb_eArgError, "need byte order"); } if (SYMBOL_P(rbOrder)) { ID id = SYM2ID(rbOrder); if (id == rb_intern("little")) { order = LITTLE_ENDIAN; } else if (id == rb_intern("big") || id == rb_intern("network")) { order = BIG_ENDIAN; } } if (order != BYTE_ORDER) { Pointer* p2; VALUE retval = slice(self, 0, ptr->memory.size); Data_Get_Struct(retval, Pointer, p2); p2->memory.flags |= MEM_SWAP; return retval; } return self; } }
@param [Type] type type of data to read from pointer’s contents @param [Symbol] reader method to send to self to read type @param [Numeric] length @return [Array] Read an array of type of length length. @example
ptr.read_array_of_type(TYPE_UINT8, :get_uint8, 4) # -> [1, 2, 3, 4]
# File lib/ffi/pointer.rb, line 106 def read_array_of_type(type, reader, length) ary = [] size = FFI.type_size(type) tmp = self length.times { |j| ary << tmp.send(reader) tmp += size unless j == length-1 # avoid OOB } ary end
@param [nil,Numeric] len length of string to return @return [String] Read pointer’s contents as a string, or the first len bytes of the equivalent string if len is not nil.
# File lib/ffi/pointer.rb, line 50 def read_string(len=nil) if len get_bytes(0, len) else get_string(0) end end
@param [Numeric] len length of string to return @return [String] Read the first len bytes of pointer’s contents as a string.
Same as:
ptr.read_string(len) # with len not nil
# File lib/ffi/pointer.rb, line 64 def read_string_length(len) get_bytes(0, len) end
@return [String] Read pointer’s contents as a string.
Same as:
ptr.read_string # with no len
# File lib/ffi/pointer.rb, line 73 def read_string_to_null get_string(0) end
static VALUE ptr_slice(VALUE self, VALUE rbOffset, VALUE rbLength) { return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength)); }
static VALUE ptr_inspect(VALUE self) { char buf[100]; Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); if (ptr->memory.size != LONG_MAX) { snprintf(buf, sizeof(buf), "#<%s address=%p size=%lu>", rb_obj_classname(self), ptr->memory.address, ptr->memory.size); } else { snprintf(buf, sizeof(buf), "#<%s address=%p>", rb_obj_classname(self), ptr->memory.address); } return rb_str_new2(buf); }
static VALUE ptr_type_size(VALUE self) { Pointer* ptr; Data_Get_Struct(self, Pointer, ptr); return INT2NUM(ptr->memory.typeSize); }
@param [Type] type type of data to write to pointer’s contents @param [Symbol] writer method to send to self to write type @param [Array] ary @return [self] Write ary in pointer’s contents as type. @example
ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4])
# File lib/ffi/pointer.rb, line 124 def write_array_of_type(type, writer, ary) size = FFI.type_size(type) tmp = self ary.each_with_index {|i, j| tmp.send(writer, i) tmp += size unless j == ary.length-1 # avoid OOB } self end
@param [String] str string to write @param [Numeric] len length of string to return @return [self] Write str in pointer’s contents, or first len bytes if len is not nil.
# File lib/ffi/pointer.rb, line 93 def write_string(str, len=nil) len = str.bytesize unless len # Write the string data without NUL termination put_bytes(0, str, 0, len) end
@param [String] str string to write @param [Numeric] len length of string to return @return [self] Write len first bytes of str in pointer’s contents.
Same as:
ptr.write_string(str, len) # with len not nil
# File lib/ffi/pointer.rb, line 84 def write_string_length(str, len) put_bytes(0, str, 0, len) end
Generated with the Darkfish Rdoc Generator 2.