FFI::Pointer

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.

Autorelease

A pointer object may autorelease his contents when freed (by default). This behaviour may be changed with {autorelease=} method.

Constants

NULL

NULL pointer

SIZE

Pointer size

Public Class Methods

new(p1, p2 = v2) click to toggle source

@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;
}
size() click to toggle source

Return the size of a pointer on the current platform, in bytes @return [Numeric]

# File lib/ffi/pointer.rb, line 30
def self.size
  SIZE
end

Public Instance Methods

ptr + offset click to toggle source
@param [Numeric] offset
@return [Pointer]
Return a new {Pointer} from an existing pointer and an +offset+.
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);
}
ptr == other click to toggle source
@param [Pointer] other
Check equality between +self+ and +other+. Equality is tested on {#address}.
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;
}
address click to toggle source
@return [Numeric] pointer's base address
Return +self+'s base address (alias: #to_i).
static VALUE
ptr_address(VALUE self)
{
    Pointer* ptr;
    
    Data_Get_Struct(self, Pointer, ptr);

    return ULL2NUM((uintptr_t) ptr->memory.address);
}
Also aliased as: to_i
autorelease = autorelease click to toggle source
@param [Boolean] autorelease
@return [Boolean] +autorelease+
Set +autorelease+ attribute. See also Autorelease section.
static VALUE
ptr_autorelease(VALUE self, VALUE autorelease)
{
    Pointer* ptr;

    Data_Get_Struct(self, Pointer, ptr);
    ptr->autorelease = autorelease == Qtrue;

    return autorelease;
}
autorelease? click to toggle source
@return [Boolean]
Get +autorelease+ attribute. See also Autorelease section.
static VALUE
ptr_autorelease_p(VALUE self)
{
    Pointer* ptr;

    Data_Get_Struct(self, Pointer, ptr);
    
    return ptr->autorelease ? Qtrue : Qfalse;
}
free click to toggle source
@return [self]
Free memory pointed by +self+.
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;
}
initialize_copy(other) click to toggle source
@param [Pointer] other source for cloning or dupping
@return [self]
@raise {RuntimeError} if +other+ is an unbounded memory area, or is unreable/unwritable
@raise {NoMemError} if failed to allocate memory for new object
DO NOT CALL THIS METHOD.

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;
}
inspect click to toggle source
@return [String]
Inspect pointer object.
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);
}
null? click to toggle source
@return [Boolean]
Return +true+ if +self+ is a {NULL} pointer.
static VALUE
ptr_null_p(VALUE self)
{
    Pointer* ptr;

    Data_Get_Struct(self, Pointer, ptr);

    return ptr->memory.address == NULL ? Qtrue : Qfalse;
}
order(p1) click to toggle source

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;
    }
}
read_array_of_type(type, reader, length) click to toggle source

@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.write_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
read_string(len=nil) click to toggle source

@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
read_string_length(len) click to toggle source

@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
read_string_to_null() click to toggle source

@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
slice(offset, length) click to toggle source
@param [Numeric] offset
@param [Numeric] length
@return [Pointer]
Return a new {Pointer} from an existing one. This pointer points on same contents
from +offset+ for a length +length+.
static VALUE
ptr_slice(VALUE self, VALUE rbOffset, VALUE rbLength)
{
    return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength));
}
to_i() click to toggle source
Alias for: address
inspect click to toggle source
@return [String]
Inspect pointer object.
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);
}
write_array_of_type(type, writer, ary) click to toggle source

@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
write_string(str, len=nil) click to toggle source

@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
write_string_length(str, len) click to toggle source

@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

[Validate]

Generated with the Darkfish Rdoc Generator 2.