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 94 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 38 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 52 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 61 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 112 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 81 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 72 def write_string_length(str, len) put_bytes(0, str, 0, len) end
Generated with the Darkfish Rdoc Generator 2.