class DataView

Public Class Methods

initialize(buffer, offset, size, endianess:) click to toggle source

Constructs a new DataView that provides a view of the data in a ArrayBuffer.

Example:

buffer = ArrayBuffer.new(10)
buffer[1] = 20
buffer[2] = 55
view = DataView.new(buffer, 1, endianess: :little)
view.getU8() == ( 20 & (55 << 8) ) # true

Or:

view = DataView.new(buffer, 1) # default endianess is "big endian"
view.getU8() == ( (20 << 8) | 55 ) # true

@param buffer [ArrayBuffer] The array buffer where to operate @param offset [Integer] Optional. The byte offset from the array buffer. The

default value is zero

@param size [Integer] Optional. The size in bytes that this DataView can

see into the array buffer. If left blank, the current size of the array
buffer will be used

@param endianess [:big, :little] Optional. The default value is big

static VALUE
t_dv_initialize(int argc, VALUE *argv, VALUE self) {
  DECLAREDV(self);
  VALUE bb_obj;
  VALUE offset;
  VALUE size;
  VALUE kwargs;
  static ID keyword_ids[] = { 0 };

  rb_scan_args(argc, argv, "12:", &bb_obj, &offset, &size, &kwargs);

  DECLAREBB(bb_obj);

  int size_val = NIL_P(size) ? (int)bb->size : NUM2INT(size);
  if (size_val < 0)
    size_val += (int)bb->size;
  if (size_val < 0)
    rb_raise(rb_eArgError, "calculated size is negative: %d", size_val);

  int offset_val = NIL_P(offset) ? 0 : NUM2INT(offset);
  if (offset_val < 0)
    offset_val += (int)bb->size;
  if (offset_val < 0)
    rb_raise(rb_eArgError, "calculated offset is negative: %d", offset_val);

  dv->offset = (unsigned long)offset_val;
  dv->size = (unsigned long)size_val;
  dv->bb_obj = bb_obj;

  if (!keyword_ids[0]) {
    keyword_ids[0] = idEndianess;
  }

  if (!NIL_P(kwargs)) {
    VALUE endianess;
    rb_get_kwargs(kwargs, keyword_ids, 0, 1, &endianess);
    if (endianess != Qundef) {
      Check_Type(endianess, T_SYMBOL);
      ID id = SYM2ID(endianess);
      if (id == idLittle)
        dv->flags |= FLAG_LITTLE_ENDIAN;
      else if (id != idBig)
        rb_raise(rb_eArgError, "endianess must be either :big or :little");
    }
  }

  return self;
}

Public Instance Methods

each() click to toggle source
static VALUE
t_dv_each(VALUE self) {
  DECLAREDV(self);
  DECLAREBB(dv->bb_obj);

  int size = dv->size;
  if (size + dv->offset >= bb->size)
    size = bb->size - dv->offset;

  if (rb_block_given_p()) {
    for (int i = 0; i < size; i++) {
      unsigned int val = (unsigned int)bb->ptr[i + dv->offset];
      rb_yield(UINT2NUM(val));
    }
  } else {
    rb_raise(rb_eArgError, "no block given");
  }
  return self;
}
endianess() click to toggle source
static VALUE
t_dv_endianess(VALUE self) {
  DECLAREDV(self);
  return CHECK_LITTLEENDIAN(dv) ?
    ID2SYM(idLittle) :
    ID2SYM(idBig);
}
getBit(p1) click to toggle source

Reads a bit at index.

This method differs from the other in that the index is given in bits, not in bytes. Thus it's possible to read from index 0 to +(size * 8) - 1+

@return [Integer] Either 0 or 1

static VALUE
t_dv_getbit(VALUE self, VALUE index) {
  DECLAREDV(self); DECLAREBB(dv->bb_obj);
  int idx = NUM2INT(index);
  if (idx < 0)
    idx += (int)dv->size * 8;
  if (idx < 0 || idx >= dv->size * 8)
    rb_raise(rb_eArgError, "index out of bounds: %d", idx);

  unsigned int bit_idx = ((unsigned int)idx) & 7;
  unsigned int byte_idx = (((unsigned int)idx) >> 3) + dv->offset;
  unsigned char bit_mask = 1 << bit_idx;

  CHECKBOUNDSBB(byte_idx);
  return (bb->ptr[byte_idx] & bit_mask) ? UINT2NUM(1) : UINT2NUM(0);
}
getU16(p1) click to toggle source

Reads two bytes starting at index as an +unsigned short+

@return [Integer] Integer between 0 and 65535

static VALUE
t_dv_getu16(VALUE self, VALUE index) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
  CHECKBOUNDSBB(idx0);
  CHECKBOUNDSBB(idx1);
  unsigned short val = 0;
  if (CHECK_LITTLEENDIAN(dv)) {
    val |= bb->ptr[idx0];
    val |= bb->ptr[idx1] << 8;
  } else {
    val |= bb->ptr[idx0] << 8;
    val |= bb->ptr[idx1];
  }
  return UINT2NUM(val);
}
getU24(p1) click to toggle source

Reads three bytes starting at index as a 3 bytes long unsigned integer

@return [Integer] Integer between 0 and 16777215

static VALUE
t_dv_getu24(VALUE self, VALUE index) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
  unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
  CHECKBOUNDSBB(idx0);
  CHECKBOUNDSBB(idx2);
  unsigned int val = 0;
  if (CHECK_LITTLEENDIAN(dv)) {
    val |= bb->ptr[idx0];
    val |= bb->ptr[idx1] << 8;
    val |= bb->ptr[idx2] << 16;
  } else {
    val |= bb->ptr[idx0] << 16;
    val |= bb->ptr[idx1] << 8;
    val |= bb->ptr[idx2];
  }
  return UINT2NUM(val);
}
getU32(p1) click to toggle source

Reads four bytes starting at index as a 4 bytes long unsigned integer

@return [Integer] Integer between 0 and 4294967295

static VALUE
t_dv_getu32(VALUE self, VALUE index) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
  unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
  unsigned int idx3 = dv->offset + (unsigned int)idx + 3;
  CHECKBOUNDSBB(idx0);
  CHECKBOUNDSBB(idx3);
  unsigned int val = 0;
  if (CHECK_LITTLEENDIAN(dv)) {
    val |= bb->ptr[idx0];
    val |= bb->ptr[idx1] << 8;
    val |= bb->ptr[idx2] << 16;
    val |= bb->ptr[idx3] << 24;
  } else {
    val |= bb->ptr[idx0] << 24;
    val |= bb->ptr[idx1] << 16;
    val |= bb->ptr[idx2] << 8;
    val |= bb->ptr[idx3];
  }
  return UINT2NUM(val);
}
getU8(p1) click to toggle source

Reads the byte at index as an +unsigned char+

@return [Integer] Integer between 0 and 255

static VALUE
t_dv_getu8(VALUE self, VALUE index) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int real_idx = dv->offset + (unsigned int)idx;
  CHECKBOUNDSBB(real_idx);
  return UINT2NUM(bb->ptr[real_idx]);
}
length()
Alias for: size
length=(p1)

Defined the new offset for the DataView.

Changing the size does not affect the offset. If passed a negative value, it will be summed with the underlying buffer size. The final value must not be lower than zero.

@param size [Integer] The new size. Must be zero or greater

Alias for: size=
offset() click to toggle source
static VALUE
t_dv_offset(VALUE self) {
  DECLAREDV(self);
  return UINT2NUM(dv->offset);
}
offset=(p1) click to toggle source

Defined the new offset for the DataView.

Changing the offset does not affect the size. If passed a negative value, it will be summed with the underlying buffer size. The final value must not be lower than zero.

@param offset [Integer] The new offset

static VALUE
t_dv_setoffset(VALUE self, VALUE offset) {
  DECLAREDV(self);
  DECLAREBB(dv->bb_obj);
  int offset_val = NIL_P(offset) ? 0 : NUM2INT(offset);
  if (offset_val < 0)
    offset_val += (int)bb->size;
  if (offset_val < 0)
    rb_raise(rb_eArgError, "calculated offset is negative: %d", offset_val);

  dv->offset = (unsigned long)offset_val;
  return self;
}
setBytes(p1, p2) click to toggle source
static VALUE
t_dv_setbytes(VALUE self, VALUE index, VALUE bytes) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  CHECKBOUNDSBB(idx0);

  if (RB_TYPE_P(bytes, T_ARRAY)) {
    const unsigned int length = (unsigned int)rb_array_len(bytes);
    const VALUE* items = rb_array_const_ptr(bytes);
    CHECKBOUNDSBB(idx0 + length);

    for (unsigned int i = 0; i < length; i++) {
      if (!RB_FIXNUM_P(items[i]))
        rb_raise(rb_eRuntimeError, "array contains non fixnum value at index %d", i);
      int num = NUM2INT(items[i]);
      ADJUSTBOUNDS(num, 0xFF);
      bb->ptr[idx0 + i] = (unsigned char)num;
    }
  } else if (RB_TYPE_P(bytes, T_STRING)) {
    const char *str_ptr = RSTRING_PTR(bytes);
    const unsigned int length = (unsigned int)RSTRING_LEN(bytes);
    CHECKBOUNDSBB(idx0 + length);

    for (unsigned int i = 0; i < length; i++) {
      bb->ptr[idx0 + i] = (unsigned char)str_ptr[i];
    }
  } else if (RB_TYPE_P(bytes, T_DATA) &&
    (CLASS_OF(bytes) == cArrayBuffer || CLASS_OF(bytes) == cDataView)) {
    unsigned int length;
    const char *src_bytes;
    if (CLASS_OF(bytes) == cArrayBuffer) {
      struct LLC_ArrayBuffer *src_bb = (struct LLC_ArrayBuffer*)rb_data_object_get(bytes);
      length = src_bb->size;
      src_bytes = (const char*)src_bb->ptr;
    } else {
      struct LLC_DataView *src_dv = (struct LLC_DataView*)rb_data_object_get(bytes);
      struct LLC_ArrayBuffer *src_bb = (struct LLC_ArrayBuffer*)rb_data_object_get(src_dv->bb_obj);
      length = src_dv->size;
      src_bytes = (const char*)(src_bb->ptr + (size_t)src_dv->offset);
      if (src_dv->offset >= src_bb->size)
        rb_raise(rb_eRuntimeError, "offset exceeds the underlying source buffer size");
      if (src_dv->offset + length >= src_bb->size)
        rb_raise(rb_eRuntimeError, "offset + size exceeds the underlying source buffer size");
    }

    CHECKBOUNDSBB(idx0 + length);
    memcpy((void*)(bb->ptr + (size_t)idx0), src_bytes, (size_t)length);
  } else {
    rb_raise(rb_eArgError, "Invalid type: %+"PRIsVALUE, CLASS_OF(bytes));
  }

  return self;
}
setU16(p1, p2) click to toggle source

Interprets two bytes starting at index and sets them an unsigned value

Values lower than zero will be set to 0 and values greater than 65535 will be capped.

static VALUE
t_dv_setu16(VALUE self, VALUE index, VALUE value) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
  CHECKBOUNDSBB(idx0);
  CHECKBOUNDSBB(idx1);
  int val = NUM2INT(value);
  ADJUSTBOUNDS(val, 0xFFFF);
  unsigned int uval = (unsigned int)val;
  if (CHECK_LITTLEENDIAN(dv)) {
    bb->ptr[idx0] = (unsigned char)(uval & 0xFF);
    bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
  } else {
    bb->ptr[idx0] = (unsigned char)((uval >> 8) & 0xFF);
    bb->ptr[idx1] = (unsigned char)(uval & 0xFF);
  }
  return self;
}
setU24(p1, p2) click to toggle source

Interprets three bytes starting at index and sets them an unsigned value

Values lower than zero will be set to 0 and values greater than 16777215 will be capped.

static VALUE
t_dv_setu24(VALUE self, VALUE index, VALUE value) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
  unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
  CHECKBOUNDSBB(idx0);
  CHECKBOUNDSBB(idx2);
  int val = NUM2INT(value);
  ADJUSTBOUNDS(val, 0xFFFFFF);
  unsigned int uval = (unsigned int)val;
  if (CHECK_LITTLEENDIAN(dv)) {
    bb->ptr[idx0] = (unsigned char)(uval & 0xFF);
    bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
    bb->ptr[idx2] = (unsigned char)((uval >> 16) & 0xFF);
  } else {
    bb->ptr[idx0] = (unsigned char)((uval >> 16) & 0xFF);
    bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
    bb->ptr[idx2] = (unsigned char)(uval & 0xFF);
  }
  return self;
}
setU32(p1, p2) click to toggle source

Interprets four bytes starting at index and sets them an unsigned value

Values lower than zero will be set to 0 and values greater than 4294967295 will be capped.

static VALUE
t_dv_setu32(VALUE self, VALUE index, VALUE value) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
  unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
  unsigned int idx3 = dv->offset + (unsigned int)idx + 3;
  CHECKBOUNDSBB(idx0);
  CHECKBOUNDSBB(idx3);
  long val = NUM2LONG(value);
  ADJUSTBOUNDS(val, 0xFFFFFFFF);
  unsigned long uval = (unsigned long)val;
  if (CHECK_LITTLEENDIAN(dv)) {
    bb->ptr[idx0] = (unsigned char)(uval & 0xFF);
    bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
    bb->ptr[idx2] = (unsigned char)((uval >> 16) & 0xFF);
    bb->ptr[idx3] = (unsigned char)((uval >> 24) & 0xFF);
  } else {
    bb->ptr[idx0] = (unsigned char)((uval >> 24) & 0xFF);
    bb->ptr[idx1] = (unsigned char)((uval >> 16) & 0xFF);
    bb->ptr[idx2] = (unsigned char)((uval >> 8) & 0xFF);
    bb->ptr[idx3] = (unsigned char)(uval & 0xFF);
  }
  return self;
}
setU8(p1, p2) click to toggle source

Interprets one byte at index and assigns it an unsigned value

Values lower than zero will be set to 0 and values greater than 255 will be capped.

static VALUE
t_dv_setu8(VALUE self, VALUE index, VALUE value) {
  DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
  unsigned int idx0 = dv->offset + (unsigned int)idx;
  CHECKBOUNDSBB(idx0);
  int val = NUM2INT(value);
  ADJUSTBOUNDS(val, 0xFF);
  bb->ptr[idx0] = (unsigned char)val;
  return self;
}
size() click to toggle source
static VALUE
t_dv_size(VALUE self) {
  DECLAREDV(self);
  return UINT2NUM(dv->size);
}
Also aliased as: length
size=(p1) click to toggle source

Defined the new offset for the DataView.

Changing the size does not affect the offset. If passed a negative value, it will be summed with the underlying buffer size. The final value must not be lower than zero.

@param size [Integer] The new size. Must be zero or greater

static VALUE
t_dv_setsize(VALUE self, VALUE size) {
  DECLAREDV(self);
  DECLAREBB(dv->bb_obj);
  int size_val = NIL_P(size) ? (int)bb->size : NUM2INT(size);
  if (size_val < 0)
    size_val += (int)bb->size;
  if (size_val < 0)
    rb_raise(rb_eArgError, "calculated size is negative: %d", size_val);

  dv->size = (unsigned long)size_val;
  return self;
}
Also aliased as: length=
to_s() click to toggle source
VALUE
t_dv_to_s(VALUE self) {
  DECLAREDV(self);
  DECLAREBB(dv->bb_obj);

  const char *ptr = (const char*)bb->ptr + (size_t)dv->offset;
  size_t len = (size_t)dv->size;

  return rb_str_new(ptr, len);
}