Hex文件的解析(C#实现)
admin 于 2017年06月01日 发表在 windows软件开发
去年的一个项目,前前后后共花了三个来月。项目主要实现对某一款芯片的烧写、测试、仿真等功能。项目中博主主要负责windows平台上整个IDE的编写。 Hex文件解析便是其中的一个小功能,在此加以总结。(注:本例程适用64K以内的烧录镜像)
1. Hex文件格式
打开Hex文件,看到类似如下文本:
:1000D000E70100088D050008E7010008E7010008B6
(1)起始标识(:)
(2)第1字节(10),表示本行数据的长度(0x10)
(3)第2、3字节(00D0),表示本行数据的起始地址(0x00D0)
(4)第4字节(00)表示数据类型,包括:0x00、0x01、0x02、0x03、0x04、0x05
"00" Data Record:记录数据,HEX文件的大部分记录都是数据记录 "01" End of File Record: 标识文件结束 "02" Extended Segment Address Record: 用来标识扩展段地址的记录 "03" Start Segment Address Record: 开始段地址记录 "04" Extended Linear Address Record: 用来标识扩展线性地址的记录 "05" Start Linear Address Record: 开始线性地址记录
(5)数据(E70100088D050008E7010008E7010008),共0x10个字节
(6)最后一个数据(B6),表示校验和。
计算0xB6前所有16进制数的累加和,不计进位(即:低位单字节),检验和 = 0x100 - 累加和 。如上例,B6之前的所有16进制累加和为0x044A,取低位单字节位0x4A,则校验和 = 0x100 - 0x4A = 0xB6 。
2. C#语言解析
使用C#开发语言实现两个函数:解析数据、重新排序。
C#实现如下:
public bool ReadHexFile(string fileName) { if (fileName == null || fileName.Trim() == "") //文件存在 { return false; } using (FileStream fs = new FileStream(fileName, FileMode.Open)) //open file { StreamReader HexReader = new StreamReader(fs); //读取数据流 string szLine = ""; string szHex = ""; string szAddress = ""; string szLength = ""; while (true) { szLine = HexReader.ReadLine(); //读取Hex中一行 if (szLine == null) { break; } //读取完毕,退出 if (szLine.Substring(0, 1) == ":") //判断首字符是”:” { if (szLine.Substring(1, 8) == "00000001") { break; } //文件结束标识 //直接解析数据类型标识为 : 00 和 01 的格式 if ((szLine.Substring(8, 1) == "0") || (szLine.Substring(8, 1) == "1")) { szHex += szLine.Substring(9, szLine.Length - 11); //所有数据分一组 szAddress += szLine.Substring(3, 4); //所有起始地址分一组 szLength += szLine.Substring(1, 2); //所有数据长度归一组 } } } //将数据字符转换为Hex,并保存在数组 szBin[] Int32 j = 0; Int32 Length = szHex.Length; //获取长度 byte[] szBin = new byte[Length / 2]; for (Int32 i = 0; i < Length; i += 2) { szBin[j] = (byte)Int16.Parse(szHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber); //两个字符合并一个Hex j++; } //将起始地址的字符转换为Hex,并保存在数组 szAdd [] j = 0; Length = szAddress.Length; //get bytes number of szAddress Int16[] szAdd = new Int16[Length / 4]; for (Int32 i = 0; i < Length; i += 4) { szAdd[j] = Int16.Parse(szAddress.Substring(i, 4), System.Globalization.NumberStyles.HexNumber); //两个字符合并一个Hex j++; } //将长度字符转换为Hex,并保存在数组 szLen [] j = 0; Length = szLength.Length; //get bytes number of szAddress byte[] szLen = new byte[Length / 2]; for (Int32 i = 0; i < Length; i += 2) { szLen[j] = (byte)Int16.Parse(szLength.Substring(i, 2), System.Globalization.NumberStyles.HexNumber); //合并成hex类型 j++; } array_show_data(szAdd, szBin, szLen); //对重排后的数据显示 } return true; }
3. 以上函数实现HEX文本中的地址、长度、数据的分别存储,接下来进行数据排序,如下:
private void array_show_data(Int16[] address, byte[] data, byte[] length) { //1.整理数据所需参数 string temp = ""; string stringshow = " "; int jcount = 0; fileDataShow.Items.Clear(); //清除已有数据 temp = ""; fileDataShow.Items.Add(temp); //添加一个空行 int max_address = (address[(address.Length) - 1]) + 16; byte[] all_show_data = new byte[max_address]; //存储解析完成的数据数组 for (Int32 i = 0; i < all_show_data.Length; i++) { all_show_data[i] = 0; } //默认全为0 //2.从address[]数组中获取HEX对应地址 for (Int32 i = 0; i < address.Length; i++) { if (i >= 1) { jcount += length[i - 1]; } //从length[]数组中获取数据对应的长度大小 for (int j = 0; j < length[i]; j++) { all_show_data[address[i] + j] = data[jcount + j]; //all_show_data[]数组中添加数据 } } //3.在listbox控件fileDataShow中显示整理后的值(对应自定义的控件名称) for (Int32 i = 0; i < (Int32)((all_show_data.Length) / 16); i++) { jcount = i * 16; //每行16个数据,根据需要设置 //左侧显示具体地址 temp = Convert.ToString(jcount, 16).PadLeft(4, '0').ToUpper(); stringshow = temp + "h" + "\t"; for (Int32 j = 0; j < 16; j++) { temp = Convert.ToString(all_show_data[jcount + j], 16).PadLeft(2, '0').ToUpper(); //转换为2位对其字符 stringshow += temp + " "; } fileDataShow.Items.Add(stringshow); //fileDataShow中添加数据 stringshow = " "; } }
4. 最终效果图,如下: