C# 学习笔记(12)hex文件转bin文件小工具

Posted 不咸不要钱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 学习笔记(12)hex文件转bin文件小工具相关的知识,希望对你有一定的参考价值。

C# 学习笔记(12)hex文件转bin文件小工具

hex文件格式

hex文件格式网上有很多
我这里参考HEX文件格式详解https://blog.csdn.net/weixin_39752827/article/details/81477686

编写hex2bin类

hex转bin文件的方法很多,但是在做bootLoader工具时,只能接受bin文件就很烦,就有了将hex转bin集成到自己工具里的想法。
首先去github找了一下,避免重复造轮子,发现了两个不错的c#示例
Hex2Bin https://github.com/x893/Hex2Bin
STM32-IAP-HEX-Merge https://github.com/SmartElec/STM32-IAP-HEX-Merge
但是不太满意,刚好又在学习c#,就动手自己造了个轮子

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharp_Hex2Bin
{
    /// <summary>
    /// hex文件转bin文件 
    /// hex格式解析:<0x3a>[数据长度1Byte][数据地址2Byte][数据类型1Byte][数据nByte][校验1Byte]<0x0d><0x0a>
    /// </summary>
    public static class MyHex2Bin
    {
        /// <summary>
        /// hex文件段信息结构体
        /// </summary>
        public class Section
        {
            public uint startAddr = new uint();
            public uint endAddr = new uint();
            public List<byte> data = new List<byte>();
            public string filePath;
        }

        /// <summary>
        /// hex 数据类型
        /// </summary>
        enum INTEL_COMMAND : byte
        {
            UNKNOWN = 0xFF,
            /// <summary>
            /// Data Record 数据
            /// </summary>
            DATA = 0x00,
            /// <summary>
            /// End of File Record 文件结束标志
            /// </summary>
            EOF = 0x01,
            /// <summary>
            /// Extended Segment Address Record 延伸段地址
            /// </summary>
            EXT_SEGMENT_ADDR = 0x02,
            /// <summary>
            /// Start Segment Address Record   起始延伸地址
            /// </summary>
            SEGMENT_ADDR = 0x03,
            /// <summary>
            /// Extended Linear Address Record 扩展线性地址 也就是基地址
            /// </summary>
            EXTEND_ADDR = 0x04,
            /// <summary>
            /// Start Linear Address Record       程序起始地址也就是程序入口地址(main)
            /// </summary>
            LINEAR_ADDR = 0x05,
            DATA_LOOP = 0x10
        }

        /// <summary>
        /// 根据hex文件生成bin文件, 不管hex文件是否有问题 
        /// </summary>
        /// <param name="outBinFilePath">bin文件路径</param>
        /// <param name="encoding">hex文件编码格式</param>
        /// <param name="ignoreByte">占位符 空白的地址填</param>
        /// <param name="sections">hex文件信息</param>
        /// <param name="log">日志信息</param>
        /// <param name="errSections">有问题的地址块</param>
        /// <param name="inHexFilePath">hex文件路径</param>
        public static void Conver(string outBinFilePath, Encoding encoding, byte ignoreByte, ref List<Section> sections, out string log, ref List<Section> errSections, params string[] inHexFilePath)
        {
            LoadHex(encoding, ref sections, out log, ref errSections, inHexFilePath);
            WriteBinFile(outBinFilePath, ignoreByte, sections);
        }

        /// <summary>
        /// 根据hex文件生成bin文件, 不管hex文件是否有问题 
        /// </summary>
        /// <param name="outBinFilePath">bin文件路径</param>
        /// <param name="inHexFilePath">hex文件路径</param>
        public static void Conver(string outBinFilePath, params string[] inHexFilePath)
        {
            List<Section> sections = new List<Section>();
            List<Section> errSections = new List<Section>();
            Conver(outBinFilePath, Encoding.Default, 0, ref sections, out string log, ref errSections, inHexFilePath);
        }

        /// <summary>
        /// 根据hex文件生成bin文件, 不管hex文件是否有问题 
        /// </summary>
        /// <param name="inHexFilePath">hex文件路径</param>
        public static void Conver(params string[] inHexFilePath)
        {
            Conver(inHexFilePath[0], inHexFilePath);
        }

        /// <summary>
        /// 将hex文件读到内存中
        /// </summary>
        /// <param name="encoding">hex文件编码格式</param>
        /// <param name="sections">hex文件信息</param>
        /// <param name="log">日志</param>
        /// <param name="errSections">有问题的地址块</param>
        /// <param name="inHexFilePath">hex文件路径</param>
        public static void LoadHex(Encoding encoding, ref List<Section> sections, out string log, ref List<Section> errSections, params string[] inHexFilePath)
        {
            //加载hex文件
            LoadHex(encoding, ref sections, out log, inHexFilePath);

            //检查地址冲突
            if (!CheckAddr(sections, out string str, ref errSections))
            {
                log += str;
            }
        }

        /// <summary>
        /// 将hex文件读到内存中
        /// </summary>
        /// <param name="encoding">hex文件编码格式</param>
        /// <param name="sections">hex文件信息</param>
        /// <param name="log">日志</param>
        /// <param name="inHexFilePath">hex文件路径</param>
        public static void LoadHex(Encoding encoding, ref List<Section> sections, out string log, params string[] inHexFilePath)
        {
            log = "";
            foreach (var item in inHexFilePath)
            {
                if (!string.IsNullOrWhiteSpace(item))
                {
                    //文件存在并且以.hex结尾
                    if (File.Exists(item) && Path.GetExtension(item).ToLower().Equals(".hex"))
                    {
                        #region 解析一个hex文件
                        //读取hex文件
                        string[] hexFileAllLines = File.ReadAllLines(item, encoding);
                        List<Section> tempSections = new List<Section>();
                        uint extend_address = 0, start_address = 0, segment_address = 0, linear_address = 0;
                        uint count = 0, address = 0;
                        byte dataType = 0;
                        INTEL_COMMAND command = INTEL_COMMAND.UNKNOWN;
                        for (int line = 0; line < hexFileAllLines.Length; line++)
                        {
                            bool fail = false;
                            string hexFileLine = hexFileAllLines[line];
                            //hex文件每行最少11个字符并且以":"起始
                            if (hexFileLine.Length >= 11 && hexFileLine.StartsWith(":") && CheckSum(hexFileLine))
                            {
                                #region 解析一行hex文件 获取其长度、地址、数据类型、校验和信息
                                fail |= !uint.TryParse(hexFileLine.Substring(1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out count);
                                fail |= !uint.TryParse(hexFileLine.Substring(3, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out address);
                                fail |= !byte.TryParse(hexFileLine.Substring(7, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out dataType);
                                command = (INTEL_COMMAND)dataType;
                                if (fail)
                                {
                                    log += "文件: " + item + " 第" + line + "行\\r\\n" + hexFileLine + "\\r\\n不符合hex文件格式!解析失败\\r\\n";
                                    break;
                                }
                                #endregion
                            }
                            else
                            {
                                log += "文件: " + item + " 第" + line + "行\\r\\n" + hexFileLine + "\\r\\n不符合hex文件格式!\\r\\n";
                                continue;
                            }

                            switch (command)
                            {
                                case INTEL_COMMAND.EOF:
                                    sections.AddRange(tempSections);
                                    log += "文件: " + item + " 解析完成 共解析:" + line + "行\\r\\n";
                                    line = hexFileAllLines.Length;
                                    break;
                                case INTEL_COMMAND.DATA:
                                #region 正常数据接收
                                case INTEL_COMMAND.DATA_LOOP:
                                    int idx = 9; //hex文件 第九个字符开始才是数据

                                    if (tempSections.Count > 0)
                                    {
                                        if (string.IsNullOrEmpty(tempSections[tempSections.Count - 1].filePath))
                                        {
                                            tempSections[tempSections.Count - 1].startAddr = segment_address + extend_address + address;
                                            tempSections[tempSections.Count - 1].endAddr = tempSections[tempSections.Count - 1].startAddr;
                                            tempSections[tempSections.Count - 1].filePath = item;
                                        }
                                        else if ((tempSections[tempSections.Count - 1].endAddr - (segment_address + extend_address) + 1) != address)
                                        {
                                            tempSections.Add(new Section());
                                            tempSections[tempSections.Count - 1].startAddr = segment_address + extend_address + address;
                                            tempSections[tempSections.Count - 1].endAddr = tempSections[tempSections.Count - 1].startAddr;
                                            tempSections[tempSections.Count - 1].filePath = item;
                                        }
                                    }

                                    for (; !fail && count > 0; --count)
                                    {
                                        fail = !byte.TryParse(hexFileLine.Substring(idx, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out byte data);

                                        if (!fail)
                                        {
                                            tempSections[tempSections.Count - 1].data.Add(data);
                                            tempSections[tempSections.Count - 1].endAddr = segment_address + extend_address + address;
                                        }
                                        else
                                        {
                                            fail = true;
                                        }
                                        idx += 2;
                                        address++;
                                    }
                                    break;
                                #endregion
                                case INTEL_COMMAND.EXT_SEGMENT_ADDR:
                                    #region 延伸段地址解析
                                    if (count != 2 || hexFileLine.Length != 15)
                                    {
                                        fail = true;
                                        log += string.Format("文件: {0} 第 {1} 行: {2}  延伸段地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                    }
                                    else
                                    {
                                        fail |= !uint.TryParse(hexFileLine.Substring(9, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out segment_address);
                                        if (fail)
                                            log += string.Format("文件: {0} 第 {1} 行:{2}  延伸段地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                        else
                                        {
                                            segment_address <<= 4;
                                            tempSections.Add(new Section());
                                        }

                                    }
                                    break;
                                #endregion
                                case INTEL_COMMAND.SEGMENT_ADDR:
                                    #region 起始段地址解析
                                    if (count != 4)
                                    {
                                        log += string.Format("文件: {0} 第 {1} 行: {2}  起始段地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                    }
                                    else
                                    {
                                        fail |= !uint.TryParse(hexFileLine.Substring(9, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out start_address);
                                        if (fail)
                                            log += string.Format("文件: {0} 第 {1} 行: {2}  起始段地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                        else
                                            log += string.Format("文件: {0} 第 {1} 行: 起始段地址解析成功: 0x{2:X}\\r\\n", item, line.ToString(), start_address);
                                    }
                                    break;
                                #endregion
                                case INTEL_COMMAND.EXTEND_ADDR:
                                    #region 扩展段地址解析
                                    if (hexFileLine.Length != 15)
                                    {
                                        log += string.Format("文件: {0} 第 {1} 行: {2}  扩展段地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                        fail = true;
                                    }
                                    else
                                    {
                                        fail |= !uint.TryParse(hexFileLine.Substring(9, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out extend_address);
                                        if (fail)
                                        {
                                            log += string.Format("文件: {0} 第 {1} 行: {2}  扩展段地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                        }
                                        else
                                        {
                                            extend_address = extend_address << 16;
                                            tempSections.Add(new Section());
                                        }
                                    }
                                    break;
                                #endregion
                                case INTEL_COMMAND.LINEAR_ADDR:
                                    #region 程序起始地址也就是程序入口地址(main)解析
                                    if (count != 4)
                                    {
                                        log += string.Format("文件: {0} 第 {1} 行: {2}  程序起始地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                    }
                                    else
                                    {
                                        fail |= !uint.TryParse(hexFileLine.Substring(9, 8), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out linear_address);
                                        if (fail)
                                            log += string.Format("文件: {0} 第 {1} 行: {2}  程序起始地址解析错误\\r\\n", item, line.ToString(), hexFileLine);
                                        else
                                            log += string.Format("文件: {0} 第 {1} 行: 程序起始地址解析成功: 0x{2:X}\\r\\n", item, line.ToString(), linear_address)以上是关于C# 学习笔记(12)hex文件转bin文件小工具的主要内容,如果未能解决你的问题,请参考以下文章

python学习笔记——进制符号&转换公式

hex文件转换成C语言

bin 文件转 hex 数组

bin 文件转 hex 数组

初学c# -- 学习笔记

Keil开发环境如何生成BIN文件