+++ /dev/null
-/*
- * Copyright © 2008 Keith Packard <keithp@keithp.com>
- *
- * 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.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#include "ccdbg.h"
-#include <stdarg.h>
-#include <ctype.h>
-
-struct hex_input {
- FILE *file;
- int line;
- char *name;
-};
-
-enum hex_read_state {
- read_marker,
- read_length,
- read_address,
- read_type,
- read_data,
- read_checksum,
- read_newline,
- read_white,
- read_done,
-};
-
-
-static void
-ccdbg_hex_error(struct hex_input *input, char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- fprintf(stderr, "Hex error %s:%d: ", input->name, input->line);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
-}
-
-static void
-ccdbg_hex_free(struct hex_record *record)
-{
- if (!record) return;
- free(record);
-}
-
-static struct hex_record *
-ccdbg_hex_alloc(uint8_t length)
-{
- struct hex_record *record;
-
- record = calloc(1, sizeof(struct hex_record) + length);
- record->length = length;
- return record;
-}
-
-static int
-ishex(char c)
-{
- return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
-}
-
-static int
-fromhex(char c)
-{
- if (isdigit(c))
- return c - '0';
- if ('a' <= c && c <= 'f')
- return c - 'a' + 10;
- if ('A' <= c && c <= 'F')
- return c - 'A' + 10;
- abort();
- return 0;
-}
-
-static uint8_t
-ccdbg_hex_checksum(struct hex_record *record)
-{
- uint8_t checksum = 0;
- int i;
-
- checksum += record->length;
- checksum += record->address >> 8;
- checksum += record->address & 0xff;
- checksum += record->type;
- for (i = 0; i < record->length; i++)
- checksum += record->data[i];
- return -checksum;
-}
-
-static struct hex_record *
-ccdbg_hex_read_record(struct hex_input *input)
-{
- struct hex_record *record = NULL;
- enum hex_read_state state = read_marker;
- char c;
- int nhexbytes;
- uint32_t hex;
- uint32_t ndata;
- uint8_t checksum;
-
- while (state != read_done) {
- c = getc(input->file);
- if (c == EOF && state != read_white) {
- ccdbg_hex_error(input, "Unexpected EOF");
- goto bail;
- }
- if (c == ' ')
- continue;
- if (c == '\n')
- input->line++;
- switch (state) {
- case read_marker:
- if (c != ':') {
- ccdbg_hex_error(input, "Missing ':'");
- goto bail;
- }
- state = read_length;
- nhexbytes = 2;
- hex = 0;
- break;
- case read_length:
- case read_address:
- case read_type:
- case read_data:
- case read_checksum:
- if (!ishex(c)) {
- ccdbg_hex_error(input, "Non-hex char '%c'",
- c);
- goto bail;
- }
- hex = hex << 4 | fromhex(c);
- --nhexbytes;
- if (nhexbytes != 0)
- break;
-
- switch (state) {
- case read_length:
- record = ccdbg_hex_alloc(hex);
- if (!record) {
- ccdbg_hex_error(input, "Out of memory");
- goto bail;
- }
- state = read_address;
- nhexbytes = 4;
- break;
- case read_address:
- record->address = hex;
- state = read_type;
- nhexbytes = 2;
- break;
- case read_type:
- record->type = hex;
- state = read_data;
- nhexbytes = 2;
- ndata = 0;
- break;
- case read_data:
- record->data[ndata] = hex;
- ndata++;
- nhexbytes = 2;
- break;
- case read_checksum:
- record->checksum = hex;
- state = read_newline;
- break;
- default:
- break;
- }
- if (state == read_data)
- if (ndata == record->length) {
- nhexbytes = 2;
- state = read_checksum;
- }
- hex = 0;
- break;
- case read_newline:
- if (c != '\n' && c != '\r') {
- ccdbg_hex_error(input, "Missing newline");
- goto bail;
- }
- state = read_white;
- break;
- case read_white:
- if (!isspace(c)) {
- if (c == '\n')
- input->line--;
- if (c != EOF)
- ungetc(c, input->file);
- state = read_done;
- }
- break;
- case read_done:
- break;
- }
- }
- checksum = ccdbg_hex_checksum(record);
- if (checksum != record->checksum) {
- ccdbg_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n",
- record->checksum, checksum);
- goto bail;
- }
- return record;
-
-bail:
- ccdbg_hex_free(record);
- return NULL;
-}
-
-void
-ccdbg_hex_file_free(struct hex_file *hex)
-{
- int i;
-
- if (!hex)
- return;
- for (i = 0; i < hex->nrecord; i++)
- ccdbg_hex_free(hex->records[i]);
- free(hex);
-}
-
-static int
-ccdbg_hex_record_compar(const void *av, const void *bv)
-{
- const struct hex_record *a = *(struct hex_record **) av;
- const struct hex_record *b = *(struct hex_record **) bv;
-
- return (int) a->address - (int) b->address;
-}
-
-struct hex_file *
-ccdbg_hex_file_read(FILE *file, char *name)
-{
- struct hex_input input;
- struct hex_file *hex = NULL, *newhex;
- struct hex_record *record;
- int srecord = 1;
- int done = 0;
-
- hex = calloc(sizeof (struct hex_file) + sizeof (struct hex_record *), 1);
- input.name = name;
- input.line = 1;
- input.file = file;
- while (!done) {
- record = ccdbg_hex_read_record(&input);
- if (!record)
- goto bail;
- if (hex->nrecord == srecord) {
- srecord *= 2;
- newhex = realloc(hex,
- sizeof (struct hex_file) +
- srecord * sizeof (struct hex_record *));
- if (!newhex)
- goto bail;
- hex = newhex;
- }
- hex->records[hex->nrecord++] = record;
- if (record->type == HEX_RECORD_EOF)
- done = 1;
- }
- /*
- * Sort them into increasing addresses, except for EOF
- */
- qsort(hex->records, hex->nrecord - 1, sizeof (struct hex_record *),
- ccdbg_hex_record_compar);
- return hex;
-
-bail:
- ccdbg_hex_file_free(hex);
- return NULL;
-}
-
-struct hex_image *
-ccdbg_hex_image_create(struct hex_file *hex)
-{
- struct hex_image *image;
- struct hex_record *first, *last, *record;
- int i;
- uint32_t base, bound;
- uint32_t offset;
- int length;
-
- first = hex->records[0];
- last = hex->records[hex->nrecord - 2]; /* skip EOF */
- base = (uint32_t) first->address;
- bound = (uint32_t) last->address + (uint32_t) last->length;
- length = bound - base;
- image = calloc(sizeof(struct hex_image) + length, 1);
- if (!image)
- return NULL;
- image->address = base;
- image->length = length;
- memset(image->data, 0xff, length);
- for (i = 0; i < hex->nrecord - 1; i++) {
- record = hex->records[i];
- offset = record->address - base;
- memcpy(image->data + offset, record->data, record->length);
- }
- return image;
-}
-
-void
-ccdbg_hex_image_free(struct hex_image *image)
-{
- free(image);
-}
-
-int
-ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b)
-{
- if (a->length != b->length)
- return 0;
- if (memcmp(a->data, b->data, a->length) != 0)
- return 0;
- return 1;
-}