#include #include #include #include #include #include "get_address.h" #include "xex.h" #ifndef VERSION #define VERSION "???" #endif #define SELF "blob2xex" #define DEFAULT_SIZE 0xffff static FILE *outfh = 0; /* get_offset() is patterned on get_address(), but isn't limited to 64K. TODO: it won't handle offsets >2GB. */ int get_offset(const char *arg) { unsigned int got; if(sscanf(arg, "0x%x", &got) != 1) if(sscanf(arg, "$%x", &got) != 1) if(sscanf(arg, "%d", &got) != 1) { fprintf(stderr, "Invalid offset '%s'\n", arg); return -1; } return (int)got; } void write_segment( const char *infile, const char *outfile, int loadaddr, int initaddr, int offset, int size) { FILE *infh; unsigned char buffer[65536], *p = buffer; xex_segment seg; int c; if(size < 1) { fprintf(stderr, SELF ": invalid size %d (must be >= 1).\n", size); exit(1); } if(strcmp(infile, "-") == 0) { infh = stdout; } else { infh = fopen(infile, "rb"); if(!infh) { perror(outfile); exit(1); } } if(outfh) { seg.has_ff_header = 0; } else { seg.has_ff_header = 1; if(strcmp(outfile, "-") == 0) { outfh = stdout; } else { outfh = fopen(outfile, "wb"); if(!outfh) { perror(outfile); exit(-1); } } } seg.object = buffer; seg.len = 0; seg.start_addr = loadaddr; /* skip bytes in input. don't seek, input might be stdin */ while(offset) { /* TODO: not very efficient to read 1 byte at a time? */ c = getc(infh); if(c < 0) { fprintf(stderr, SELF ": offset extends past EOF on file %s\n", infile); exit(1); /* TODO: handle this better? */ } offset--; } /* read bytes, or until EOF (which is not an error) */ while(size) { c = getc(infh); if(c < 0) break; *p++ = c; seg.len++; size--; } seg.end_addr = seg.start_addr + seg.len - 1; xex_fwrite_seg(&seg, outfh); if(initaddr >= 0) { xex_init_seg(&seg, buffer, initaddr); xex_fwrite_seg(&seg, outfh); } fclose(infh); } void usage() { printf(SELF ": Usage:\n\t" SELF " outfile [-r runaddr] [-l loadaddr [-i initaddr] " "[-o offset] [-s size] infile] ..." "\nSee man page for details.\n"); } int main(int argc, char **argv) { char *outfile = 0, *infile = 0; int i, loadaddr = -1, runaddr = -1, initaddr = -1, offset = 0, size = DEFAULT_SIZE, *param = 0; outfile = argv[1]; if(!outfile || strcmp(outfile, "--help") == 0 || strcmp(outfile, "-h") == 0) { usage(); exit(0); } if(strcmp(outfile, "--version") == 0 || strcmp(outfile, "-V") == 0) { printf(SELF " " VERSION "\n"); exit(0); } if(outfile[0] == '-' && outfile[1] != '\0') { fprintf(stderr, SELF ": output file must come before any options.\n"); exit(1); } if(argc < 5) { fprintf(stderr, SELF ": not enough arguments.\n"); usage(); exit(1); } for(i = 2; i < argc; i++) { char *arg = argv[i]; if(!arg[0]) continue; /* skip empty args */ if(param) { /* previous option needs an argument */ if(param == &offset) { if( (offset = get_offset(arg) ) < 0 ) exit(1); } else { if( (*param = get_address(SELF, arg) ) < 0 ) exit(1); } param = 0; } else if(arg[0] == '-') { infile = 0; switch(arg[1]) { case 'l': param = &loadaddr; break; case 'r': param = &runaddr; break; case 'i': param = &initaddr; break; case 'o': param = &offset; break; case 's': param = &size; break; case 'v': xex_verbose = 1; break; default: fprintf(stderr, SELF ": unknown option '-%c'\n", arg[1]); usage(); exit(1); break; } } else { if(infile) { fprintf(stderr, SELF ": input filename without -l option: %s\n", arg); usage(); exit(1); } infile = arg; write_segment(infile, outfile, loadaddr, initaddr, offset, size); loadaddr = -1; initaddr = -1; offset = 0; size = DEFAULT_SIZE; } } if(param || (loadaddr >= 0) || (initaddr >= 0) || (offset != 0) || (size != DEFAULT_SIZE)) { fprintf(stderr, SELF ": " "warning: extra arguments after last input file ignored.\n"); } if(outfh) { if(runaddr >= 0) { xex_segment seg; unsigned char buf[10]; xex_run_seg(&seg, buf, runaddr); xex_fwrite_seg(&seg, outfh); } fclose(outfh); } return 0; }