#!/usr/bin/ruby class HexBinaryFormat @@debug = false def HexBinaryFormat.debug=(value) @@debug = value end def HexBinaryFormat.m_record_read(line, result) if @@debug puts <<-__DEBUG_STRING__ #{line[1].chr} #{line[2..3]} #{line[4..-3]} #{line[-2..-1]} __DEBUG_STRING__ end record_type = line[1].chr.hex record_length = line[2..3].hex address_data = [] (4..(line.length - 3)).step(2){|i| address_data << line[i..(i+1)].hex } check_sum = record_length address_data.each{|v| check_sum += v} unless ((check_sum + line[-2..-1].hex) & 0xFF) == 0xFF then raise "Checksum error!" end case record_type when 0 # Start Record result[:start_record] = address_data.pack("c*") when 1, 2, 3 # Data Record (16bit, 24bit, 32bit) offset = address_data.shift record_type.times{|i| offset <<= 8 offset += address_data.shift } result[:data][offset, address_data.length] = address_data else return end end def HexBinaryFormat.m_record_write(source, stream) address_type = \ (source[:data].size > 0xFFFFFF ? 3 \ : (source[:data].size > 0xFFFF ? 2 : 1)) index = 0 record_type = address_type.to_s while index < source[:data].size if !source[:data][index] index += 1 next end offset = format("%0#{(address_type + 1) * 2}X", index) check_sum = index % 256 index_copy = index address_type.times{|i| index_copy /= 256 check_sum += index_copy % 256 } data_length = 0 hex_data = "" while data_length < 16 check_sum += source[:data][index] hex_data += format("%02X", source[:data][index]) index += 1 data_length += 1 unless source[:data][index] then break end end record_length = (address_type + 1) + data_length + 1 record_length_hex = format("%02X", record_length) check_sum += record_length check_sum_hex = format("%02X", 0xFF - (check_sum & 0xFF)) stream.puts "S#{record_type}#{record_length_hex}#{offset}#{hex_data}#{check_sum_hex}" end record_length_hex = format("%02X", (address_type + 2)) offset = format("%0#{(address_type + 1) * 2}X", 0) check_sum_hex = format("%02X", 0xFF - (address_type + 2)) stream.puts "S#{10 - address_type}#{record_length_hex}#{offset}#{check_sum_hex}" end def HexBinaryFormat.i_record_read(line, result) if @@debug puts <<-__DEBUG_STRING__ #{line[1..2]} #{line[3..6]} #{line[7..8]} #{line[9..-3]} #{line[-2..-1]} __DEBUG_STRING__ end data_length = line[1..2].hex offset = line[3..6].hex # Big Endian record_type = line[7..8].hex data = [] (9..(line.length - 3)).step(2){|i| data << line[i..(i+1)].hex } check_sum = data_length + line[3..4].hex + line[5..6].hex + record_type data.each{|v| check_sum += v} unless ((check_sum + line[-2..-1].hex) & 0xFF) == 0 then raise "Checksum error!" end case record_type when 0 # Data Record if result[:offset_base] then offset += result[:offset_base] end result[:data][offset, data.length] = data when 1 # End Record when 2 # Segment Address Record result[:offset_base] = (line[9..-3].hex << 4) when 3 # Start Segement Address Record result[:start_address] = line[9..-3].hex when 4 # Extend Liner Address Record result[:offset_base] = (line[9..-3].hex << 16) when 5 # Start Liner Address Record result[:start_address] = line[9..-3].hex end end def HexBinaryFormat.i_record_write(source, stream) index = 0 offset_base = 0 while index < source[:data].size if !source[:data][index] index += 1 next end if (index >> 16) != offset_base then offset_base = (index >> 16) offset_base_hex = format("%04X", offset_base) check_sum = 0x100 - (( \ + (offset_base / 256) \ + (offset_base % 256) \ + 4 + 4 \ ) & 0xFF) check_sum_hex = format("%02X", check_sum) stream.puts <<-__HEX_STRING__ :04000004#{offset_base_hex}#{check_sum_hex} __HEX_STRING__ end offset_hex = format("%04X", index & 0xFFFF) data_length = 0 hex_data = "" check_sum = (index / 256) + (index % 256) while data_length < 16 check_sum += source[:data][index] hex_data += format("%02X", source[:data][index]) index += 1 data_length += 1 unless source[:data][index] then break end end data_length_hex = format("%02X", data_length) check_sum += data_length check_sum_hex = format("%02X", (0x100 - check_sum) & 0xFF) stream.puts <<-__HEX_STRING__ :#{data_length_hex}#{offset_hex}00#{hex_data}#{check_sum_hex} __HEX_STRING__ end stream.puts <<-__HEX_STRING__ :00000001FF __HEX_STRING__ end def HexBinaryFormat.read(stream = $stdin) result = {:data => []} stream.each_with_index{|line, line_no| line.chop! begin case line[0].chr when 'S','s' m_record_read(line, result) when ':' i_record_read(line, result) else raise "Format error!" end rescue Exception raise "#{$!} Line:#{line_no + 1} => #{line}" end } return result end def HexBinaryFormat.write(source, type = 'm', stream = $stdout) eval("HexBinaryFormat.#{type}_record_write(source, stream)") end end if $0 == __FILE__ then #HexBinaryFormat.debug = true result = nil if ARGV.empty? then result = HexBinaryFormat.read else result = HexBinaryFormat.read(open(ARGV.shift)) end #p result require 'stringio' m_format = StringIO::new i_format = StringIO::new HexBinaryFormat.write(result, 'm', m_format) HexBinaryFormat.write(result, 'i', i_format) print m_format.string print i_format.string m_format.seek(0) i_format.seek(0) result2_m = HexBinaryFormat.read(m_format) result2_i = HexBinaryFormat.read(i_format) #p result2_m[:data] #p result2_i[:data] p (result[:data] == result2_m[:data]) p (result[:data] == result2_i[:data]) end