summaryrefslogtreecommitdiff
path: root/tools/hex2bin-2.0/src/hex2bin.c
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2020-12-30 19:07:31 +0000
committerJuan J. Martinez <jjm@usebox.net>2020-12-30 19:23:41 +0000
commit2682bc5d1d864341aaeb42a449db73c3ecd16d70 (patch)
tree9116764364b4ee0ce7f6037305077807b57776de /tools/hex2bin-2.0/src/hex2bin.c
downloadubox-msx-lib-2682bc5d1d864341aaeb42a449db73c3ecd16d70.tar.gz
ubox-msx-lib-2682bc5d1d864341aaeb42a449db73c3ecd16d70.zip
Initial import1.0
Diffstat (limited to 'tools/hex2bin-2.0/src/hex2bin.c')
-rw-r--r--tools/hex2bin-2.0/src/hex2bin.c587
1 files changed, 587 insertions, 0 deletions
diff --git a/tools/hex2bin-2.0/src/hex2bin.c b/tools/hex2bin-2.0/src/hex2bin.c
new file mode 100644
index 0000000..7537d8c
--- /dev/null
+++ b/tools/hex2bin-2.0/src/hex2bin.c
@@ -0,0 +1,587 @@
+/*
+ hex2bin converts an Intel hex file to binary.
+
+ Copyright (C) 2015, Jacques Pelletier
+ checksum extensions Copyright (C) 2004 Rockwell Automation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ 20040617 Alf Lacis: Added pad byte (may not always want FF).
+ Added 'break;' to remove GNU compiler warning about label at
+ end of compound statement
+ Added PROGRAM & VERSION strings.
+
+ 20071005 PG: Improvements on options parsing
+ 20091212 JP: Corrected crash on 0 byte length data records
+ 20100402 JP: Corrected bug on physical address calculation for extended
+ linear address record.
+ ADDRESS_MASK is now calculated from MEMORY_SIZE
+
+ 20120125 Danny Schneider:
+ Added code for filling a binary file to a given Max_Length relative to
+ Starting Address if Max-Address is larger than Highest-Address
+ 20120509 Yoshimasa Nakane:
+ modified error checking (also for output file, JP)
+ 20141005 JP: added support for byte swapped hex files
+ corrected bug caused by extra LF at end or within file
+ 20141008 JP: removed junk code
+ 20141121 Slucx: added line for removing extra CR when entering file name at run time.
+ 20141122 Simone Fratini: small feature added
+ 20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag
+ 20150122 JP: added support for different check methods
+ 20150221 JP: rewrite of the checksum write/force value
+*/
+
+#define PROGRAM "hex2bin"
+#define VERSION "2.0"
+
+#include "common.h"
+
+#define NO_ADDRESS_TYPE_SELECTED 0
+#define LINEAR_ADDRESS 1
+#define SEGMENTED_ADDRESS 2
+
+const char *Pgm_Name = PROGRAM;
+
+int main (int argc, char *argv[])
+{
+ /* line inputted from file */
+ char Line[MAX_LINE_SIZE];
+
+ /* flag that a file was read */
+ bool Fileread;
+
+ /* cmd-line parameter # */
+ char *p;
+
+ int Param,result;
+
+ /* Application specific */
+
+ unsigned int Nb_Bytes;
+ unsigned int First_Word, Address, Segment, Upper_Address;
+ unsigned int Phys_Addr, Type;
+ unsigned int temp;
+ unsigned int Records_Start; // Lowest address of the records
+
+ /* We will assume that when one type of addressing is selected, it will be valid for all the
+ current file. Records for the other type will be ignored. */
+ unsigned int Seg_Lin_Select = NO_ADDRESS_TYPE_SELECTED;
+
+ unsigned int temp2;
+
+ byte Data_Str[MAX_LINE_SIZE];
+
+ fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n");
+
+ if (argc == 1)
+ usage();
+
+ strcpy(Extension, "bin"); /* default is for binary file extension */
+
+ /* read file */
+ Starting_Address = 0;
+
+ /*
+ use p for parsing arguments
+ use i for number of parameters to skip
+ use c for the current option
+ */
+ for (Param = 1; Param < argc; Param++)
+ {
+ int i = 0;
+ char c;
+
+ p = argv[Param];
+ c = *(p+1); /* Get option character */
+
+ if ( _IS_OPTION_(*p) )
+ {
+ // test for no space between option and parameter
+ if (strlen(p) != 2) usage();
+
+ switch(c)
+ {
+ /* file extension */
+ case 'c':
+ Enable_Checksum_Error = true;
+ i = 0;
+ break;
+ case 'd':
+ DisplayCheckMethods();
+ case 'e':
+ GetExtension(argv[Param + 1],Extension);
+ i = 1; /* add 1 to Param */
+ break;
+ case 'E':
+ Endian = GetBin(argv[Param + 1]);
+ i = 1; /* add 1 to Param */
+ break;
+ case 'f':
+ Cks_Addr = GetHex(argv[Param + 1]);
+ Cks_Addr_set = true;
+ i = 1; /* add 1 to Param */
+ break;
+ case 'F':
+ Cks_Addr = GetHex(argv[Param + 1]);
+ Cks_Value = GetHex(argv[Param + 2]);
+ Force_Value = true;
+ i = 2; /* add 2 to Param */
+ break;
+ case 'k':
+ Cks_Type = GetHex(argv[Param + 1]);
+ {
+ if (Cks_Type > LAST_CHECK_METHOD) usage();
+ }
+ i = 1; /* add 1 to Param */
+ break;
+ case 'l':
+ Max_Length = GetHex(argv[Param + 1]);
+ if (Max_Length > 0x800000)
+ {
+ fprintf(stderr,"Max_Length = %u\n", Max_Length);
+ exit(1);
+ }
+ Max_Length_Setted = true;
+ i = 1; /* add 1 to Param */
+ break;
+ case 'm':
+ Minimum_Block_Size = GetHex(argv[Param + 1]);
+ Minimum_Block_Size_Setted = true;
+ i = 1; /* add 1 to Param */
+ break;
+ case 'p':
+ Pad_Byte = GetHex(argv[Param + 1]);
+ i = 1; /* add 1 to Param */
+ break;
+ case 'r':
+ Cks_Start = GetHex(argv[Param + 1]);
+ Cks_End = GetHex(argv[Param + 2]);
+ Cks_range_set = true;
+ i = 2; /* add 2 to Param */
+ break;
+ case 's':
+ Starting_Address = GetHex(argv[Param + 1]);
+ Starting_Address_Setted = true;
+ i = 1; /* add 1 to Param */
+ break;
+ case 'w':
+ Swap_Wordwise = true;
+ i = 0;
+ break;
+ case 'C':
+ Crc_Poly = GetHex(argv[Param + 1]);
+ Crc_Init = GetHex(argv[Param + 2]);
+ Crc_RefIn = GetBoolean(argv[Param + 3]);
+ Crc_RefOut = GetBoolean(argv[Param + 4]);
+ Crc_XorOut = GetHex(argv[Param + 5]);
+ CrcParamsCheck();
+ i = 5; /* add 5 to Param */
+ break;
+
+ case '?':
+ case 'h':
+ default:
+ usage();
+ } /* switch */
+
+ /* Last parameter is not a filename */
+ if (Param == argc-1) usage();
+
+ /* if (Param + i) < (argc -1) */
+ if (Param < argc -1 -i) Param += i;
+ else usage();
+
+ }
+ else
+ break;
+ /* if option */
+ } /* for Param */
+
+ /* when user enters input file name */
+
+ /* Assume last parameter is filename */
+ strcpy(Filename,argv[argc -1]);
+
+ /* Just a normal file name */
+ NoFailOpenInputFile (Filename);
+ PutExtension(Filename, Extension);
+ NoFailOpenOutputFile(Filename);
+ Fileread = true;
+
+ /* To begin, assume the lowest address is at the end of the memory.
+ While reading each records, subsequent addresses will lower this number.
+ At the end of the input file, this value will be the lowest address.
+
+ A similar assumption is made for highest address. It starts at the
+ beginning of memory. While reading each records, subsequent addresses will raise this number.
+ At the end of the input file, this value will be the highest address. */
+ Lowest_Address = (unsigned int)-1;
+ Highest_Address = 0;
+ Records_Start = 0;
+ Segment = 0;
+ Upper_Address = 0;
+ Record_Nb = 0; // Used for reporting errors
+
+ /* get highest and lowest addresses so that we can allocate the right size */
+ do
+ {
+ unsigned int i;
+
+ /* Read a line from input file. */
+ GetLine(Line,Filin);
+ Record_Nb++;
+
+ /* Remove carriage return/line feed at the end of line. */
+ i = strlen(Line);
+
+ if (--i != 0)
+ {
+ if (Line[i] == '\n') Line[i] = '\0';
+
+ /* Scan the first two bytes and nb of bytes.
+ The two bytes are read in First_Word since its use depend on the
+ record type: if it's an extended address record or a data record.
+ */
+ result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str);
+ if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ p = (char *) Data_Str;
+
+ /* If we're reading the last record, ignore it. */
+ switch (Type)
+ {
+ /* Data record */
+ case 0:
+ if (Nb_Bytes == 0)
+ break;
+
+ Address = First_Word;
+
+ if (Seg_Lin_Select == SEGMENTED_ADDRESS)
+ {
+ Phys_Addr = (Segment << 4) + Address;
+ }
+ else
+ {
+ /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED
+ Upper_Address = 0 as specified in the Intel spec. until an extended address
+ record is read. */
+ Phys_Addr = ((Upper_Address << 16) + Address);
+ }
+
+ /* Set the lowest address as base pointer. */
+ if (Phys_Addr < Lowest_Address)
+ Lowest_Address = Phys_Addr;
+
+ /* Same for the top address. */
+ temp = Phys_Addr + Nb_Bytes -1;
+
+ if (temp > Highest_Address)
+ Highest_Address = temp;
+
+ break;
+
+ case 2:
+ /* First_Word contains the offset. It's supposed to be 0000 so
+ we ignore it. */
+
+ /* First extended segment address record ? */
+ if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED)
+ Seg_Lin_Select = SEGMENTED_ADDRESS;
+
+ /* Then ignore subsequent extended linear address records */
+ if (Seg_Lin_Select == SEGMENTED_ADDRESS)
+ {
+ result = sscanf (p, "%4x%2x",&Segment,&temp2);
+ if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ /* Update the current address. */
+ Phys_Addr = (Segment << 4);
+ }
+ else
+ {
+ fprintf(stderr,"Ignored extended linear address record %d\n", Record_Nb);
+ }
+ break;
+
+ case 4:
+ /* First_Word contains the offset. It's supposed to be 0000 so
+ we ignore it. */
+
+ /* First extended linear address record ? */
+ if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED)
+ Seg_Lin_Select = LINEAR_ADDRESS;
+
+ /* Then ignore subsequent extended segment address records */
+ if (Seg_Lin_Select == LINEAR_ADDRESS)
+ {
+ result = sscanf (p, "%4x%2x",&Upper_Address,&temp2);
+ if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ /* Update the current address. */
+ Phys_Addr = (Upper_Address << 16);
+ }
+ else
+ {
+ fprintf(stderr,"Ignored extended segment address record %d\n", Record_Nb);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ while (!feof (Filin));
+
+ rewind(Filin);
+ Segment = 0;
+ Upper_Address = 0;
+ Record_Nb = 0;
+
+ if (Starting_Address_Setted == true)
+ {
+ Records_Start = Lowest_Address;
+ Lowest_Address = Starting_Address;
+ }
+ else
+ {
+ Records_Start = Lowest_Address;
+ Starting_Address = Lowest_Address;
+ }
+
+ if (Max_Length_Setted == false)
+ Max_Length = Highest_Address - Lowest_Address + 1;
+ else
+ Highest_Address = Lowest_Address + Max_Length - 1;
+
+ /* Now, that we know the buffer size, we can allocate it. */
+ /* allocate a buffer */
+ Memory_Block = (byte *) NoFailMalloc(Max_Length);
+
+ /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */
+ memset (Memory_Block,Pad_Byte,Max_Length);
+
+ /* Read the file & process the lines. */
+ do /* repeat until EOF(Filin) */
+ {
+ unsigned int i;
+
+ /* Read a line from input file. */
+ GetLine(Line,Filin);
+ Record_Nb++;
+
+ /* Remove carriage return/line feed at the end of line. */
+ i = strlen(Line);
+
+ //fprintf(stderr,"Record: %d; length: %d\n", Record_Nb, i);
+
+ if (--i != 0)
+ {
+ if (Line[i] == '\n') Line[i] = '\0';
+
+ /* Scan the first two bytes and nb of bytes.
+ The two bytes are read in First_Word since its use depend on the
+ record type: if it's an extended address record or a data record.
+ */
+ result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str);
+ if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ Checksum = Nb_Bytes + (First_Word >> 8) + (First_Word & 0xFF) + Type;
+
+ p = (char *) Data_Str;
+
+ /* If we're reading the last record, ignore it. */
+ switch (Type)
+ {
+ /* Data record */
+ case 0:
+ if (Nb_Bytes == 0)
+ {
+ fprintf(stderr,"0 byte length Data record ignored\n");
+ break;
+ }
+
+ Address = First_Word;
+
+ if (Seg_Lin_Select == SEGMENTED_ADDRESS)
+ Phys_Addr = (Segment << 4) + Address;
+ else
+ /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED
+ Upper_Address = 0 as specified in the Intel spec. until an extended address
+ record is read. */
+ Phys_Addr = ((Upper_Address << 16) + Address);
+
+ /* Check that the physical address stays in the buffer's range. */
+ if ((Phys_Addr >= Lowest_Address) && (Phys_Addr <= Highest_Address))
+ {
+ /* The memory block begins at Lowest_Address */
+ Phys_Addr -= Lowest_Address;
+
+ /* Read the Data bytes. */
+ /* Bytes are written in the Memory block even if checksum is wrong. */
+ i = Nb_Bytes;
+
+ do
+ {
+ result = sscanf (p, "%2x",&temp2);
+ if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+ p += 2;
+
+ /* Check that the physical address stays in the buffer's range. */
+ if (Phys_Addr < Max_Length)
+ {
+ /* Overlapping record will erase the pad bytes */
+ if (Swap_Wordwise)
+ {
+ if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n");
+ Memory_Block[Phys_Addr++ ^ 1] = temp2;
+ }
+ else
+ {
+ if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n");
+ Memory_Block[Phys_Addr++] = temp2;
+ }
+
+ Checksum = (Checksum + temp2) & 0xFF;
+ }
+ }
+ while (--i != 0);
+
+ /* Read the Checksum value. */
+ result = sscanf (p, "%2x",&temp2);
+ if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ /* Verify Checksum value. */
+ Checksum = (Checksum + temp2) & 0xFF;
+ VerifyChecksumValue();
+ }
+ else
+ {
+ if (Seg_Lin_Select == SEGMENTED_ADDRESS)
+ fprintf(stderr,"Data record skipped at %4X:%4X\n",Segment,Address);
+ else
+ fprintf(stderr,"Data record skipped at %8X\n",Phys_Addr);
+ }
+
+ break;
+
+ /* End of file record */
+ case 1:
+ /* Simply ignore checksum errors in this line. */
+ break;
+
+ /* Extended segment address record */
+ case 2:
+ /* First_Word contains the offset. It's supposed to be 0000 so
+ we ignore it. */
+
+ /* First extended segment address record ? */
+ if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED)
+ Seg_Lin_Select = SEGMENTED_ADDRESS;
+
+ /* Then ignore subsequent extended linear address records */
+ if (Seg_Lin_Select == SEGMENTED_ADDRESS)
+ {
+ result = sscanf (p, "%4x%2x",&Segment,&temp2);
+ if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ /* Update the current address. */
+ Phys_Addr = (Segment << 4);
+
+ /* Verify Checksum value. */
+ Checksum = (Checksum + (Segment >> 8) + (Segment & 0xFF) + temp2) & 0xFF;
+ VerifyChecksumValue();
+ }
+ break;
+
+ /* Start segment address record */
+ case 3:
+ /* Nothing to be done since it's for specifying the starting address for
+ execution of the binary code */
+ break;
+
+ /* Extended linear address record */
+ case 4:
+ /* First_Word contains the offset. It's supposed to be 0000 so
+ we ignore it. */
+
+ /* First extended linear address record ? */
+ if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED)
+ Seg_Lin_Select = LINEAR_ADDRESS;
+
+ /* Then ignore subsequent extended segment address records */
+ if (Seg_Lin_Select == LINEAR_ADDRESS)
+ {
+ result = sscanf (p, "%4x%2x",&Upper_Address,&temp2);
+ if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb);
+
+ /* Update the current address. */
+ Phys_Addr = (Upper_Address << 16);
+
+ /* Verify Checksum value. */
+ Checksum = (Checksum + (Upper_Address >> 8) + (Upper_Address & 0xFF) + temp2)
+ & 0xFF;
+ VerifyChecksumValue();
+ }
+ break;
+
+ /* Start linear address record */
+ case 5:
+ /* Nothing to be done since it's for specifying the starting address for
+ execution of the binary code */
+ break;
+ default:
+ fprintf(stderr,"Unknown record type\n");
+ break;
+ }
+ }
+ }
+ while (!feof (Filin));
+ /*-----------------------------------------------------------------------------*/
+
+ fprintf(stdout,"Binary file start = %08X\n",Lowest_Address);
+ fprintf(stdout,"Records start = %08X\n",Records_Start);
+ fprintf(stdout,"Highest address = %08X\n",Highest_Address);
+ fprintf(stdout,"Pad Byte = %X\n", Pad_Byte);
+
+ WriteMemory();
+
+#ifdef USE_FILE_BUFFERS
+ free (FilinBuf);
+ free (FiloutBuf);
+#endif
+
+ fclose (Filin);
+ fclose (Filout);
+
+ if (Status_Checksum_Error && Enable_Checksum_Error)
+ {
+ fprintf(stderr,"Checksum error detected.\n");
+ return 1;
+ }
+
+ if (!Fileread)
+ usage();
+ return 0;
+}