summaryrefslogtreecommitdiff
path: root/xpp/utils/hexfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/utils/hexfile.c')
-rw-r--r--xpp/utils/hexfile.c316
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;