#include #include #include #include "xex.h" int xex_errno; static int xex_sys_errno; int xex_verbose = 0; static char *errors[] = { "OK", /* XERR_NONE 0 */ "Failed system call", /* XERR_SYSCALL 1 */ "End address < start address", /* XERR_REVERSED 2 */ "Truncated segment", /* XERR_TRUNCATED 3 */ "No data", /* XERR_NULLDATA 4 */ "Unknown/Invalid XEX error code", /* XERR_MAXERR 5 */ }; int xex_new_seg(xex_segment *seg, unsigned char *data) { int offset = 0; if(data[0] == 0xff && data[1] == 0xff) { offset = 2; seg->has_ff_header = 1; } else { seg->has_ff_header = 0; } seg->start_addr = data[offset] + (data[offset + 1] << 8); offset += 2; seg->end_addr = data[offset] + (data[offset + 1] << 8); offset += 2; seg->object = &data[offset]; seg->len = seg->end_addr - seg->start_addr + 1; return xex_check_seg(seg); } int xex_init_seg(xex_segment *seg, unsigned char *object, unsigned short addr) { object[0] = XEX_LSB(addr); object[1] = XEX_MSB(addr); seg->start_addr = XEX_INITAD; seg->end_addr = XEX_INITAD + 1; seg->object = object; seg->len = 2; seg->has_ff_header = 0; if(xex_verbose) { fprintf(stderr, "xex_init_seg(): created init segment @ %04X:\n", addr); xex_print_seg_info(seg); } return 1; } int xex_run_seg(xex_segment *seg, unsigned char *object, unsigned short addr) { object[0] = XEX_LSB(addr); object[1] = XEX_MSB(addr); seg->start_addr = XEX_RUNAD; seg->end_addr = XEX_RUNAD + 1; seg->object = object; seg->len = 2; seg->has_ff_header = 0; if(xex_verbose) { fprintf(stderr, "xex_run(): created run segment @ %04X:\n", addr); xex_print_seg_info(seg); } return 1; } static int read_char(FILE *file) { int c; c = getc(file); if(c == EOF) { if(ferror(file)) { xex_sys_errno = errno; xex_errno = XERR_SYSCALL; } else { xex_errno = XERR_TRUNCATED; } } return c; } int xex_fread_seg_header(xex_segment *seg, FILE *file) { int c, d; unsigned short addr; xex_errno = XERR_NONE; seg->has_ff_header = 0; seg->object = NULL; c = read_char(file); if(c == EOF) { if(feof(file)) xex_errno = XERR_NONE; return 0; } d = read_char(file); if(d == EOF) return 0; addr = XEX_ADDR(c, d); if(addr == 0xffff) { seg->has_ff_header = 1; c = read_char(file); if(c == EOF) return 0; d = read_char(file); if(d == EOF) return 0; addr = XEX_ADDR(c, d); } if(addr == 0xffff) { xex_errno = XERR_REVERSED; return 0; } seg->start_addr = addr; c = read_char(file); if(c == EOF) return 0; d = read_char(file); if(d == EOF) return 0; addr = XEX_ADDR(c, d); seg->end_addr = addr; seg->len = seg->end_addr - seg->start_addr + 1; if(seg->end_addr < seg->start_addr) { xex_errno = XERR_REVERSED; return 0; } if(xex_verbose) { fprintf(stderr, "xex_fread_seg_header(): read header:\n"); xex_print_seg_info(seg); } return 1; } int xex_fread_seg_data(xex_segment *seg, FILE *file) { int res; xex_errno = XERR_NONE; res = fread(seg->object, 1, seg->len, file); xex_sys_errno = errno; if(xex_verbose) { fprintf(stderr, "xex_fread_seg_data(): read data:\n"); xex_print_seg_info(seg); } if(res == seg->len) return 1; if(ferror(file)) { xex_errno = XERR_SYSCALL; } else { /* EOF or short read */ xex_errno = XERR_TRUNCATED; } return xex_check_seg(seg); } int xex_fread_seg(xex_segment *seg, FILE *file) { unsigned char *tmp = seg->object; int res; xex_errno = XERR_NONE; if(tmp == NULL) { if(xex_verbose) fprintf(stderr, "xex_fread_seg(): seg->object == NULL\n"); xex_errno = XERR_NULLDATA; return 0; } res = xex_fread_seg_header(seg, file); seg->object = tmp; if(!res) return 0; if(!xex_fread_seg_data(seg, file)) return 0; return 1; } int xex_fwrite_seg(xex_segment *seg, FILE *file) { int res; xex_errno = XERR_NONE; if(xex_verbose) { fprintf(stderr, "xex_fwrite_seg(): about to write:\n"); xex_print_seg_info(seg); } if(!xex_check_seg(seg)) return 0; if(seg->has_ff_header) { putc(0xff, file); putc(0xff, file); } putc(XEX_LSB(seg->start_addr), file); putc(XEX_MSB(seg->start_addr), file); putc(XEX_LSB(seg->end_addr), file); putc(XEX_MSB(seg->end_addr), file); res = fwrite(seg->object, 1, seg->len, file); if(res == seg->len) return 1; if(ferror(file)) { xex_errno = XERR_SYSCALL; xex_sys_errno = errno; } else { xex_errno = XERR_TRUNCATED; } return 0; } int xex_get_object(xex_segment *seg, unsigned char *data) { int offset = 0; if(!xex_check_seg(seg)) return 0; if(seg->has_ff_header) { data[0] = data[1] = 0xff; offset = 2; } data[offset] = XEX_LSB(seg->start_addr); data[offset + 1] = XEX_MSB(seg->start_addr); offset += 2; data[offset] = XEX_LSB(seg->end_addr); data[offset + 1] = XEX_MSB(seg->end_addr); offset += 2; memcpy(&data[offset], seg->object, seg->len); return 1; } int xex_check_seg(xex_segment *seg) { int ret = 1; xex_errno = XERR_NONE; if(seg->end_addr < seg->start_addr) { xex_errno = XERR_REVERSED; ret = 0; } if(seg->len != (seg->end_addr - seg->start_addr) + 1) { xex_errno = XERR_TRUNCATED; ret = 0; } if(seg->object == NULL) { xex_errno = XERR_NULLDATA; ret = 0; } if(xex_verbose && !ret && xex_errno != XERR_NULLDATA) fprintf(stderr, "xex_check_seg() FAILED: %s\n", xex_strerror(xex_errno)); return ret; } char *xex_strerror(int err) { if(err < 0 || err >= XERR_MAXERR) err = XERR_MAXERR; if(err == XERR_SYSCALL) return strerror(xex_sys_errno); else return errors[err]; } void xex_perror(char *msg) { fprintf(stderr, "%s: %s\n", msg, xex_strerror(xex_errno)); } void xex_print_seg_info(xex_segment *seg) { xex_check_seg(seg); fprintf(stderr, "has_ff_header==%d start==%04X end==%04X " "len==%04X status==%s\n", seg->has_ff_header, seg->start_addr, seg->end_addr, seg->len, xex_strerror(xex_errno)); }