// // ac_hexfile.c - handle intel hex files // // Copyright (C) 2006 Nathan (Acorn) Pooley // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as published by the Free Software Foundation. // // 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 (gpl.txt) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // You can contact the author, Nathan (Acorn) Pooley, by writing // to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA 94086, USA // or through the form at http://www.rawbw.com/~acorn/wand/feedback.html // //#@DOC@ handle intel hex files //########################################################################### //############################### INCLUDES ################################## //########################################################################### #include "ac_hexfile.h" #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> //########################################################################### //############################### TYPEDEFS ################################## //########################################################################### //=========================================================================== // AcHexRegion //=========================================================================== typedef struct AcHexRegionRec { void *data; AcHexAddress addr; AcHexOffset len; AcHexOffset alloc; struct AcHexRegionRec *next; struct AcHexRegionRec *prev; } AcHexRegion; //=========================================================================== // AcHexFile //=========================================================================== struct AcHexFileRec { char *filename; AcHexRegion head; // this region always contains addr 0 // It may have a length of 0 }; //########################################################################### //############################### PROTOTYPES ################################ //########################################################################### static void AcHexRegionDelete(AcHexFile *f, AcHexRegion *r); //########################################################################### //############################### GLOBALS ################################### //########################################################################### static int debug = 0; //########################################################################### //############################### CODE ###################################### //########################################################################### //=========================================================================== // AcHexGetFilename() //=========================================================================== const char *AcHexGetFilename(AcHexFile *f) { return f->filename ? f->filename : ""; } //=========================================================================== // AcHexGetline() //=========================================================================== static int AcHexGetline(FILE *fp, unsigned char *buf, int maxlen) { unsigned char *s = buf; unsigned char *e = buf + maxlen; int c; while(1) { c = getc(fp); if (c == EOF || c == '\n' || c == '\r') { break; } if (s==e) { return -2; // error } *(s++) = c; } if (s==buf && c==EOF) return -1; return s-buf; } //=========================================================================== // AcHexDelete() - delete hex structure //=========================================================================== void AcHexDelete(AcHexFile *f) { if (f->filename) { free(f->filename); } while(f->head.next != &f->head) { AcHexRegionDelete(f, f->head.next); } AcHexRegionDelete(f, &f->head); free(f); } //=========================================================================== // AcHexCreate() - Create hex structure //=========================================================================== AcHexFile *AcHexCreate(void) { AcHexFile *f; f = calloc(1,sizeof(AcHexFile)); if (f) { f->head.next = &f->head; f->head.prev = &f->head; } return f; } //=========================================================================== // AcHexToBin() - convert ascii buffer to binary //=========================================================================== static int AcHexToBin(unsigned char *s,int cnt) { unsigned int tmp = 0; int htmp = 0; unsigned char *e = s+cnt; unsigned char *d = s; unsigned char *buf = s; int sum = 0; for(;s != e; s++) { int c = *s; if (isspace(c)) continue; if (!isxdigit(c)) { return -1; } if (isdigit(c)) { c -= '0'; } else { c = toupper(c) - 'A' + 10; } if (htmp) { unsigned int num = tmp | c; sum += num; *(d++) = num; htmp = 0; } else { tmp = c << 4; htmp = 1; } } if (htmp || (sum & 0xff)) return -1; return d-buf; } //=========================================================================== // AcHexLoadFile() - load entire file into a hexfile sturcture //=========================================================================== // Curently format is ignored - use 0 AcHexFile *AcHexLoadFile(const char *filename, int format) { unsigned char buf[100]; AcHexFile *f; int err = 0; int done = 0; int type; AcHexAddress addr; AcHexAddress addrhi = 0; FILE *fp; if (format) return 0; f = AcHexCreate(); if (!f) return 0; f->filename = strdup(filename); fp = fopen(filename,"r"); if (!fp) { AcHexDelete(f); fprintf(stderr,"Hex file loading error (could not open file)\n"); return 0; } while(!done) { int cnt = AcHexGetline(fp, buf, sizeof(buf)-1); unsigned char *s; if (cnt < 11) { if (cnt == -2) { fprintf(stderr,"Hex file loading error (a)\n"); err = 1; break; } if (cnt > 0 && buf[0] == ':') { fprintf(stderr,"Hex file loading error (b)\n"); err = 1; break; } if (cnt < 0) break; continue; } if (buf[0] != ':') continue; cnt = AcHexToBin(buf+1,cnt-1); if (cnt < 5) { fprintf(stderr,"Hex file loading error (c)\n"); err=1; break; } cnt -= 5; s = buf+1; if (*s != cnt) { fprintf(stderr,"Hex file loading error (d)\n"); err=1; break; } if (debug) { printf("cnt=%d ",cnt); } s++; addr = addrhi + (s[0] << 8) + s[1]; if (debug) { printf("addr=%08lx addrhi=%08lx ",addr,addrhi); } s += 2; type = *s; if (debug) { printf("TYPE=%02x\n",type); } s++; switch(type) { case 0x00: // data record if (AcHexSetBytes(f,addr,s,cnt)) { err = 1; done = 1; fprintf(stderr,"Hex file loading error (e)\n"); } break; case 0x02: // extended segment addr record if (cnt != 2 || ((addr-addrhi) & 0xffff)) { fprintf(stderr,"Hex file loading error (f)\n"); err = 1; done = 1; break; } addrhi = (s[0] << 16) + (s[1] << 8); break; case 0x04: // extended addr record if (cnt != 2 || ((addr-addrhi) & 0xffff)) { fprintf(stderr,"Hex file loading error (g)\n"); err = 1; done = 1; break; } addrhi = (s[0] << 24) + (s[1] << 16); break; case 0x01: // EOF record if (cnt != 0 || ((addr-addrhi) & 0xffff)) { fprintf(stderr,"Hex file loading error (h)\n"); err = 1; break; } done = 1; break; default: fprintf(stderr,"Hex file loading error (bad record type)\n"); err=1; done = 1; break; } } fclose(fp); if (err || !done) { AcHexDelete(f); fprintf(stderr,"Hex file loading error (i)\n"); return 0; } return f; } //=========================================================================== // AcHexRegionSizeCalc() //=========================================================================== static AcHexOffset AcHexRegionSizeCalc(AcHexOffset req) { AcHexOffset size = 2048; req += 1024; while(size < req) size *= 2; return size; } //=========================================================================== // AcHexRegionDelete() //=========================================================================== static void AcHexRegionDelete(AcHexFile *f, AcHexRegion *r) { if (r->data) { free(r->data); } // // Never free the head node // if (r == &f->head) { r->data = 0; r->alloc = 0; r->len = 0; return; } r->next->prev = r->prev; r->prev->next = r->next; free(r); } //=========================================================================== // AcHexRegionCreate() //=========================================================================== static AcHexRegion *AcHexRegionCreate( AcHexFile *f, AcHexAddress addr, AcHexOffset size) { AcHexRegion *r = calloc(1,sizeof(AcHexRegion)); if (!r) return 0; r->addr = addr; r->data = calloc(size,1); if (!r->data) { free(r); return 0; } r->len = 0; r->alloc = size; r->data = calloc(size/4, 4); return r; } //=========================================================================== // AcHexRegionSplit() - split a region into 2 regions //=========================================================================== // // 0 = success // -1 = failure // static int AcHexRegionSplit( AcHexFile *f, AcHexRegion *r, AcHexAddress addr) { AcHexOffset len0, len1; AcHexRegion *r2; if (addr <= r->addr || addr >= r->addr + r->len) return -1; len0 = addr - r->addr; len1 = r->len - len0; r2 = AcHexRegionCreate(f,addr,len1); if (!r2) return -1; memcpy(r2->data, (char*)r->data + len0, len1); r->len = len0; r2->prev = r; r2->next = r->next; r2->next->prev = r2; r->next = r2; return 0; } //=========================================================================== // AcHexRegionPrint() - print region info //=========================================================================== static void AcHexRegionPrint(AcHexFile *f, AcHexRegion *r) { printf(" Region %08lx - %08lx size=%08lx alloc=%08lx ptr=%08lx\n", (long)(r->addr), (long)(r->addr + r->len - 1), (long)(r->len), (long)(r->alloc), (long)(r->data)); } //=========================================================================== // AcBytePrint() - print hex bytes from binary buffer //=========================================================================== void AcBytePrint(void *buf, unsigned long len, unsigned long addr, int rpt) { unsigned long o = 0; unsigned char *p = buf; for (; o<len; o++, addr++, p++) { if (!o || !(addr&0xf)) { if (o) { printf("\n"); } while (rpt) { unsigned char *s = p+1; unsigned long o2 = o+1; unsigned long o3 = o+2; while(o2<len && *s == *p) { o2++; s++; } o2 = o2 - o - 1; s = p+2; while(o3<len-1 && s[0]==p[0] && s[1]==p[1]) { o3 += 2; s += 2; } o3 = o3 - o - 1; if (o2 >= o3 && o2 >= 16) { printf(" %08lx - %08lx = %02x\n", (long)addr, (long)(addr + o2), *p); addr += o2 + 1; o += o2 + 1; p += o2 + 1; } else if (o3 >= 16) { printf(" %08lx - %08lx = %02x %02x\n", (long)addr, (long)(addr + o3), p[0],p[1]); addr += o3 + 1; o += o3 + 1; p += o3 + 1; } else { if (o>=len) return; break; } } printf(" %08lx: ",addr); } printf("%02x ",*p); } printf("\n"); } //=========================================================================== // AcHexRegionPrintData() - print region data //=========================================================================== static void AcHexRegionPrintData(AcHexFile *f, AcHexRegion *r) { #if 1 AcBytePrint(r->data, r->len, r->addr, 1); #else AcHexOffset o = 0; AcHexAddress a = r->addr; unsigned char *p = r->data; for (; o<r->len; o++, a++, p++) { if (!o || !(a&0xf)) { if (o) { printf("\n"); } printf(" %08lx: ",a); } printf("%02x ",*p); } printf("\n"); #endif } //=========================================================================== // AcHexPrint() - print region data //=========================================================================== void AcHexPrint(AcHexFile *f, int showdata) { AcHexRegion *r = &f->head; printf("Hex file %s\n", f->filename?f->filename:""); do { AcHexRegionPrint(f,r); if (showdata) { AcHexRegionPrintData(f,r); } r = r->next; } while (r != &f->head); } //=========================================================================== // AcHexRegionFind() - find region containing or preceding addr //=========================================================================== static AcHexRegion *AcHexRegionFind(AcHexFile *f, AcHexAddress addr) { AcHexRegion *r = &f->head; do { if (addr < r->addr) { return r->prev; } r = r->next; } while(r!=&f->head); return r->prev; } //=========================================================================== // AcHexGetRegion() - get region ingfo //=========================================================================== // // Given addr as input, return start, end, and len of region containing addr. // If no region contains addr then return info for following region. // If addr is after last region then return 0 and do not change start, end. // // f - hex file // addr - address to look for // start - returns start addr of reqion (may be NULL) // end - returns end addr of reqion (may be NULL) // // Returns: len of region, or 0 if addr is greter than end of last region // AcHexOffset AcHexGetRegion( AcHexFile *f, AcHexAddress addr, AcHexAddress *start, AcHexAddress *end) { AcHexRegion *r = AcHexRegionFind(f,addr); if (addr >= r->addr + r->len) { r = r->next; if (r == &f->head) return 0; } if (start) *start = r->addr; if (end) *end = r->addr + r->len - 1; return r->len; } //=========================================================================== // AcHexGetBytes() - get bytes from AcHexFile (unkown bytes not touched) //=========================================================================== // // returns # of known bytes retrieved // AcHexOffset AcHexGetBytes( AcHexFile *f, AcHexAddress addr, void *data, AcHexOffset bytes) { char *dst = data; AcHexRegion *r = AcHexRegionFind(f,addr); AcHexOffset sum = 0; while(bytes) { char *src = r->data; AcHexOffset len = r->len; if (addr < r->addr) { AcHexOffset dif = r->addr - addr; if (dif >= bytes) break; dst += dif; addr += dif; bytes -= dif; } if (addr > r->addr) { AcHexOffset dif = addr - r->addr; dif = dif < len ? dif : len; len -= dif; src += dif; } if (len) { len = len < bytes ? len : bytes; memcpy(dst, src, len); sum += len; addr += len; dst += len; bytes -= len; } r = r->next; if (r == &f->head) break; } return sum; } //=========================================================================== // AcHexSetBytes() - write bytes into AcHexFile //=========================================================================== // // 0 = success // -1 = failure // int AcHexSetBytes( AcHexFile *f, AcHexAddress addr, const void *data, AcHexOffset bytes) { AcHexRegion *s = AcHexRegionFind(f,addr); AcHexRegion *e = s; AcHexAddress ea1 = addr + bytes; AcHexAddress ea = ea1; // // find last region overlapping new bytes (e) // do { e = e->next; } while (e != &f->head && e->addr <= ea); e = e->prev; if (ea < e->addr + e->len) { ea = e->addr + e->len; } // // do we overlap or connect with preceding region? // if (addr <= s->addr + s->len) { // // are we talking about addr==0 and len==0? // if (s->len == 0) { AcHexOffset alloc = AcHexRegionSizeCalc(bytes); s->data = malloc(alloc); if (!s->data) return -1; s->alloc = alloc; // // do we not have enough room allocated already? // } else if (ea > s->addr + s->alloc) { AcHexOffset alloc = AcHexRegionSizeCalc(ea - s->addr); void *ptr = realloc(s->data, alloc); if (!ptr) return -1; s->data = ptr; s->alloc = alloc; } // // no overlap - create new region // } else { AcHexOffset alloc = bytes + 8192; AcHexRegion *r; r = AcHexRegionCreate(f,addr,alloc); if (!r) return -1; r->prev = s; r->next = s->next; s->next->prev = r; s->next = r; e = e==s ? r : e; s = r; } memcpy((char*)s->data + addr - s->addr, data, bytes); s->len = ea - s->addr; // // success, and no additional overlapped regions // if (e == s) { if (debug) { AcHexPrint(f,1); } return 0; } // // handle overlapped regions // s = s->next; while(s != e) { AcHexRegion *r = s->next; AcHexRegionDelete(f, s); s = r; } // // need to copy end of overlapped region? // if (ea1 < ea) { memcpy( s->data + ea1 - s->addr, e->data + ea1 - e->addr, ea - ea1); } AcHexRegionDelete(f,e); if (debug) { AcHexPrint(f,1); } return 0; } //=========================================================================== // AcHexDeleteBytes() - delete bytes from AcHexFile //=========================================================================== // // 0 = success // -1 = failure // int AcHexDeleteBytes( AcHexFile *f, AcHexAddress addr, AcHexOffset bytes) { if (bytes == 0) return 0; while(1) { AcHexRegion *r = AcHexRegionFind(f,addr); // // if r does not contain addr then we are done // if (r->addr + r->len <= addr) { return 0; // done } // // split at the end? // if (addr + bytes < r->addr + r->len) { if (AcHexRegionSplit(f,r,addr + bytes)) { return -1; } } // // split at the start? // if (addr > r->addr) { if (AcHexRegionSplit(f,r,addr)) { return -1; } r = r->next; } AcHexRegionDelete(f,r); } } |
This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:24:55 PDT 2007