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

注意:本站所有文章除特别说明外,均为原创,转载请务必以超链接方式并注明作者出处。 标签:Hex,C#