class CStruct

Description ↑

CStruct is a simulation of the C language's struct. Its main purpose is to manipulate binary-data conveniently in Ruby.

Supported primitive types in CStruct ↑

More infomantion ↑

Constants

VERSION

version

Attributes

owner[RW]

Public Class Methods

__size__()
Alias for: size
align() click to toggle source

Return the align of a struct;the default is 1.

# File lib/cstruct/cstruct.rb, line 31
def align
  @options[:align]
end
endian() click to toggle source

Return the endian of a struct;the default is :little.

# File lib/cstruct/cstruct.rb, line 26
def endian
  @options[:endian] 
end
fields() click to toggle source

Return the fields of a struct.

# File lib/cstruct/cstruct.rb, line 36
def fields
  @fields
end
options(opts) click to toggle source

set the options of a struct.

# File lib/cstruct/cstruct.rb, line 21
def options opts
   @options.merge! opts
end
size() click to toggle source

Return the size of a struct;size similar to sizeof in C language.

Example:

class Point < CStruct
  int32:x
  int32:y
end

puts Point.size # or Point.__size__
# File lib/cstruct/cstruct.rb, line 50
def size
  @options[:layout_size]
end
Also aliased as: __size__
struct(symbol,&block) click to toggle source

Define a anonymous struct field.

Example:

in C:

struct Window
{
   int style;
   struct{
     int x;
     int y;
   }position;
};

use CStruct in Ruby:

class Window < CStruct
  int32:style
  struct :position do
    int32:x
    int32:y 
  end
end
# File lib/cstruct/cstruct.rb, line 451
def CStruct.struct symbol,&block
  struct_super  = self.ancestors[1]
  struct_class = Class.new(struct_super) 
  struct_class.instance_eval(&block)
  structfield symbol,struct_class,struct_class.__size__
end
union(symbol,&block) click to toggle source

Define a anonymous union field.

Example: in C:

struct U
{
   union{
     int x;
     int y;
   }value;    values is anonymous union's instance

};

use CStruct in Ruby:

class U < CStruct
  union:value do
    int32:x
    int32:y
  end
end
# File lib/cstruct/cstruct.rb, line 405
def CStruct.union symbol,&block
        union_super  = self.ancestors[1]
        union_class = Class.new(union_super) do
        def self.change_to_union #:nodoc:
            @fields.each_key  { |symbol| @fields[symbol].offset = 0 }

            max_field_size = @fields.values.inject(0)do |max,field| 
              dimension = field.dimension
              dimension_product = 1
        if dimension.is_a? Array
                dimension_product = dimension.inject(1){|m,d| m *= d }
        end       
              field_size = field.size* dimension_product
              max = (field_size> max ? field_size : max)
            end
            @options[:layout_size] = max_field_size
          end
        end    
    union_class.instance_eval(&block) 
    union_class.instance_eval{change_to_union}
    structfield symbol,union_class,union_class.size
end

Private Class Methods

do_arrayfield(field) click to toggle source
# File lib/cstruct/cstruct.rb, line 143
def self.do_arrayfield(field) 
  symbol = field.tag   
  define_method(symbol)       {  array_field_to_value(symbol) }
  define_method("#{symbol}=") { |value| value_to_arrayfield(symbol,value) }
end
do_arraystructfield(field,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 155
def self.do_arraystructfield(field,sclass) 
  symbol = field.tag    
  define_method(symbol)       { array_struct_field_to_value(symbol,sclass) }
  define_method("#{symbol}=") { |value| value_to_array_struct_field(symbol,sclass,value) }
end
do_field(field) click to toggle source
# File lib/cstruct/cstruct.rb, line 137
def self.do_field(field)
  symbol = field.tag   
  define_method(symbol)       { normal_field_to_value(symbol) }
  define_method("#{symbol}=") { |value| value_to_field(symbol,value) }
end
do_structfield(field,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 149
def self.do_structfield(field,sclass)
  symbol = field.tag 
  define_method(symbol)       { struct_field_to_value(symbol,sclass)}
  define_method("#{symbol}=") { |value| value_to_struct_field(symbol,sclass,value)}
end
field(symbol,fsize,fsign,dimension = nil) click to toggle source
# File lib/cstruct/cstruct.rb, line 63
def self.field(symbol,fsize,fsign,dimension = nil)
  field = Field.new(symbol,fsize,@options[:layout_size],fsign,dimension)
  @options[:layout_size] += field.byte_size
  @fields[symbol] = field     
  dimension.is_a?(Array) ? (do_arrayfield field):(do_field field)
end
inherited(clazz) click to toggle source
# File lib/cstruct/cstruct.rb, line 77
def self.inherited(clazz)
    clazz.init_class_variables
end
init_class_variables() click to toggle source
# File lib/cstruct/cstruct.rb, line 58
def self.init_class_variables  
  @fields = {}
  @options= { :layout_size =>0, :endian => :little, :align  => 1}
end
method_missing(method, *args) click to toggle source
Calls superclass method
# File lib/cstruct/cstruct.rb, line 81
def self.method_missing(method, *args)
  sclass = method_to_class_by_class self,method
  sclass = method_to_class_by_class Object,method unless sclass
        sclass = method_to_class_by_namespace method unless sclass
        sclass = method_to_class method unless sclass
  super unless sclass 
  is_cstruct = sclass.ancestors.select{|x| x == CStruct } 
  if is_cstruct
      symbol,dimension = *args
      structfield symbol,sclass,sclass.size,dimension
  else
    super
  end
end
method_to_class_by_class(clazz,method) click to toggle source
# File lib/cstruct/cstruct.rb, line 96
def self.method_to_class_by_class(clazz,method)
  method_string_or_symbol = RUBY_VERSION < '1.9' ? (method.to_s):(method)
  unless clazz.constants.include? method_string_or_symbol
    return nil
  end
  clazz.const_get method
end
signed(symbol,fsize,dimension) click to toggle source
# File lib/cstruct/cstruct.rb, line 165
def self.signed(symbol,fsize,dimension)
  field symbol,fsize,:signed,dimension
end
structfield(symbol,sclass,ssize,dimension = nil) click to toggle source
# File lib/cstruct/cstruct.rb, line 70
def self.structfield(symbol,sclass,ssize,dimension = nil)
  field = Field.new(symbol,ssize,@options[:layout_size],:struct,dimension)
  @options[:layout_size] += field.byte_size
  @fields[symbol] = field
  dimension.is_a?(Array) ? (do_arraystructfield field,sclass):(do_structfield field,sclass)        
end
unsigned(symbol,fsize,dimension) click to toggle source
# File lib/cstruct/cstruct.rb, line 161
def self.unsigned(symbol,fsize,dimension)
  field symbol,fsize,:unsigned,dimension
end

Public Instance Methods

<<(bindata) click to toggle source

Assign to CStruct's instance.

# File lib/cstruct/cstruct.rb, line 229
def << bindata
  count = @data.size < bindata.size ? @data.size : bindata.size
  (0...count).each do |i|
    Utils.string_setbyte @data,i,Utils.string_getbyte(bindata,i)
  end
end
__data__()
Alias for: data
__data__=(bindata)
Alias for: data=
__reset__()
Alias for: reset
data() click to toggle source

Return the data buffer of a CStruct's instance.

# File lib/cstruct/cstruct.rb, line 212
def data
  @data
end
Also aliased as: __data__
data=(bindata) click to toggle source

Assign to CStruct's instance.

# File lib/cstruct/cstruct.rb, line 223
def data= bindata
  raise 'Data Type Error!' unless bindata.is_a? String
  self << bindata
end
Also aliased as: __data__=
reset() click to toggle source

Fill the date buffer of a CStruct's instance with zero.

# File lib/cstruct/cstruct.rb, line 217
def reset
  (0...self.class.size).each { |i| Utils.string_setbyte @data,i, 0 }
  sync_to_owner
end
Also aliased as: __reset__

Private Instance Methods

array_field_to_value(symbol) click to toggle source
# File lib/cstruct/cstruct.rb, line 255
def array_field_to_value(symbol)
  make_array_normal_field(self.class.fields[symbol],self.class.endian)
end
array_struct_field_to_value(symbol,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 263
def array_struct_field_to_value(symbol,sclass)
  make_array_struct_field(self.class.fields[symbol],self.class.endian,sclass)
end
buffer_to_single_struct(sclass,ssize,soffset,iterator,sendian,fsign) click to toggle source
# File lib/cstruct/cstruct.rb, line 365
def buffer_to_single_struct(sclass,ssize,soffset,iterator,sendian,fsign)
  value =  sclass.new
  value << @data[soffset + iterator * ssize,ssize]

  value.owner << [@data,soffset + iterator * ssize,ssize]

  unless self.owner.empty?
    value.owner += self.owner
  end   
  value
end
buffer_to_single_value(fsize,foffset,iterator,sendian,fsign) click to toggle source
# File lib/cstruct/cstruct.rb, line 355
def buffer_to_single_value(fsize,foffset,iterator,sendian,fsign)
  CStruct::Utils::unpack(@data[foffset + iterator * fsize,fsize],sendian,fsize,fsign)
end
buffer_to_structs(field,sendian,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 377
def buffer_to_structs(field,sendian,sclass)
  (0...field.byte_size/field.size).map do |i|
    buffer_to_single_struct(sclass,field.size,field.offset,i,sendian,field.sign)
  end
end
buffer_to_values(field,sendian) click to toggle source
# File lib/cstruct/cstruct.rb, line 359
def buffer_to_values(field,sendian)
  (0...field.byte_size/field.size).map do |i|
    buffer_to_single_value(field.size,field.offset,i,sendian,field.sign)
  end
end
make_array_normal_field(field,sendian,sclass = nil) click to toggle source
# File lib/cstruct/cstruct.rb, line 318
def make_array_normal_field(field,sendian,sclass = nil)
  dataref= @data
  objref = self
  value  = buffer_to_values field,sendian
  
  def value.metaclass  
    class<<self; self; end
  end
  
  value.metaclass.__send__ :define_method,:[]= do |i,v|
    bin_string = Utils::pack [v],sendian,field.size,field.sign
    Utils.buffer_setbytes dataref,bin_string,field.offset + i * field.size
    objref.sync_to_owner
  end

  case field.size
  when 1
    value.metaclass.__send__(:define_method,:to_cstr){ value.pack("C#{value.index(0)}") }
  when 2
    if  RUBY_VERSION > "1.9"
      utf_endian = {:little=>"LE",:big=>"BE"} 
      value.metaclass.__send__ :define_method,:to_wstr do 
        value.pack("S#{value.index(0)}").force_encoding("UTF-16#{utf_endian[sendian]}")
      end   
    end 
  when 4
    value.metaclass.__send__ :define_method,:to_wstr do 
      value.pack("L#{value.index(0)}").force_encoding("UTF-32#{utf_endian[sendian]}")   
    end     
  end  
  value
end
make_array_struct_field(field,sendian,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 351
def make_array_struct_field(field,sendian,sclass)
  buffer_to_structs field,sendian,sclass
end
make_normal_field(field,sendian,sclass = nil) click to toggle source
# File lib/cstruct/cstruct.rb, line 304
def make_normal_field(field,sendian,sclass = nil) 
  Utils::unpack(@data[field.offset,field.size],sendian,field.size,field.sign)
end
make_struct_field(field,sendian,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 308
def make_struct_field(field,sendian,sclass)
  value = sclass.new
  value <<  @data[field.offset,field.size]
  value.owner << [@data,field.offset,field.size]
  unless self.owner.empty? 
    value.owner += self.owner
  end
  value
end
normal_field_to_value(symbol) click to toggle source
# File lib/cstruct/cstruct.rb, line 251
def normal_field_to_value(symbol)
  make_normal_field(self.class.fields[symbol],self.class.endian)
end
struct_field_to_value(symbol,sclass) click to toggle source
# File lib/cstruct/cstruct.rb, line 259
def struct_field_to_value(symbol,sclass)
  make_struct_field(self.class.fields[symbol],self.class.endian,sclass)
end
value_to_array_struct_field(symbol,sclass,value) click to toggle source
# File lib/cstruct/cstruct.rb, line 300
def value_to_array_struct_field(symbol,sclass,value)
  raise "No Implement!(CStruct,version:#{CStruct::VERSION})" 
end
value_to_arrayfield(symbol,value) click to toggle source
# File lib/cstruct/cstruct.rb, line 279
def value_to_arrayfield(symbol,value)  
  field = self.class.fields[symbol]
  array_length = field.byte_size/field.size

  if field.size == 1 and value.is_a? String   
    if value.length >= array_length
      puts "WARNING: \"#{value}\".length(#{value.length}) >= #{symbol}.length(#{dimension})!!"
    end  

    value = value[0...array_length-1]
    CStruct::Utils.buffer_setbytes @data,value,field.offset
    sync_to_owner
  else 
    raise "No Implement!(CStruct,version:#{CStruct::VERSION})" 
  end
end
value_to_field(symbol,value) click to toggle source
# File lib/cstruct/cstruct.rb, line 267
def value_to_field(symbol,value)
  dataref   = @data
  onwerref  = @owner
  self.class.class_eval do
    field = @fields[symbol]
    bin_string = CStruct::Utils::pack [value],@options[:endian],field.byte_size,field.sign
    CStruct::Utils.buffer_setbytes dataref,bin_string,field.offset
  end   
  sync_to_owner
end
value_to_struct_field(symbol,sclass,value) click to toggle source
# File lib/cstruct/cstruct.rb, line 296
def value_to_struct_field(symbol,sclass,value)
  raise "No Implement!(CStruct,version:#{CStruct::VERSION})" 
end