diff options
Diffstat (limited to 'ext/dl/lib/dl/struct.rb')
-rw-r--r-- | ext/dl/lib/dl/struct.rb | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/ext/dl/lib/dl/struct.rb b/ext/dl/lib/dl/struct.rb new file mode 100644 index 0000000000..5c0775277e --- /dev/null +++ b/ext/dl/lib/dl/struct.rb @@ -0,0 +1,203 @@ +require 'dl' +require 'dl/pack.rb' + +module DL + class CStruct + def CStruct.entity_class() + CStructEntity + end + end + + class CUnion + def CUnion.entity_class() + CUnionEntity + end + end + + module CStructBuilder + def create(klass, types, members) + new_class = Class.new(klass){ + entity = nil + define_method(:initialize){|addr| + entity = klass.entity_class.new(addr, types) + entity.assign_names(members) + } + define_method(:to_ptr){ entity } + define_method(:to_i){ entity.to_i } + members.each{|name| + define_method(name){ entity[name] } + define_method(name + "="){|val| entity[name] = val } + } + } + size = klass.entity_class.size(types) + new_class.module_eval(<<-EOS) + def new_class.size() + #{size} + end + def new_class.malloc() + addr = DL.malloc(#{size}) + new(addr) + end + EOS + return new_class + end + module_function :create + end + + class CStructEntity < CPtr + include PackInfo + include ValueUtil + + def CStructEntity.malloc(types, func = nil) + addr = DL.malloc(CStructEntity.size(types)) + CStructEntity.new(addr, types, func) + end + + def CStructEntity.size(types) + offset = 0 + types.each_with_index{|t,i| + orig_offset = offset + if( t.is_a?(Array) ) + offset = PackInfo.align(orig_offset, PackInfo::ALIGN_MAP[TYPE_VOIDP]) + size = offset - orig_offset + offset += (PackInfo::SIZE_MAP[t[0]] * t[1]) + else + offset = PackInfo.align(orig_offset, PackInfo::ALIGN_MAP[t]) + size = offset - orig_offset + offset += PackInfo::SIZE_MAP[t] + end + } + offset = PackInfo.align(offset, PackInfo::ALIGN_MAP[TYPE_VOIDP]) + offset + end + + def initialize(addr, types, func = nil) + set_ctypes(types) + super(addr, @size, func) + end + + def assign_names(members) + @members = members + end + + def set_ctypes(types) + @ctypes = types + @offset = [] + offset = 0 + types.each_with_index{|t,i| + orig_offset = offset + if( t.is_a?(Array) ) + offset = align(orig_offset, ALIGN_MAP[TYPE_VOIDP]) + else + offset = align(orig_offset, ALIGN_MAP[t]) + end + size = offset - orig_offset + @offset[i] = offset + if( t.is_a?(Array) ) + offset += (SIZE_MAP[t[0]] * t[1]) + else + offset += SIZE_MAP[t] + end + } + offset = align(offset, ALIGN_MAP[TYPE_VOIDP]) + @size = offset + end + + def [](name) + idx = @members.index(name) + if( idx.nil? ) + raise(ArgumentError, "no such member: #{name}") + end + ty = @ctypes[idx] + if( ty.is_a?(Array) ) + r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1]) + else + r = super(@offset[idx], SIZE_MAP[ty.abs]) + end + packer = Packer.new([ty]) + val = packer.unpack([r]) + case ty + when Array + case ty[0] + when TYPE_VOIDP + val = val.collect{|v| CPtr.new(v)} + end + when TYPE_VOIDP + val = CPtr.new(val[0]) + else + val = val[0] + end + if( ty.is_a?(Integer) && (ty < 0) ) + return unsigned_value(val, ty) + elsif( ty.is_a?(Array) && (ty[0] < 0) ) + return val.collect{|v| unsigned_value(v,ty[0])} + else + return val + end + end + + def []=(name, val) + idx = @members.index(name) + if( idx.nil? ) + raise(ArgumentError, "no such member: #{name}") + end + ty = @ctypes[idx] + packer = Packer.new([ty]) + val = wrap_arg(val, ty, []) + buff = packer.pack([val].flatten()) + super(@offset[idx], buff.size, buff) + if( ty.is_a?(Integer) && (ty < 0) ) + return unsigned_value(val, ty) + elsif( ty.is_a?(Array) && (ty[0] < 0) ) + return val.collect{|v| unsigned_value(v,ty[0])} + else + return val + end + end + + def to_s() + super(@size) + end + end + + class CUnionEntity < CStruct + include PackInfo + + def CUnionEntity.malloc(types) + addr = DL.malloc(CUnionEntity.size(types)) + CUnionEntity.new(addr, types, func) + end + + def CUnionEntity.size(types) + size = 0 + types.each_with_index{|t,i| + if( t.is_a?(Array) ) + tsize = PackInfo::SIZE_MAP[t[0]] * t[1] + else + tsize = PackInfo::SIZE_MAP[t] + end + if( tsize > size ) + size = tsize + end + } + end + + def set_ctypes(types) + @ctypes = types + @offset = [] + @size = 0 + types.each_with_index{|t,i| + @offset[i] = 0 + if( t.is_a?(Array) ) + size = SIZE_MAP[t[0]] * t[1] + else + size = SIZE_MAP[t] + end + if( size > @size ) + @size = size + end + } + end + end +end + |