osd-contiki/tools/z80/hex2bin/src/ihx2bin.c

291 lines
6.7 KiB
C

/*
* Copyright (c) 2003-2008, Takahide Matsutsuka.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
/*
* Intel HEX format (extended) to binary format conversion utility.
*/
#include <stdio.h>
#include <string.h>
#include "ihx2bin.h"
#define TYPE_DATA 0
#define TYPE_END 1
#define TYPE_STRING 2
#define TYPE_BYTE 3
#define TYPE_WORD 4
#define MEMORY_SIZE 0x10000
typedef struct {
unsigned int start;
unsigned int end;
char buffer[MEMORY_SIZE];
// current line
int type;
unsigned int address;
unsigned int length;
} Memory;
static
const char NAME_CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_";
/**
* Convert a character to a value.
* @param ch a character to convert
* @return integer value represents the given character
*/
static
int aton(const unsigned char ch) {
if (ch >= '0' && ch <= '9') {
return ch - '0';
}
if (ch >= 'A' && ch <= 'F') {
return ch - 'A' + 10;
}
if (ch >= 'a' && ch <= 'f') {
return ch - 'a' + 10;
}
return 0;
}
/**
* Convert a byte characters from a given file and returns a byte.
* @param in file
* @return -1 if EOF
*/
static
int getByte(FILE *in) {
int ch1, ch2;
if (feof(in)) {
printf("eof");
return -1;
}
ch1 = fgetc(in);
if (feof(in)) {
printf("eof");
return -1;
}
ch2 = fgetc(in);
return 16 * aton(ch1) + aton(ch2);
}
/**
* @return non-zero if error
*/
static
void replace(FILE* in, struct ConvertInfo *info, Memory *memory) {
int i, j;
char name[DEF_NAMELEN];
int len = 0;
// read name
while (len < DEF_NAMELEN - 1) {
char ch = fgetc(in);
if (!strchr(NAME_CHARS, ch)) {
break;
}
name[len] = ch;
len++;
}
name[len] = 0;
for (i = 0; i < info->defsize; i++) {
if (!strcmp(name, info->defs[i].name)) {
int tmp;
char value[DEF_VALUELEN];
memset(value, 0, DEF_VALUELEN);
// replace!
switch (memory->type) {
case TYPE_STRING:
strncpy(&memory->buffer[memory->address], info->defs[i].value, memory->length);
strncpy(value, &memory->buffer[memory->address], memory->length);
if (info->verbose) {
printf("[%s]->[%s], ", name, value);
}
break;
case TYPE_BYTE:
tmp = 0;
for (j = 0; j < 2; j++) {
if (aton(info->defs[i].value[j])) {
tmp = tmp * 16 + aton(info->defs[i].value[j]);
}
}
memory->buffer[memory->address] = tmp;
if (info->verbose) {
printf("[%s]->[%02x], ", name, tmp);
}
break;
case TYPE_WORD:
tmp = 0;
for (j = 0; j < 2; j++) {
tmp = tmp * 16 + aton(info->defs[i].value[j]);
}
memory->buffer[memory->address + 1] = tmp;
tmp = 0;
for (j = 2; j < 4; j++) {
tmp = tmp * 16 + aton(info->defs[i].value[j]);
}
memory->buffer[memory->address] = tmp;
if (info->verbose) {
printf("[%s]->[%02x%02x], ", name,
memory->buffer[memory->address + 1],
memory->buffer[memory->address]);
}
break;
}
break;
}
}
}
/**
* Extract a 64kB memory map from given file.
* IHEX format is as follows:
* :A_B___C_D_....D_E_
* A_ : size of this chunk
* B___: address (big endian)
* C_ : record type (00: notmal data, 01: end)
* extension: 02: char, 03: byte(hex), 04: word(hex, little-endian)
* D_....D_: data
* E_ : check sum
* :0DCCCF00673008D620D607D63013C937C904
* :00000001FF
* @param inFilename file name to convert
* @param start pointer to start address
* @param end pointer to end address
* @return 0 if noerror, otherwise if error
*/
static
int ihx2mem(struct ConvertInfo *info, Memory *memory) {
FILE *in;
memory->start = MEMORY_SIZE - 1;
memory->end = 0;
in = fopen(info->filename, "rb");
if (in == NULL) {
printf("cannot open input file\n");
return 1;
}
while(1) {
int tmp;
// skip checksum and cr/lf
while (!feof(in)) {
if (fgetc(in) == ':') {
break;
}
}
if (feof(in)) {
break;
}
// get length of this chunk
if ((memory->length = getByte(in)) < 0) {
break;
}
// make an address
if ((tmp = getByte(in)) < 0) {
break;
}
memory->address = tmp * 256;
if ((tmp = getByte(in)) < 0) {
break;
}
memory->address += tmp;
// process record type
if ((memory->type = getByte(in)) < 0) {
break;
}
if (memory->type != TYPE_END) {
// modify start and end
if (memory->start > memory->address) {
memory->start = memory->address;
}
if (memory->end < (memory->address + memory->length)) {
memory->end = memory->address + memory->length;
}
}
if (memory->type == TYPE_DATA) {
while (memory->length > 0) {
memory->buffer[memory->address] = getByte(in);
memory->address++;
memory->length--;
}
} else if (memory->type == TYPE_STRING
|| memory->type == TYPE_BYTE
|| memory->type == TYPE_WORD) {
replace(in, info, memory);
}
}
fclose(in);
return 0;
}
/**
* @return written size
*/
int ihx2bin(struct ConvertInfo *info) {
Memory memory;
unsigned int i;
memset(&memory, 0, sizeof(Memory));
if (info->verbose) {
printf("importing ihx: %s, ", info->filename);
}
if (ihx2mem(info, &memory)) {
printf("cannot open input file: %s\n", info->filename);
return 0;
}
if (info->verbose) {
printf("(%04x:%04x)\n", memory.start, memory.end);
}
for (i = memory.start; i < memory.end; i++) {
putc(memory.buffer[i], info->out);
}
return (memory.end - memory.start);
}