hexstruct/hex_struct.rb
# IE Control Library Ver.0.1.0 2003/11/30
# Copyright (C) 2005 Oka Yasushi <yac@tech-notes.dyndns.org>
#
# You may redistribute it and/or modify it under the same license terms as Ruby.
class HexStruct
class NoMemberError < StandardError
end
class SizeError < StandardError
end
class FormatError < StandardError
end
STRUCT = [
[:len, 1], # lenメンバは1バイト
[:code, 2], # codeメンバは2バイト
[:data, -1] # dataメンバは不定長
]
def HexStruct::size()
total_size = 0
self::STRUCT.each {|sym, elem_size|
if (sym == nil) or (elem_size == nil)
raise FormatError, "Illegal STRUCT Format.", caller
end
if elem_size > 0
total_size += elem_size
end
}
total_size
end
def initialize(hex_str=nil)
unless hex_str
hex_str = "00" * self.class::size()
end
@item_list = []
@cache = {}
to_itemlist(hex_str)
end
def byte_size()
@item_list.flatten.join('').size / 2
end
alias size byte_size
def size_of(member_name)
member_check(member_name)
item_size, item_data = @cache[member_name]
if item_size > 0
item_size
else
item_data.size / 2
end
end
def data_of(member_name)
member_check(member_name)
item_size, item_data = @cache[member_name]
item_data
end
def write_to(member_name, data)
member_check(member_name)
item_size, item_data = @cache[member_name]
if data.is_a?(HexStruct) or data.is_a?(Array)
index = @item_list.index(item_data)
@item_list[index] = data
@cache[member_name] = [item_size, @item_list[index]]
return data
elsif data.is_a?(Integer)
current_size = item_data.size
set_param = sprintf("%0#{current_size}X", data)
item_data.replace(set_param)
else
if (item_size > 0) and (item_size * 2 != data.size)
raise SizeError, "unmatch data size.", caller
end
item_data.replace(data)
end
end
def ==(other)
self.to_str == other.to_s
end
def to_str
str = ""
@item_list.flatten.each {|item|
str += item.to_s
}
str
end
alias to_s to_str
def to_ary
arr = []
@item_list.each {|item|
if item.is_a?(String)
arr.push item
elsif item.is_a?(Array)
sub_arr = []
item.each {|sub_item|
sub_arr.push sub_item.to_a
}
arr.push sub_arr
else
arr.push item.to_ary
end
}
arr
end
alias to_a to_ary
def inspect()
arr = []
self.class::STRUCT.each {|member_sym, item_size|
item = data_of(member_sym.to_s)
if item.is_a?(String)
arr.push "#{member_sym}:#{item.to_s}"
else
arr.push "#{member_sym}:<#{item.inspect}>"
end
}
"#{self.class}:[#{arr.join(", ")}]"
end
private
def to_itemlist(hex_str)
offset = 0
@cache.clear
@item_list.clear
self.class::STRUCT.each {|member_sym, item_size|
if (member_sym == nil) or (item_size == nil)
raise FormatError, "Illegal STRUCT Format.", caller
end
if item_size > 0
item_data = hex_str[(offset * 2), item_size * 2]
if (item_data == "") or (item_data == nil)
raise SizeError, "unmatch data size.", caller
end
offset += item_size
else
item_data = hex_str[(offset * 2)..-1]
offset += item_data.size / 2
end
@item_list.push item_data
@cache[member_sym.to_s] = [item_size, item_data]
}
if offset != hex_str.size / 2
raise SizeError, "unmatch data size.", caller
end
end
def method_missing(method_sym, *params)
#puts "method_missing()"; p [method_sym, *params]
if method_sym.to_s =~ /\w=$/
member_name = method_sym.to_s.gsub(/=$/, "")
write_to(member_name, *params)
else
member_name = method_sym.to_s
set_flag = false
end
unless @cache.key?(member_name)
hex_str = self.to_s
if hex_str.methods.include?(member_name)
return hex_str.send(method_sym, *params)
else
raise NoMemberError, "'#{member_name}' is not member.", caller
end
end
item_size, item_data = @cache[member_name]
item_data
end
def member_check(member_name)
unless @cache.key?(member_name)
raise NoMemberError, "#{member_name} is not member.", caller
end
end
end