diff options
author | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2008-06-17 17:49:05 +0000 |
---|---|---|
committer | Tzafrir Cohen <tzafrir.cohen@xorcom.com> | 2008-06-17 17:49:05 +0000 |
commit | 53894e5aa1e733a0321a69bd1b12bd794586b4ab (patch) | |
tree | 3e0d4543ad58256dd39cae60ba6de5d7a91f46a6 /xpp/hexfile.c | |
parent | 91d0a6d645e95755c4ae0f0a13919eeb213f6606 (diff) |
Move the xpp utilities to the tools side.
git-svn-id: http://svn.asterisk.org/svn/dahdi/tools/trunk@4374 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'xpp/hexfile.c')
-rw-r--r-- | xpp/hexfile.c | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/xpp/hexfile.c b/xpp/hexfile.c new file mode 100644 index 0000000..2a01b3f --- /dev/null +++ b/xpp/hexfile.c @@ -0,0 +1,567 @@ +/* + * Written by Oron Peled <oron@actcom.co.il> + * Copyright (C) 2006, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include "hexfile.h" + +static const char rcsid[] = "$Id$"; + +static parse_hexfile_report_func_t report_func = NULL; + +parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf) +{ + parse_hexfile_report_func_t old_rf = report_func; + report_func = rf; + return old_rf; +} + +static void chomp(char buf[]) +{ + size_t last = strlen(buf) - 1; + while(last >= 0 && isspace(buf[last])) + buf[last--] = '\0'; +} + +static int hexline_checksum(struct hexline *hexline) +{ + unsigned int i; + unsigned int chksm = 0; + int ll = hexline->d.content.header.ll; + + for(i = 0; i <= sizeof(hexline->d.content.header) + ll; i++) { + chksm += hexline->d.raw[i]; + } + return chksm & 0xFF; +} + +int dump_hexline(int recordno, struct hexline *line, FILE *fp) +{ + uint8_t ll; + uint16_t offset; + uint8_t tt; + uint8_t old_chksum; + uint8_t new_chksum; + uint8_t *data; + unsigned int i; + + ll = line->d.content.header.ll; + offset = line->d.content.header.offset; + tt = line->d.content.header.tt; + fprintf(fp, ":%02X%04X%02X", ll, offset, tt); + data = line->d.content.tt_data.data; + for(i = 0; i < ll; i++) { + fprintf(fp, "%02X", data[i]); + } + old_chksum = data[ll]; + data[ll] = 0; + new_chksum = 0xFF - hexline_checksum(line) + 1; + data[ll] = old_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", + recordno, new_chksum, old_chksum); + return 0; + } + return 1; +} + +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; + + if(hexdata->got_eof) { + if(report_func) + report_func(LOG_ERR, "Extranous data after EOF record\n"); + return -EINVAL; + } + if(hexdata->last_line >= hexdata->maxlines) { + if(report_func) + report_func(LOG_ERR, "Hexfile too large (maxline %d)\n", hexdata->maxlines); + return -ENOMEM; + } + ret = sscanf(buf, "%02X%04X%02X", &ll, &offset, &tt); + if(ret != 3) { + if(report_func) + report_func(LOG_ERR, "Bad line header (only %d items out of 3 parsed)\n", ret); + return -EINVAL; + } + switch(tt) { + case TT_DATA: + break; + case TT_EOF: + if(ll != 0) { + if(report_func) + 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, + "%d: Record %d(EOF): Bad offset = %d\n", + hexdata->last_line, tt, offset); + return -EINVAL; + } + hexdata->got_eof = 1; + break; + 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 */ + 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, "%d: Unimplemented record type %d: %s\n", + hexdata->last_line, tt, buf); + return -EINVAL; + } + buf += 8; /* Skip header */ + if((hexline = new_hexline(ll, offset, tt)) == NULL) { + if(report_func) + report_func(LOG_ERR, "No more memory for hexfile lines\n"); + return -EINVAL; + } + p = buf; + for(i = 0; i < ll + 1; i++) { /* include checksum */ + unsigned int val; + + if((*p == '\0') || (*(p+1) == '\0')) { + if(report_func) + report_func(LOG_ERR, "Short data string '%s'\n", buf); + return -EINVAL; + } + ret = sscanf(p, "%02X", &val); + if(ret != 1) { + if(report_func) + report_func(LOG_ERR, "Bad data byte #%d\n", i); + return -EINVAL; + } + hexline->d.content.tt_data.data[i] = val; + p += 2; + } + if(hexline_checksum(hexline) != 0) { + if(report_func) { + 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++; + return 1; +} + +void free_hexdata(struct hexdata *hexdata) +{ + if(hexdata) { + unsigned int i; + + for(i = 0; i < hexdata->maxlines; i++) + if(hexdata->lines[i] != NULL) + free(hexdata->lines[i]); + free(hexdata); + } +} + +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) { + if(report_func) + report_func(LOG_ERR, "Missing line at #%d\n", i); + return -EINVAL; + } + if(!dump_hexline(i, line, fp)) + return -EINVAL; + } + return 0; +} + +int dump_hexfile2(struct hexdata *hexdata, const char *outfile, uint8_t maxwidth) +{ + FILE *fp; + uint8_t tt; + unsigned int i; + struct hexline *line; + + 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++) { + 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; + } + 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) { + struct hexline *extraline; + uint8_t new_chksum; + unsigned int curr_bytes = (bytesleft >= maxwidth) ? maxwidth : bytesleft; + + /* generate the new line */ + 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; + } + 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 */ + dump_hexline(i, extraline, fp); + /* cleanups */ + 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; +} + +void process_comment(struct hexdata *hexdata, char buf[]) +{ + char *dollar_start; + char *dollar_end; + const char id_prefix[] = "Id: "; + char tmp[BUFSIZ]; + char *p; + int len; + + if(report_func) + report_func(LOG_INFO, "Comment: %s\n", buf + 1); + /* Search for RCS keywords */ + if((dollar_start = strchr(buf, '$')) == NULL) + return; + if((dollar_end = strchr(dollar_start + 1, '$')) == NULL) + return; + /* Crop the '$' signs */ + len = dollar_end - dollar_start; + len -= 2; + memcpy(tmp, dollar_start + 1, len); + tmp[len] = '\0'; + p = tmp; + if(strstr(tmp, id_prefix) == NULL) + return; + p += strlen(id_prefix); + if((p = strchr(p, ' ')) == NULL) + return; + p++; + snprintf(hexdata->version_info, BUFSIZ, "%s", p); + if((p = strchr(hexdata->version_info, ' ')) != NULL) + *p = '\0'; +} + +struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines) +{ + 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) + report_func(LOG_INFO, "Parsing %s\n", fname); + datasize = sizeof(struct hexdata) + maxlines * sizeof(char *); + hexdata = (struct hexdata *)malloc(datasize); + if(!hexdata) { + if(report_func) + report_func(LOG_ERR, "Failed to allocate %d bytes for hexfile contents\n", datasize); + goto err; + } + memset(hexdata, 0, datasize); + hexdata->maxlines = maxlines; + if((fp = fopen(fname, "r")) == NULL) { + if(report_func) + report_func(LOG_ERR, "Failed to open hexfile '%s'\n", fname); + goto err; + } + 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, "%s:%d - Short line\n", fname, line); + goto err; + } + if(buf[0] == '#') { + process_comment(hexdata, buf); + continue; + } + if(buf[0] != ':') { + if(report_func) + report_func(LOG_ERR, "%s:%d - Line begins with 0x%X\n", fname, line, buf[0]); + goto err; + } + if((ret = append_hexline(hexdata, buf + 1)) < 0) { + if(report_func) + report_func(LOG_ERR, "%s:%d - Failed parsing.\n", fname, line); + goto err; + } + } + fclose(fp); + if(report_func) + report_func(LOG_INFO, "%s parsed OK\n", fname); + return hexdata; +err: + free_hexdata(hexdata); + return NULL; +} + +void dump_binary(struct hexdata *hexdata, const char *outfile) +{ + FILE *fp; + unsigned int i; + size_t len; + + if(report_func) + report_func(LOG_INFO, "Dumping binary data into '%s'\n", outfile); + if((fp = fopen(outfile, "w")) == NULL) { + perror(outfile); + exit(1); + } + for(i = 0; i < hexdata->maxlines; i++) { + struct hexline *hexline = hexdata->lines[i]; + + if(!hexline) + break; + switch(hexline->d.content.header.tt) { + case TT_EOF: + if(report_func) + report_func(LOG_INFO, "\ndump: good EOF record"); + 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); + } + } + if(report_func) + report_func(LOG_INFO, "\nDump finished\n"); + 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 bsd_checksum(struct hexdata *hexdata) +{ + unsigned int i; + size_t len; + int ck = 0; + + for(i = 0; i < hexdata->maxlines; i++) { + struct hexline *hexline = hexdata->lines[i]; + unsigned char *p; + + if(!hexline) + break; + if(hexline->d.content.header.tt == TT_EOF) + continue; + len = hexline->d.content.header.ll; + p = hexline->d.content.tt_data.data; + for(; len; p++, len--) { + ck = (ck >> 1) + ((ck & 1) << 15); + ck += *p; + ck &= 0xffff; /* Keep it within bounds. */ + } + } + return ck; +} |