
8 changed files with 302 additions and 284 deletions
@ -0,0 +1,140 @@ |
|||||
|
/*
|
||||
|
* ihex2bin.c: Read Intel HEX format, write binary data. |
||||
|
* |
||||
|
* By default reads from stdin and writes to stdout. The command-line |
||||
|
* options `-i` and `-o` can be used to specify the input and output |
||||
|
* file, respectively. Specifying an output file allows sparse writes. |
||||
|
* |
||||
|
* NOTE: Many Intel HEX files produced by compilers/etc have data |
||||
|
* beginning at an address greater than zero, potentially causing very |
||||
|
* unnecessarily large files to be created. The command-line option |
||||
|
* `-a` can be used to specify the start address of the output file, |
||||
|
* i.e., the value will be subtracted from the IHEX addresses (the |
||||
|
* result must not be negative). |
||||
|
* |
||||
|
* Alternatively, the command-line option `-A` sets the address offset |
||||
|
* to the first address that would be written (i.e., first byte of |
||||
|
* data written will be at address 0). |
||||
|
* |
||||
|
* Copyright (c) 2013-2019 Kimmo Kulovesi, https://arkku.com
|
||||
|
* Provided with absolutely no warranty, use at your own risk only. |
||||
|
* Distribute freely, mark modified copies as such. |
||||
|
*/ |
||||
|
|
||||
|
#include "kk_ihex_read.h" |
||||
|
#include <stdbool.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
#define AUTODETECT_ADDRESS (~0UL) |
||||
|
|
||||
|
|
||||
|
static unsigned long line_number = 1L; |
||||
|
static unsigned long file_position = 0L; |
||||
|
static unsigned long address_offset = 0UL; |
||||
|
static bool debug_enabled = 0; |
||||
|
|
||||
|
|
||||
|
|
||||
|
static FILE *infile = NULL; |
||||
|
static FILE *outfile = NULL; |
||||
|
|
||||
|
int hex2bin(const char *infilename, const char *outfilename) |
||||
|
{ |
||||
|
int ret = 0; |
||||
|
if (!(infile = fopen(infilename, "r"))) { |
||||
|
return 255; |
||||
|
} |
||||
|
if (!(outfile = fopen(outfilename, "wb"))) { |
||||
|
return 255; |
||||
|
} |
||||
|
|
||||
|
struct ihex_state ihex; |
||||
|
|
||||
|
ihex_count_t count; |
||||
|
char buf[256]; |
||||
|
|
||||
|
ihex_read_at_address( |
||||
|
&ihex, |
||||
|
(address_offset != AUTODETECT_ADDRESS) ? (ihex_address_t)address_offset : 0); |
||||
|
while (fgets(buf, sizeof(buf), infile)) { |
||||
|
count = (ihex_count_t)strlen(buf); |
||||
|
ihex_read_bytes(&ihex, buf, count); |
||||
|
line_number += (count && buf[count - 1] == '\n'); |
||||
|
} |
||||
|
ihex_end_read(&ihex); |
||||
|
|
||||
|
if (infile != stdin) { |
||||
|
(void)fclose(infile); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
ihex_bool_t ihex_data_read(struct ihex_state *ihex, ihex_record_type_t type, ihex_bool_t error) |
||||
|
{ |
||||
|
if (error) { |
||||
|
(void)fprintf(stderr, "Checksum error on line %lu\n", line_number); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
if ((error = (ihex->length < ihex->line_length))) { |
||||
|
(void)fprintf(stderr, "Line length error on line %lu\n", line_number); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
if (!outfile) { |
||||
|
(void)fprintf(stderr, "Excess data after end of file record\n"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
if (type == IHEX_DATA_RECORD) { |
||||
|
unsigned long address = (unsigned long)IHEX_LINEAR_ADDRESS(ihex); |
||||
|
if (address < address_offset) { |
||||
|
if (address_offset == AUTODETECT_ADDRESS) { |
||||
|
// autodetect initial address
|
||||
|
address_offset = address; |
||||
|
if (debug_enabled) { |
||||
|
(void)fprintf(stderr, "Address offset: 0x%lx\n", address_offset); |
||||
|
} |
||||
|
} else { |
||||
|
(void)fprintf(stderr, "Address underflow on line %lu\n", line_number); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
} |
||||
|
address -= address_offset; |
||||
|
if (address != file_position) { |
||||
|
if (debug_enabled) { |
||||
|
(void)fprintf( |
||||
|
stderr, |
||||
|
"Seeking from 0x%lx to 0x%lx on line %lu\n", |
||||
|
file_position, |
||||
|
address, |
||||
|
line_number); |
||||
|
} |
||||
|
if (outfile == stdout || fseek(outfile, (long)address, SEEK_SET)) { |
||||
|
if (file_position < address) { |
||||
|
// "seek" forward in stdout by writing NUL bytes
|
||||
|
do { |
||||
|
(void)fputc('\0', outfile); |
||||
|
} while (++file_position < address); |
||||
|
} else { |
||||
|
perror("fseek"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
} |
||||
|
file_position = address; |
||||
|
} |
||||
|
if (!fwrite(ihex->data, ihex->length, 1, outfile)) { |
||||
|
perror("fwrite"); |
||||
|
exit(EXIT_FAILURE); |
||||
|
} |
||||
|
file_position += ihex->length; |
||||
|
} else if (type == IHEX_END_OF_FILE_RECORD) { |
||||
|
if (debug_enabled) { |
||||
|
(void)fprintf(stderr, "%lu bytes written\n", file_position); |
||||
|
} |
||||
|
if (outfile != stdout) { |
||||
|
(void)fclose(outfile); |
||||
|
} |
||||
|
outfile = NULL; |
||||
|
} |
||||
|
return true; |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
int hex2bin(const char *infilename, const char *outfile); |
Loading…
Reference in new issue