Converting byte string into signed, unsigned (int_8, int_16, int_32, ...) integer in Ruby

  

  ########################################

  # acceptable format

  # '\x00', '\x00\x00', '\x00\x00\x00', '\x00\x00\x00\x00', '\x00\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00', '\x00\x00\x00\x00\x00\x00\x00' ...

  # '0x0', '0x00', '0x000', '0x0000', '0x00000', '0x000000', '0x0000000', '0x000000000', '0x0000000000', '0x00000000000' ...

  # '0', '00', '000', '000', '00000', '000000', '0000000', '000000000', '0000000000', '00000000000' ...

  #########################################


  ########################################

  # convert byte string to signed integer

  ########################################

  def byte_string_to_unigned_integer(string)

    byte_string = string.downcase.gsub("\\x","").dup

    byte_string.slice! "0x"

    byte_string.hex

  end


  ########################################

  # convert byte string to signed integer

  ########################################

  def byte_string_to_signed_integer(string)

    byte_string = string.downcase.gsub("\\x","").dup

    byte_string.slice! "0x"

    bit_count = byte_string.length * 4

    signed_integer_value = byte_string.hex


    expected_bit_count = 8;

    #make sure it's 8, 16, 32, 64, 128 ... bits

    loop {

      bit_count = expected_bit_count if bit_count <= expected_bit_count

      break if expected_bit_count == bit_count

      expected_bit_count *= 2

    }


    # add missing Zeros '0' infront of string

    chars = signed_integer_value.to_s(2).rjust(bit_count, '0').scan /\w/


    # find MIN value

    minimum_value_bit_array = Array.new(bit_count, '1')

    minimum_value_bit_array[0] = '0'

    minimum_value = (minimum_value_bit_array.join('').to_i(2) * -1) - 1


    # if first bit is '1' it's negative value

    if chars[0] == '1'

      # find positive value

      chars[0] = '0'

      signed_string = chars.join('')

      # and add it to mininum value

      signed_integer_value = minimum_value + signed_string.to_i(2)

    end

    signed_integer_value

  end



Test Code


RESULTS = { '0x00' => 0, '00' => 0, '0' => 0,

            '0xFF' => -1, '0xff' => -1, 'FF' => -1, 'ff' => -1,

            '0xF' => 15, '0xf' => 15, '0F' => 15, '0f' => 15,

            '0x3F' => 63, '\x3f' => 63, '3F' => 63, '3f' => 63,

            '0xD8' => -40, '\xd8' => -40, 'D8' => -40, 'd8' => -40,

            '0xE7' => -25, '0xe7' => -25, 'E7' => -25, 'e7' => -25,

            '0x01' => 1, '0x1' => 1, '01' => 1, '\x1' => 1,

            '0x0A' => 10, '\x0a' => 10, '\x00\x0a' => 10, '\x00\x00\x0a' => 10,'\xA' => 10, 'a' => 10 }


RESULTS.each do |value, answer|

    result = byte_string_to_signed_integer(value)

    

    if result != answer

      puts "fail - expected : #{answer}, result : #{result}, given : #{value}"

    else

      puts "success - expected : #{answer}, result : #{result}, given : #{value}"

    end

end

박상건 - gunnih