diff options
Diffstat (limited to 'xpp/utils/hexfile.c')
-rw-r--r-- | xpp/utils/hexfile.c | 316 |
1 files changed, 224 insertions, 92 deletions
diff --git a/xpp/utils/hexfile.c b/xpp/utils/hexfile.c index 5d6eaa7..1493199 100644 --- a/xpp/utils/hexfile.c +++ b/xpp/utils/hexfile.c @@ -25,6 +25,7 @@ #include <string.h> #include <stdlib.h> #include <errno.h> +#include <ctype.h> #include "hexfile.h" static const char rcsid[] = "$Id$"; @@ -41,11 +42,11 @@ parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_fun static void chomp(char buf[]) { size_t last = strlen(buf) - 1; - while(last >= 0 && (buf[last] == '\n' || buf[last] == '\r')) + while(last >= 0 && isspace(buf[last])) buf[last--] = '\0'; } -int checksum(struct hexline *hexline) +static int hexline_checksum(struct hexline *hexline) { unsigned int i; unsigned int chksm = 0; @@ -57,7 +58,7 @@ int checksum(struct hexline *hexline) return chksm & 0xFF; } -int dump_hexline(int recordno, struct hexline *line, FILE *outfile) +int dump_hexline(int recordno, struct hexline *line, FILE *fp) { uint8_t ll; uint16_t offset; @@ -70,16 +71,16 @@ int dump_hexline(int recordno, struct hexline *line, FILE *outfile) ll = line->d.content.header.ll; offset = line->d.content.header.offset; tt = line->d.content.header.tt; - fprintf(outfile, ":%02X%04X%02X", ll, offset, tt); + fprintf(fp, ":%02X%04X%02X", ll, offset, tt); data = line->d.content.tt_data.data; for(i = 0; i < ll; i++) { - fprintf(outfile, "%02X", data[i]); + fprintf(fp, "%02X", data[i]); } old_chksum = data[ll]; data[ll] = 0; - new_chksum = 0xFF - checksum(line) + 1; + new_chksum = 0xFF - hexline_checksum(line) + 1; data[ll] = old_chksum; - fprintf(outfile, "%02X\n", new_chksum); + fprintf(fp, "%02X\n", new_chksum); if(new_chksum != old_chksum) { if(report_func) report_func(LOG_ERR, "record #%d: new_chksum(%02X) != old_chksum(%02X)\n", @@ -89,22 +90,38 @@ int dump_hexline(int recordno, struct hexline *line, FILE *outfile) return 1; } -static int update_hexline(struct hexdata *hexdata, char *buf) +struct hexline *new_hexline(uint8_t datalen, uint16_t offset, uint8_t tt) +{ + struct hexline *hexline; + size_t allocsize; + + allocsize = sizeof(struct hexline) + datalen + 1; /* checksum byte */ + if((hexline = malloc(allocsize)) == NULL) { + if(report_func) + report_func(LOG_ERR, "No more memory\n"); + return NULL; + } + memset(hexline, 0, allocsize); + hexline->d.content.header.ll = datalen; + hexline->d.content.header.offset = offset; + hexline->d.content.header.tt = tt; + return hexline; +} + +static int append_hexline(struct hexdata *hexdata, char *buf) { int ret; unsigned int ll, offset, tt; char *p; struct hexline *hexline; unsigned int i; - int allocsize; - unsigned int last_line = hexdata->last_line; if(hexdata->got_eof) { if(report_func) report_func(LOG_ERR, "Extranous data after EOF record\n"); return -EINVAL; } - if(last_line >= hexdata->maxlines) { + if(hexdata->last_line >= hexdata->maxlines) { if(report_func) report_func(LOG_ERR, "Hexfile too large (maxline %d)\n", hexdata->maxlines); return -ENOMEM; @@ -121,41 +138,98 @@ static int update_hexline(struct hexdata *hexdata, char *buf) case TT_EOF: if(ll != 0) { if(report_func) - report_func(LOG_ERR, "Bad EOF record len = %d\n", ll); + report_func(LOG_ERR, + "%d: Record %d(EOF): Bad len = %d\n", + hexdata->last_line, tt, ll); return -EINVAL; } if(offset != 0) { if(report_func) - report_func(LOG_ERR, "Bad EOF record offset = %d\n", offset); + report_func(LOG_ERR, + "%d: Record %d(EOF): Bad offset = %d\n", + hexdata->last_line, tt, offset); return -EINVAL; } hexdata->got_eof = 1; break; - case TT_EXT_SEG: /* Unimplemented */ - case TT_START_SEG: /* Unimplemented */ - case TT_EXT_LIN: /* Unimplemented */ + case TT_EXT_SEG: + if(ll != 2) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(EXT_SEG): Bad len = %d\n", + hexdata->last_line, tt, ll); + return -EINVAL; + } + if(offset != 0) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(EXT_SEG): Bad offset = %d\n", + hexdata->last_line, tt, offset); + return -EINVAL; + } + break; + case TT_START_SEG: + if(ll != 4) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(START_SEG): Bad len = %d\n", + hexdata->last_line, tt, ll); + return -EINVAL; + } + if(offset != 0) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(START_SEG): Bad offset = %d\n", + hexdata->last_line, tt, offset); + return -EINVAL; + } + break; + case TT_EXT_LIN: + if(ll != 2) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(EXT_LIN): Bad len = %d\n", + hexdata->last_line, tt, ll); + return -EINVAL; + } + if(offset != 0) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(EXT_LIN): Bad offset = %d\n", + hexdata->last_line, tt, ll); + return -EINVAL; + } + break; case TT_START_LIN: /* Unimplemented */ - return 1; + if(ll != 4) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(EXT_LIN): Bad len = %d\n", + hexdata->last_line, tt, ll); + return -EINVAL; + } + if(offset != 0) { + if(report_func) + report_func(LOG_ERR, + "%d: Record %d(EXT_LIN): Bad offset = %d\n", + hexdata->last_line, tt, ll); + return -EINVAL; + } + break; default: if(report_func) - report_func(LOG_ERR, "Unknown record type %d\n", tt); + report_func(LOG_ERR, "%d: Unimplemented record type %d: %s\n", + hexdata->last_line, tt, buf); return -EINVAL; } buf += 8; /* Skip header */ - ll++; /* include the checksum for now */ - allocsize = sizeof(struct hexline) + ll; - if((hexline = (struct hexline *)malloc(allocsize)) == NULL) { + if((hexline = new_hexline(ll, offset, tt)) == NULL) { if(report_func) report_func(LOG_ERR, "No more memory for hexfile lines\n"); return -EINVAL; } - memset(hexline, 0, allocsize); - hexline->d.content.header.ll = ll; - hexline->d.content.header.offset = offset; - hexline->d.content.header.tt = tt; - hexdata->lines[last_line++] = hexline; p = buf; - for(i = 0; i < ll; i++) { + for(i = 0; i < ll + 1; i++) { /* include checksum */ unsigned int val; if((*p == '\0') || (*(p+1) == '\0')) { @@ -172,14 +246,15 @@ static int update_hexline(struct hexdata *hexdata, char *buf) hexline->d.content.tt_data.data[i] = val; p += 2; } - hexline->d.content.header.ll--; /* Fix the checksum */ - if(checksum(hexline) != 0) { + if(hexline_checksum(hexline) != 0) { if(report_func) { - report_func(LOG_ERR, "Bad checksum (%d instead of 0)\n", checksum(hexline)); - dump_hexline(last_line, hexline, stderr); + report_func(LOG_ERR, "Bad checksum (%d instead of 0)\n", + hexline_checksum(hexline)); + dump_hexline(hexdata->last_line, hexline, stderr); } return -EINVAL; } + hexdata->lines[hexdata->last_line] = hexline; if(hexdata->got_eof) return 0; hexdata->last_line++; @@ -198,10 +273,19 @@ void free_hexdata(struct hexdata *hexdata) } } -int dump_hexfile(struct hexdata *hexdata, FILE *outfile) +int dump_hexfile(struct hexdata *hexdata, const char *outfile) { + FILE *fp; unsigned int i; + if(report_func) + report_func(LOG_INFO, "Dumping hex data into '%s'\n", outfile); + if(!outfile || strcmp(outfile, "-") == 0) + fp = stdout; + else if((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + exit(1); + } for(i = 0; i <= hexdata->last_line; i++) { struct hexline *line = hexdata->lines[i]; if(!line) { @@ -209,72 +293,76 @@ int dump_hexfile(struct hexdata *hexdata, FILE *outfile) report_func(LOG_ERR, "Missing line at #%d\n", i); return -EINVAL; } - if(!dump_hexline(i, line, outfile)) + if(!dump_hexline(i, line, fp)) return -EINVAL; } return 0; } -int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth) +int dump_hexfile2(struct hexdata *hexdata, const char *outfile, uint8_t maxwidth) { - uint8_t ll; + FILE *fp; uint8_t tt; - uint8_t new_chksum; - uint8_t *data; unsigned int i; - unsigned int j; + struct hexline *line; - if (maxwidth <= sizeof(hexdata->lines[0]->d.content.header) ){ - if(report_func) - report_func(LOG_ERR, "Line width too small %d\n", maxwidth); - return -EINVAL; + if(report_func) + report_func(LOG_INFO, + "Dumping hex data into '%s' (maxwidth=%d)\n", + outfile, maxwidth); + if(!outfile || strcmp(outfile, "-") == 0) + fp = stdout; + else if((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + exit(1); } - + if(maxwidth == 0) + maxwidth = UINT8_MAX; for(i = 0; i <= hexdata->last_line; i++) { - struct hexline *line = hexdata->lines[i]; - struct hexline *extraline; - int allocsize; - int bytesleft = 0; - int extra_offset = 0; - unsigned int this_line = 0; + int bytesleft = 0; + int extra_offset = 0; + int base_offset; + uint8_t *base_data; + line = hexdata->lines[i]; if(!line) { if(report_func) report_func(LOG_ERR, "Missing line at #%d\n", i); return -EINVAL; } - ll = line->d.content.header.ll; - bytesleft = ll; + bytesleft = line->d.content.header.ll; /* split the line into several lines */ tt = line->d.content.header.tt; + base_offset = line->d.content.header.offset; + base_data = line->d.content.tt_data.data; while (bytesleft > 0) { - this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft; - allocsize = sizeof(struct hexline) + this_line + 1; + struct hexline *extraline; + uint8_t new_chksum; + unsigned int curr_bytes = (bytesleft >= maxwidth) ? maxwidth : bytesleft; + /* generate the new line */ - if((extraline = (struct hexline *)malloc(allocsize)) == NULL) { + if((extraline = new_hexline(curr_bytes, base_offset + extra_offset, tt)) == NULL) { if(report_func) report_func(LOG_ERR, "No more memory for hexfile lines\n"); return -EINVAL; } - memset( extraline, 0, allocsize ); - extraline->d.content.header.ll = this_line; - extraline->d.content.header.offset = line->d.content.header.offset + extra_offset; - extraline->d.content.header.tt = tt; - memcpy( extraline->d.content.tt_data.data, line->d.content.tt_data.data+extra_offset, this_line); - new_chksum = 0xFF - checksum(extraline) + 1; + memcpy(extraline->d.content.tt_data.data, base_data + extra_offset, curr_bytes); + new_chksum = 0xFF - hexline_checksum(extraline) + 1; + extraline->d.content.tt_data.data[curr_bytes] = new_chksum; /* print it */ - data = extraline->d.content.tt_data.data; - fprintf(outfile, ":%02X%04X%02X", extraline->d.content.header.ll, extraline->d.content.header.offset, tt); - for(j = 0; j < this_line; j++) { - fprintf(outfile, "%02X", data[j]); - } - fprintf(outfile, "%02X\n", new_chksum); + dump_hexline(i, extraline, fp); /* cleanups */ - free( extraline); - extra_offset += this_line; - bytesleft -= this_line; + free(extraline); + extra_offset += curr_bytes; + bytesleft -= curr_bytes; } } + if(tt != TT_EOF) { + if(report_func) + report_func(LOG_ERR, "Missing EOF record\n"); + return -EINVAL; + } + dump_hexline(i, line, fp); return 0; } @@ -313,12 +401,13 @@ void process_comment(struct hexdata *hexdata, char buf[]) struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines) { - FILE *fp; - struct hexdata *hexdata = NULL; - int datasize; - char buf[BUFSIZ]; - int line; - int ret; + FILE *fp; + struct hexdata *hexdata = NULL; + int datasize; + char buf[BUFSIZ]; + int line; + int dos_eof = 0; + int ret; assert(fname != NULL); if(report_func) @@ -337,27 +426,34 @@ struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines) report_func(LOG_ERR, "Failed to open hexfile '%s'\n", fname); goto err; } - line = 0; - while(fgets(buf, BUFSIZ, fp)) { - line++; + for(line = 1; fgets(buf, BUFSIZ, fp); line++) { + if(dos_eof) { + if(report_func) + report_func(LOG_ERR, "%s:%d - Got DOS EOF character before true EOF\n", fname, line); + goto err; + } + if(buf[0] == 0x1A && buf[1] == '\0') { /* DOS EOF char */ + dos_eof = 1; + continue; + } + chomp(buf); if(buf[0] == '\0') { if(report_func) - report_func(LOG_ERR, "Short line at %s:%d\n", fname, line); + report_func(LOG_ERR, "%s:%d - Short line\n", fname, line); goto err; } - chomp(buf); if(buf[0] == '#') { process_comment(hexdata, buf); continue; } if(buf[0] != ':') { if(report_func) - report_func(LOG_ERR, "Line begins with 0x%X at %s:%d\n", buf[0], fname, line); + report_func(LOG_ERR, "%s:%d - Line begins with 0x%X\n", fname, line, buf[0]); goto err; } - if((ret = update_hexline(hexdata, buf + 1)) < 0) { + if((ret = append_hexline(hexdata, buf + 1)) < 0) { if(report_func) - report_func(LOG_ERR, "Failed parsing %s at line: %d\n", fname, line); + report_func(LOG_ERR, "%s:%d - Failed parsing.\n", fname, line); goto err; } } @@ -387,16 +483,33 @@ void dump_binary(struct hexdata *hexdata, const char *outfile) if(!hexline) break; - if(hexline->d.content.header.tt == TT_EOF) { + switch(hexline->d.content.header.tt) { + case TT_EOF: if(report_func) report_func(LOG_INFO, "\ndump: good EOF record"); - continue; - } - if(report_func) - report_func(LOG_INFO, "dump: %6d\r", i); - len = hexline->d.content.header.ll; - if(fwrite(hexline->d.content.tt_data.data, 1, len, fp) != len) { - perror("write"); + break; + case TT_DATA: + if(report_func) + report_func(LOG_INFO, "dump: %6d\r", i); + len = hexline->d.content.header.ll; + if(fwrite(hexline->d.content.tt_data.data, 1, len, fp) != len) { + perror("write"); + exit(1); + } + break; + case TT_EXT_SEG: + case TT_START_SEG: + case TT_EXT_LIN: + case TT_START_LIN: + if(report_func) + report_func(LOG_INFO, + "\ndump(%d): ignored record type %d", + i, hexline->d.content.header.tt); + break; + default: + if(report_func) + report_func(LOG_ERR, "dump: Unknown record type %d\n", + hexline->d.content.header.tt); exit(1); } } @@ -405,11 +518,30 @@ void dump_binary(struct hexdata *hexdata, const char *outfile) fclose(fp); } +void gen_hexline(const uint8_t *data, uint16_t addr, size_t len, FILE *output) +{ + struct hexline *hexline; + + if(!data) { + fprintf(output, ":%02X%04X%02XFF\n", 0, 0, TT_EOF); + return; + } + if((hexline = new_hexline(len, addr, (!data) ? TT_EOF : TT_DATA)) == NULL) { + if(report_func) + report_func(LOG_ERR, "No more memory\n"); + return; + } + if(data) + memcpy(&hexline->d.content.tt_data, data, len); + dump_hexline(0, hexline, output); + free(hexline); +} + /* * Algorithm lifted of sum(1) implementation from coreutils. * We chose the default algorithm (BSD style). */ -int calc_checksum(struct hexdata *hexdata) +int bsd_checksum(struct hexdata *hexdata) { unsigned int i; size_t len; |