#include #include #include #include #define MAXLINE BUFSIZ static long gethex(char **p, uint8_t *csum) { unsigned int v; int chi; if ( !sscanf(*p, "%02x%n", &v, &chi) ) return -1L; if ( csum ) *csum += v; *p += chi; return v; } static void parse_line(char *p, uint8_t *data, uint8_t *isset) { uint8_t csum; int databytes, type, checksum; int a1, a2, d; int n; uint16_t address; uint8_t buf[256]; csum = 0; if ( (databytes = gethex(&p, &csum)) < 0 ) return; if ( (a1 = gethex(&p, &csum)) < 0 ) return; if ( (a2 = gethex(&p, &csum)) < 0 ) return; address = ((uint16_t)a1 << 8) + a2; if ( (type = gethex(&p, &csum)) < 0 || type != 0x00 ) return; for ( n = 0 ; n < databytes ; n++ ) { if ( (d = gethex(&p, &csum)) < 0 ) return; buf[n] = d; } if ( (checksum = gethex(&p, NULL)) < 0 ) return; if ( checksum != (uint8_t) -csum ) return; memcpy(data+address, buf, databytes); memset(isset+address, 1, databytes); } static void readith(FILE *in, uint8_t *data, uint8_t *isset) { char buffer[MAXLINE]; while ( fgets(buffer, sizeof buffer, in) ) { if ( buffer[0] != ':' ) continue; parse_line(buffer+1, data, isset); } } static void write_buffer(FILE *out, uint8_t *buf, int buf_len, int buf_address, int *spaceinrecord_ptr) { int spaceinrecord = *spaceinrecord_ptr; struct abs_data_hdr { uint8_t type; /* 0 for data */ uint8_t data_bytes; uint8_t zero; /* Reserved */ uint8_t addrh; uint8_t addrhx; uint8_t addrl; uint8_t addrlx; } hdr; uint8_t csum; int i; memset(&hdr, 0, sizeof hdr); csum = 0; for ( i = 0 ; i < buf_len ; i++ ) csum += buf[i]; hdr.data_bytes = buf_len; hdr.addrh = buf_address >> 8; hdr.addrhx = ~hdr.addrh; hdr.addrl = buf_address; hdr.addrlx = ~hdr.addrl; fwrite(&hdr, 1, sizeof hdr, out); fwrite(buf, 1, buf_len, out); putc(csum, out); spaceinrecord -= (buf_len + sizeof hdr + 1); if ( spaceinrecord < sizeof hdr + 4 ) { putc(0xff, out); spaceinrecord--; putc(0x00, out); spaceinrecord--; while ( spaceinrecord-- ) putc(0xee, out); spaceinrecord = 253; } *spaceinrecord_ptr = spaceinrecord; } static void writeabs(FILE *out, uint8_t *data, uint8_t *isset, uint16_t entry_point) { int spaceinrecord = 253; int lastaddr = -999; int addr; uint8_t buf[256]; int buf_address = 0; int buf_len = 0; struct abs_entry_hdr { uint8_t type; /* 0 for data */ uint8_t data_bytes; /* 0 for the entry point */ uint8_t zero; /* Reserved */ uint8_t addrh; uint8_t addrhx; uint8_t addrl; uint8_t addrlx; } hdr; for ( addr = 0 ; addr < 65536 ; addr++ ) { if ( isset[addr] ) { if ( buf_len && (spaceinrecord < (buf_len+11) || addr != lastaddr+1) ) { /* Write previous buffer head */ write_buffer(out, buf, buf_len, buf_address, &spaceinrecord); buf_len = 0; } if ( !buf_len ) buf_address = addr; buf[buf_len++] = data[addr]; lastaddr = addr; } } if ( buf_len ) write_buffer(out, buf, buf_len, buf_address, &spaceinrecord); /* Write entry point */ write_buffer(out, NULL, 0, entry_point, &spaceinrecord); /* Pad to end of record */ while ( spaceinrecord-- ) putc(0xee, out); } /* This obviously assumes a modern computer... */ int ithabs(FILE *in, FILE *out, uint16_t entry_point) { uint8_t data[65536]; /* All the data read from the file */ uint8_t isset[65536]; /* To write or not to write... */ memset(data, 0, 65536); memset(isset, 0, 65536); readith(in, data, isset); writeabs(out, data, isset, entry_point); } int main(int argc, char *argv[]) { FILE *in, *out; uint16_t entry_point; if ( argc != 4 ) { fprintf(stderr, "Usage: %s input output entrypoint\n", argv[0]); exit(1); } in = fopen(argv[1], "rt"); if ( !in ) { perror(argv[1]); exit(1); } out = fopen(argv[2], "wb"); if ( !out ) { perror(argv[2]); exit(1); } entry_point = (uint16_t)strtoul(argv[3], NULL, 0); return !ithabs(in, out, entry_point); }