lib/bindata/int.rb in bindata-1.1.0 vs lib/bindata/int.rb in bindata-1.2.0

- old
+ new

@@ -7,61 +7,73 @@ module Int #:nodoc: all class << self def define_class(nbits, endian, signed) name = class_name(nbits, endian, signed) unless BinData.const_defined?(name) - int_type = (signed == :signed) ? 'int' : 'uint' - creation_method = "create_#{int_type}_methods" - BinData.module_eval <<-END class #{name} < BinData::BasePrimitive - register(self.name, self) - Int.#{creation_method}(self, #{nbits}, :#{endian.to_s}) + register_self + Int.define_methods(self, #{nbits}, :#{endian}, :#{signed}) end END end + BinData.const_get(name) end def class_name(nbits, endian, signed) endian_str = (endian == :big) ? "be" : "le" base = (signed == :signed) ? "Int" : "Uint" "#{base}#{nbits}#{endian_str}" end - def create_uint_methods(int_class, nbits, endian) + def define_methods(int_class, nbits, endian, signed) raise "nbits must be divisible by 8" unless (nbits % 8).zero? - min = 0 - max = (1 << nbits) - 1 + int_class.module_eval <<-END + #--------------- + private - clamp = create_clamp_code(min, max) - read = create_read_code(nbits, endian) - to_binary_s = create_to_binary_s_code(nbits, endian) + def _assign(val) + #{create_clamp_code(nbits, signed)} + super(val) + end - define_methods(int_class, nbits / 8, clamp, read, to_binary_s) - end + def _do_num_bytes + #{nbits / 8} + end - def create_int_methods(int_class, nbits, endian) - raise "nbits must be divisible by 8" unless (nbits % 8).zero? + def sensible_default + 0 + end - max = (1 << (nbits - 1)) - 1 - min = -(max + 1) + def value_to_binary_string(val) + #{create_clamp_code(nbits, signed)} + #{create_int2uint_code(nbits) if signed == :signed} + #{create_to_binary_s_code(nbits, endian)} + end - clamp = create_clamp_code(min, max) - read = create_read_code(nbits, endian) - to_binary_s = create_to_binary_s_code(nbits, endian) + def read_and_return_value(io) + val = #{create_read_code(nbits, endian)} + #{create_uint2int_code(nbits) if signed == :signed} + end + END + end - int2uint = create_int2uint_code(nbits) - uint2int = create_uint2int_code(nbits) + #------------- + private - define_methods(int_class, nbits / 8, clamp, read, to_binary_s, - int2uint, uint2int) - end + def create_clamp_code(nbits, signed) + if signed == :signed + max = (1 << (nbits - 1)) - 1 + min = -(max + 1) + else + min = 0 + max = (1 << nbits) - 1 + end - def create_clamp_code(min, max) "val = (val < #{min}) ? #{min} : (val > #{max}) ? #{max} : val" end def create_int2uint_code(nbits) "val = val & #{(1 << nbits) - 1}" @@ -73,57 +85,36 @@ "val = ((val & #{1 << (nbits - 1)}).zero?) ? " + "val & #{mask} : -(((~val) & #{mask}) + 1)" end def create_read_code(nbits, endian) - # determine "word" size and unpack directive - if (nbits % 32).zero? - bytes_per_word = 4 - d = (endian == :big) ? 'N' : 'V' - elsif (nbits % 16).zero? - bytes_per_word = 2 - d = (endian == :big) ? 'n' : 'v' - else - bytes_per_word = 1 - d = 'C' - end - - bits_per_word = bytes_per_word * 8 + bits_per_word = bytes_per_word(nbits) * 8 nwords = nbits / bits_per_word nbytes = nbits / 8 idx = (0 ... nwords).to_a idx.reverse! if (endian == :big) - unpack_str = "a = io.readbytes(#{nbytes}).unpack('#{d * nwords}')" - parts = (0 ... nwords).collect do |i| - i.zero? ? "a.at(#{idx[i]})" : - "(a.at(#{idx[i]}) << #{bits_per_word * i})" + if i.zero? + "a.at(#{idx[i]})" + else + "(a.at(#{idx[i]}) << #{bits_per_word * i})" + end end + + unpack_str = "a = io.readbytes(#{nbytes}).unpack('#{pack_directive(nbits, endian)}')" assemble_str = parts.join(" + ") "(#{unpack_str}; #{assemble_str})" end def create_to_binary_s_code(nbits, endian) # special case 8bit integers for speed return "val.chr" if nbits == 8 - # determine "word" size and pack directive - if (nbits % 32).zero? - bytes_per_word = 4 - d = (endian == :big) ? 'N' : 'V' - elsif (nbits % 16).zero? - bytes_per_word = 2 - d = (endian == :big) ? 'n' : 'v' - else - bytes_per_word = 1 - d = 'C' - end - - bits_per_word = bytes_per_word * 8 + bits_per_word = bytes_per_word(nbits) * 8 nwords = nbits / bits_per_word mask = (1 << bits_per_word) - 1 vals = (0 ... nwords).collect do |i| i.zero? ? "val" : "(val >> #{bits_per_word * i})" @@ -131,57 +122,44 @@ vals.reverse! if (endian == :big) parts = (0 ... nwords).collect { |i| "#{vals[i]} & #{mask}" } array_str = "[" + parts.join(", ") + "]" - "#{array_str}.pack('#{d * nwords}')" + "#{array_str}.pack('#{pack_directive(nbits, endian)}')" end - def define_methods(int_class, nbytes, clamp, read, to_binary_s, - int2uint = nil, uint2int = nil) - int_class.module_eval <<-END - #--------------- - private + def bytes_per_word(nbits) + (nbits % 32).zero? ? 4 : (nbits % 16).zero? ? 2 : 1 + end - def _assign(val) - #{clamp} - super(val) - end + def pack_directive(nbits, endian) + bits_per_word = bytes_per_word(nbits) * 8 + nwords = nbits / bits_per_word - def _do_num_bytes - #{nbytes} - end + if (nbits % 32).zero? + d = (endian == :big) ? 'N' : 'V' + elsif (nbits % 16).zero? + d = (endian == :big) ? 'n' : 'v' + else + d = 'C' + end - def sensible_default - 0 - end - - def value_to_binary_string(val) - #{clamp} - #{int2uint unless int2uint.nil?} - #{to_binary_s} - end - - def read_and_return_value(io) - val = #{read} - #{uint2int unless uint2int.nil?} - end - END + d * nwords end end end # Unsigned 1 byte integer. class Uint8 < BinData::BasePrimitive - register(self.name, self) - Int.create_uint_methods(self, 8, :little) + register_self + Int.define_methods(self, 8, :little, :unsigned) end # Signed 1 byte integer. class Int8 < BinData::BasePrimitive - register(self.name, self) - Int.create_int_methods(self, 8, :little) + register_self + Int.define_methods(self, 8, :little, :signed) end # Create classes on demand class << self alias_method :const_missing_without_int, :const_missing