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. 最终效果图,如下:
