HEX文件和BIN文件总结及hex文件流转bin文件流示例代码

作者:flydream0

转自:http://blog.csdn.net/flydream0/article/details/8447087


这几天在写STM32的ISP烧录工具,因此有涉及到输入hex文件或bin文件进行烧录的问题,所以对hex文件和bin文件进行了些总结。

1 hex介绍

Hex 全称 (Intel HEX)文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制编码数字组成。Intel HEX文件通常用于传输将被存于ROM或者EPROM中的程序和数据。大多数EPROM编程器或模拟器使用Intel HEX文件。

2 hex与bin的区别

1     HEX文件是包括地址信息的,而BIN文件格式只包括了数据本身,在烧写或下载HEX文件的时候,一般都不需要用户指定地址,因为HEX文件内部的信息已经包括了地址。而烧写BIN文件的时候,用户是一定需要指定地址信息的。

2   BIN文件格式,对二进制文件而言,其实没有”格式”。文件只是包括了纯粹的二进制数据。

3  HEX文件格式

HEX文件都是由记录(RECORD)组成的。在HEX文件里面,每一行代表一个记录。记录的基本格式为:

 +---------------------------------------------------------------+
         |  RECORD  | RECLEN |  LOAD  |RECTYPE | INFO or DATA | CHKSUM |
         |  MARK ':'|        | OFFSET |        |             |       |
        +---------------------------------------------------------------+
         |  1-byte  | 1-byte | 2-byte | 1-byte  |   n-byte    | 1-byte |
        +---------------------------------------------------------------+
 

记录类型包括:
         '00' DataRrecord:用来记录数据,HEX文件的大部分记录都是数据记录
         '01' End of File Record:用来标识文件结束,放在文件的最后,标识HEX文件的结尾
         '02' Extended SegmentAddress Record: 用来标识扩展段地址的记录

         '03' Start Segment Address Record

          '04' Extended Linear AddressRecord: 用来标识扩展线性地址的记录

          '05' Start Linear Address Record
         
        在上面的后2种记录,都是用来提供地址信息的。每次碰到这2个记录的时候,都可以根据记录计算出一个“基”地址。
        对于后面的数据记录,计算地址的时候,都是以这些“基”地址为基础的。
         
         数据记录的具体格式:
        +---------------------------------------------------------------+
         |  RECORD  | RECLEN |  LOAD  |RECTYPE | INFO or DATA | CHKSUM |
         |  MARK ':'|        | OFFSET|  '00'   |             |       |
        +---------------------------------------------------------------+
         |  1-byte  | 1-byte | 2-byte | 1-byte  |   n-byte    | 1-byte |
        +---------------------------------------------------------------+        
         
         看个例子:
        :020000040000FA
       :10000400FF00A0E314209FE5001092E5011092E5A3
        :00000001FF        
      
        对上面的HEX文件进行分析:
        第1条记录的长度为02,LOADOFFSET为0000,RECTYPE为04,说明该记录为扩展段地址记录。数据为0000,校验和为
       FA。从这个记录的长度和数据,我们可以计算出一个基地址,这个地址为0X0000。后面的数据记录都以这个地址为基
        地址。
        第2条记录的长度为10(16),LOADOFFSET为0004,RECTYPE为00,说明该记录为数据记录。
       数据为FF00A0E314209FE5001092E5011092E5,共16个BYTE。这个记录的校验和为A3。此时的基地址为0X0000,加上OFFSET,
        这个记录里的16BYTE的数据的起始地址就是0x0000+ 0x0004 = 0x0004.
        第3条记录的长度为00,LOADOFFSET为0000,TYPE = 01,校验和为FF。说明这个是一个END OF FILE RECORD,标识
        文件的结尾。
      
       在上面这个例子里,实际的数据只有16个BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址为0x4

4   HEX文件和BIN文件大小有区别

     HEX文件是用ASCII来表示二进制的数值。例如一般8-BIT的二进制数值0x3F,用ASCII来表示就需要分别表示字符'3'
     和字符'F',每个字符需要一个BYTE,所以HEX文件需要 > 2倍的空间。
    对一个BIN文件而言,你查看文件的大小就可以知道文件包括的数据的实际大小。而对HEX文件而言,你看到的文件
    大小并不是实际的数据的大小。一是因为HEX文件是用ASCII来表示数据,二是因为HEX文件本身还包括别的附加信息。


要想详细了解HEX文件格式, 请参见INTEL HEX PDF文档

3 hex文件流转bin文件流

hex.h:

  1. #ifndef __HEX_H_  
  2. #define __HEX_H_  
  3.   
  4. typedef struct{  
  5.     int len; //bin文件大小  
  6.     UINT startAddress; //刷写的起始地址  
  7.     BYTE *pContent;     //转化后的内容  
  8. }HexToBinData;  
  9.   
  10. typedef struct{  
  11.     BYTE data[16];//数据  
  12.     BYTE len;   //数据长度  
  13.     UINT pos;   //偏移地址  
  14.     BYTE type;  //类型  
  15. }HexLinData;  
  16.   
  17. int ConvertHexToBin(const char *str,HexToBinData *pData);  
  18. #endif  

hex.cpp:
  1. //#include "StdAfx.h"  
  2. #include "hex.h"  
  3.   
  4. static BYTE HexCharToByte(char c)  
  5. {  
  6.     if(c>='0' && c<='9')  
  7.         return c -'0';  
  8.     else if(c>='a' && c<='f')  
  9.         return c-'a'+0x0a;  
  10.     else if(c>='A' && c <='F')  
  11.         return c-'A'+0x0a;  
  12.       
  13.     return -1;  
  14. }  
  15. static BYTE GetFirstByte(const char *str)  
  16. {  
  17.     ASSERT(str !=NULL);  
  18.   
  19.     BYTE tmp =0;  
  20.     tmp =HexCharToByte(str[0]);  
  21.     tmp <<=4;  
  22.     tmp +=HexCharToByte(str[1]);  
  23.   
  24.     return tmp;  
  25. }  
  26. //从字符串中获取一行  
  27. static int GetLine(const char *str,char *pBuf)  
  28. {  
  29.     ASSERT(str !=NULL);  
  30.     ASSERT(pBuf !=NULL);  
  31.   
  32.     char *start =strchr((char *)str,':');  
  33.     if(NULL ==start){  
  34.         return -1;  
  35.     }  
  36.   
  37.     char *end =strstr(start,"\r\n");  
  38.     char *p =start;  
  39.     char *p2 =pBuf;  
  40.     int len=0;  
  41.     for (;p<end+2;p++,p2++)  
  42.     {  
  43.         if(*p =='\0')  
  44.             break;  
  45.         *p2 =*p;  
  46.         len ++;  
  47.     }  
  48.     *p2 ='\0';  
  49.   
  50.     return len;  
  51. }  
  52.   
  53. //获取一行的数据  
  54. static int GetHexLineData(const char *line,HexLinData *pData)  
  55. {  
  56.     ASSERT(line !=NULL);  
  57.     ASSERT(pData !=NULL);  
  58.   
  59.     if(line[0] !=':')  
  60.         return -1;  
  61.     int i=1;  
  62.     pData->len =GetFirstByte(&line[i]);  
  63.     i +=2;  
  64.     pData->pos =GetFirstByte(&line[i]);  
  65.     i +=2;  
  66.     pData->pos <<=8;  
  67.     pData->pos +=GetFirstByte(&line[i]);  
  68.     i +=2;  
  69.     pData->type =GetFirstByte(&line[i]);  
  70.     i +=2;  
  71.     for(int j=0;j<pData->len;i+=2,j++){  
  72.         pData->data[j] =GetFirstByte(&line[i]);  
  73.     }  
  74.     return 0;  
  75. }  
  76. //获取第一行指定类型的数据  
  77. static int GetFirstDataLine(const char *str,BYTE type,HexLinData *pData)  
  78. {  
  79.   
  80.     ASSERT(str !=NULL);  
  81.     ASSERT(pData !=NULL);  
  82.   
  83.     char *p =(char *)str;  
  84.     char line[128];  
  85.     HexLinData data ={0};  
  86.     int len =strlen(str);  
  87.     int dataLen =0;  
  88.   
  89.     for(;p<str+len;p+=dataLen){  
  90.         memset(line,0,128);  
  91.         dataLen =GetLine(p,line);  
  92.         if(dataLen <0)  
  93.             return -1;  
  94.         memset(&data,0x00,sizeof(HexLinData));  
  95.         if(0 !=GetHexLineData(line,&data))  
  96.             return -1;  
  97.   
  98.         if(data.type ==type){  
  99.             memcpy(pData,&data,sizeof(HexLinData));  
  100.             return 0;  
  101.         }  
  102.     }  
  103.     return -1;  
  104. }  
  105.   
  106. static int GetStartAddress(const char *str,UINT *pStartAddress)  
  107. {  
  108.     HexLinData data ={0};  
  109.     UINT basePos=0;  
  110.     UINT pos;  
  111.   
  112.     if(0 !=GetFirstDataLine(str,4,&data))  
  113.         return -1;  
  114.     for(int i=0;i<data.len;i++){  
  115.         basePos <<=8;  
  116.         basePos +=data.data[i];  
  117.     }  
  118.   
  119.     memset(&data,0x00,sizeof(HexLinData));  
  120.     if(0 !=GetFirstDataLine(str,0,&data))  
  121.         return -1;  
  122.     pos =data.pos;  
  123.   
  124.     *pStartAddress =(basePos<<16) +pos;  
  125.     return 0;  
  126. }  
  127.   
  128. int ConvertHexToBin(const char *str,HexToBinData *pData)  
  129. {  
  130.     ASSERT(str !=NULL);  
  131.     ASSERT(pData !=NULL);  
  132.   
  133.   
  134.     UINT startAddress =0;  
  135.     char line[128] ={0};  
  136.     HexLinData data={0};  
  137.     if(0 !=GetStartAddress(str,&startAddress))  
  138.         return -1;  
  139.   
  140.     pData->startAddress =startAddress;  
  141.   
  142.     char *p =(char *)str;  
  143.     int binLen =0;  
  144.     int len =0;  
  145.     int size =strlen(str);  
  146.   
  147.     /*FILE *file =fopen("test.hex","wb+"); 
  148.     fseek(file,0,SEEK_SET); 
  149.     FILE *file1 =fopen("test.bin","wb+"); 
  150.     fseek(file1,0,SEEK_SET);*/  
  151.     for(binLen=0;p<str+size;p +=len){  
  152.         memset(line,0,128);  
  153.         len =GetLine(p,line);  
  154.         if(len <0)  
  155.             break;  
  156.         /*fwrite(line,1,len,file);*/  
  157.         memset(&data,0x00,sizeof(HexLinData));  
  158.         if(0 !=GetHexLineData(line,&data))  
  159.             return -1;  
  160.         if(data.type ==0){  
  161.             binLen +=data.len;  
  162.             /*fwrite(data.data,1,data.len,file1);*/  
  163.         }  
  164.     }  
  165.     /*fclose(file); 
  166.     fclose(file1);*/  
  167.     pData->len =binLen;  
  168.     pData->pContent =(BYTE *)malloc(pData->len+1);  
  169.     if(pData->pContent ==NULL)  
  170.         return -1;  
  171.   
  172.     p =(char *)str;  
  173.     binLen =0;  
  174.     len =0;  
  175.     for(binLen=0;p<str+size;p +=len){  
  176.         memset(line,0,128);  
  177.         len =GetLine(p,line);  
  178.         if(len <0)  
  179.             break;  
  180.         memset(&data,0x00,sizeof(HexLinData));  
  181.         if(0 !=GetHexLineData(line,&data))  
  182.             return -1;  
  183.         if(data.type ==0){  
  184.             memcpy(pData->pContent+binLen,data.data,data.len);  
  185.             binLen +=data.len;  
  186.         }  
  187.     }  
  188.   
  189.     return 0;  
  190. }  

只有一个接口函数:

  1. int ConvertHexToBin(const char *str,HexToBinData *pData);  

它的作用是将hex文件流str直接转化为bin文件流,并存储到HexToBinData结构体中,若成功则返回0,失败则返回非0.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值