/* xed - Simple hex editor Copyright (C) 2005 Ian Cowburn (ianc@noddybox.demon.co.uk) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------- */ static const char id[]="$Id$"; #include #include #include #include #include #include #include #include #include #include #include "xedkeys.h" #define VERSION "V2.0" #define USAGE "[-x] [-i] [-r] [-c] [-R] file" #define NONE 0 #define HEX 1 #define ASCII 2 #define REGEXP 3 #define FILENAME_LEN 25 #define GETSTR_LEN 80 #define GETSTR_DISP_LEN 50 #define BUFSIZE(x) ((((x)/1024)+1)*1024) #define CTYPE(func,c) (((c>=0)&&(c<=255)) ? func(c) : (c)) #define CTEST(func,c) (((c>=0)&&(c<=255)) ? func(c) : (FALSE)) #define IPBUFFSIZE 1024 typedef unsigned char uchar; char *name; char *filename; char print_name[FILENAME_LEN+1]; uchar *edit; uchar *mirror; long bufsize; int in_place=FALSE; int regexp=FALSE; int casesense=TRUE; int readonly=FALSE; int fd; long file_len; long page_ptr; long file_ptr; long end_page; long page_depth; int edit_hex=TRUE; int overtype=TRUE; int editted=FALSE; int last_search=NONE; char sch_str[GETSTR_LEN]; int sch_hex[128]; int sch_no; regex_t re; int re_alloc=FALSE; /* Function prototypes */ void Err(const char *s); void SysErr(const char *p); void MainCode(void); int HandleKey(int key); int HandleKeyHex(int key); void HandleKeyAscii(int key); int CompileRegExp(void); void SearchRegExp(void); void DoSearchRegExp(void); void SearchString(void); void DoSearchString(void); void SearchHex(void); void DoSearchHex(void); int Read(int fd, void *buff, int no); int Write(int fd, void *buff, int no); void OpenFile(void); void SaveFile(void); int CalcHex(int x[]); int GetByte(long cur); char *GetByteString(long *cur, int all_lower); int GetLastSaved(long cur); void Display(void); void PartialDisplay(long cur, int x, int y); void InsertValue(long p,long b); void DeleteValue(long p); void ReplaceValue(long p,long b); void UpdateValue(long p, int b); void ShowCursor(void); void ShowPos(void); int ScanKey(void); int GetKey(int allkeys); void GetString(char s[]); char *Get(char *p); int GetChar(char *p, char *v); void Message(const char *fmt, ...); char *Tail(char s[], int l); int main(int argc, char *argv[]) { char *env,*arg,*list[256]; /* If you're that prepared to break it, you */ int listc; /* DESERVE to get a segmentation fault */ int src,dest,f; name=argv[0]; /* Prepend XEDARG variable if present */ src=0; dest=0; if (env=getenv("XEDARG")) { arg=strtok(env," \t"); while(arg) { list[dest++]=arg; arg=strtok(NULL," \t"); } } for(f=1;f15) { file_ptr-=16; if (file_ptr(file_len-1)) file_ptr=file_len-1; if (file_ptr>end_page) { page_ptr+=16; Display(); } else ShowCursor(); } break; case CURS_RIGHT1: case CURS_RIGHT2: if (file_ptr<(file_len-1)) { file_ptr++; if (file_ptr>end_page) { page_ptr+=16; Display(); } else ShowCursor(); } break; case PAGE_BACK1: case PAGE_BACK2: case PAGE_BACK3: if (file_ptr>=page_depth) { page_ptr-=page_depth; if (page_ptr<0) page_ptr=0; file_ptr-=page_depth; Display(); } break; case PAGE_FWD1: case PAGE_FWD2: case PAGE_FWD3: if (page_ptr<=file_len-page_depth-1) { page_ptr+=page_depth; file_ptr+=page_depth; if (file_ptr>(file_len-1)) file_ptr=file_len-1; Display(); } break; case SWITCH_TO_ASCII: edit_hex=FALSE; ShowCursor(); break; case START_OF_FILE: page_ptr=file_ptr=0L; Display(); break; case END_OF_FILE: page_ptr=file_len-page_depth; if (page_ptr<0) page_ptr=0; file_ptr=file_len-1; Display(); break; case JUMP_TO: s=Get("Address to jump to (prefix with 0x for hex) : "); page_ptr=strtol(s,(char **)NULL,0); if (page_ptr<0) page_ptr=0; if (page_ptr>=file_len) page_ptr=file_len-1; file_ptr=page_ptr; if ((page_ptr>file_len-page_depth)&&(page_depthend_page) { page_ptr+=16; Display(); } else ShowCursor(); } } } else Message("Can't recover in -x mode!"); } else Message("File is read-only!"); ShowCursor(); break; case REFRESH: Display(); break; case INSERT_TOGGLE: if (!readonly) if (in_place) { Message("no insert/delete in -x mode"); ShowCursor(); } else { overtype=!overtype; ShowPos(); ShowCursor(); } break; case DELETE_CHAR: if (!readonly) { if (in_place) Message("no insert/delete in -x mode"); else if (file_len) { editted=TRUE; DeleteValue(file_ptr); if ((file_ptr>=file_len)&&(file_len)) if (--file_ptrend_page) { page_ptr=file_ptr; Display(); } else ShowCursor(); } else ShowCursor(); } else { if (!overtype) ReplaceValue(file_ptr,old_val); else UpdateValue(file_ptr,old_val); ShowCursor(); } } } break; } } void HandleKeyAscii(int key) { switch(key) { case ASC_CURS_UP1: case ASC_CURS_UP2: if (file_ptr>15) { file_ptr-=16; if (file_ptr(file_len-1)) file_ptr=file_len-1; if (file_ptr>end_page) { page_ptr+=16; Display(); } else ShowCursor(); } break; case ASC_CURS_RIGHT1: case ASC_CURS_RIGHT2: if (file_ptr<(file_len)-1) { file_ptr++; if (file_ptr>end_page) { page_ptr+=16; Display(); } else ShowCursor(); } break; case ASC_PAGE_BACK: if (file_ptr>=page_depth) { page_ptr-=page_depth; if (page_ptr<0) page_ptr=0; file_ptr-=page_depth; Display(); } break; case ASC_PAGE_FWD: if (page_ptr<=file_len-page_depth-1) { page_ptr+=page_depth; file_ptr+=page_depth; if (file_ptr>(file_len-1)) file_ptr=file_len-1; Display(); } break; case ASC_REFRESH: Display(); break; case SWITCH_TO_HEX: edit_hex=TRUE; ShowCursor(); break; case INSERT_TOGGLE: if (!readonly) if (in_place) { Message("no insert/delete in -x mode"); ShowCursor(); } else { overtype=!overtype; ShowPos(); ShowCursor(); } break; case ASC_DELETE_CHAR: if (!readonly) { if (in_place) Message("no insert/delete in -x mode"); else if (file_len) { DeleteValue(file_ptr); if ((file_ptr>=file_len)&&(file_len)) if (--file_ptrend_page) { page_ptr=file_ptr; Display(); } else ShowCursor(); } else ShowCursor(); } break; } } int CompileRegExp(void) { char buff[80]; int ret; if (re_alloc) regfree(&re); re_alloc=FALSE; if (casesense) ret=regcomp(&re,sch_str,REG_EXTENDED|REG_NEWLINE); else ret=regcomp(&re,sch_str,REG_EXTENDED|REG_ICASE|REG_NEWLINE); if(ret!=0) { regerror(ret,&re,buff,80); Message ("RE error : %s",buff); return (FALSE); } re_alloc=TRUE; return TRUE; } void SearchRegExp(void) { last_search=NONE; strcpy(sch_str,Get("/")); if (!strlen(sch_str)) return; if (CompileRegExp()) { last_search=REGEXP; DoSearchRegExp(); } } void DoSearchRegExp(void) { char *p; long f,of; regmatch_t re_match; Message("Searching...."); f=file_ptr+1; of=f; p=GetByteString(&f,!casesense); while(p) { if (regexec(&re,p,1,&re_match,0)==0) { file_ptr=of+re_match.rm_so; if ((file_ptrend_page)) page_ptr=file_ptr; free(p); return; } free(p); of=f; p=GetByteString(&f,!casesense); } Message("Not found. Press a key."); GetKey(TRUE); Message(""); } void SearchString(void) { last_search=NONE; strcpy(sch_str,Get("Search string : ")); if (!strlen(sch_str)) return; last_search=ASCII; DoSearchString(); } void DoSearchString(void) { long f; int l,r; Message("Searching...."); l=strlen(sch_str); for(f=file_ptr+1;fend_page)) page_ptr=file_ptr; return; } } Message("Not found. Press a key."); GetKey(TRUE); Message(""); } void SearchHex(void) { char *s; last_search=NONE; sch_no=0; s=Get("Enter First number (return to quit) : "); while(*s) { sch_hex[sch_no++]=(int)strtol(s,(char **)NULL,0); s=Get("Enter next number (return to finish) : "); } if (!sch_no) return; last_search=HEX; DoSearchHex(); } void DoSearchHex(void) { int f,r; Message("Searching...."); for(f=file_ptr+1;fend_page)) page_ptr=file_ptr; return; } } Message("Not found. Press a key"); GetKey(TRUE); Message(""); } /* Provide a skin to read(2) and write(2) */ int Read(int fd, void *buff, int no) { int tot,rd; tot=0; while(tot=file_len) return -1; if(!in_place) return edit[cur]; if (first_read) first_read=FALSE; else if ((cur>=buffpos)&&(cur=file_len) return NULL; l=0; while(((b=GetByte(cp++))!=-1)&&(b!=0)&&(b!='\n')) l++; if (!l) { if (!(p=(char *)malloc(0x1))) SysErr(NULL); *p=0; *cur+=1; return p; } if (!(p=(char *)malloc((int)l+1))) SysErr(NULL); for(cp=0;cp126)) mvaddch(r,62+f,(chtype)'.'); else mvaddch(r,62+f,(chtype)b); } r++; } end_page=cur-1; page_depth=end_page-page_ptr+1; ShowCursor(); } void PartialDisplay(long cur, int x, int y) { int r,f,b; r=y; while(r126)) mvaddch(r,62+f,(chtype)'.'); else mvaddch(r,62+f,(chtype)b); } x=0; r++; } } void InsertValue(long p,long b) { if (++file_len>bufsize) { if (!(edit=(uchar *)realloc(edit,(bufsize=BUFSIZE(file_len))))) SysErr(NULL); if (!(mirror=(uchar *)realloc(mirror,bufsize))) SysErr(NULL); } memmove(edit+p+1,edit+p,file_len-p-1); memmove(mirror+p+1,mirror+p,file_len-p-1); edit[p]=(uchar)b; mirror[p]=(uchar)b; } void DeleteValue(long p) { if (file_len>1) { memmove(edit+p,edit+p+1,file_len-p-1); memmove(mirror+p,mirror+p+1,file_len-p-1); file_len--; } else file_len=0; } void ReplaceValue(long p,long b) { int x,y; uchar c=b; edit[p]=(uchar)b; y=3+(p-page_ptr)/16; x=(p-page_ptr)%16; mvprintw(y,11+x*3,"%2.2X",(uchar)b); if ((b<32)||(b>126)) mvaddch(y,62+x,(chtype)'.'); else mvaddch(y,62+x,(chtype)b); } void UpdateValue(long p, int b) { int x,y; uchar c=b; if (!in_place) { if (overtype) edit[p]=(uchar)b; else InsertValue(p,b); } else { lseek(fd,p,SEEK_SET); if (Write(fd,&c,1)==-1) SysErr(filename); } y=3+(p-page_ptr)/16; x=(p-page_ptr)%16; if (overtype) { mvprintw(y,11+x*3,"%2.2X",(uchar)b); if ((b<32)||(b>126)) mvaddch(y,62+x,(chtype)'.'); else mvaddch(y,62+x,(chtype)b); } else PartialDisplay(p,x,y); } void ShowCursor(void) { int x,y; ShowPos(); y=(file_ptr-page_ptr)/16; x=(file_ptr-page_ptr)%16; if (edit_hex) move(3+y,11+x*3); else move(3+y,62+x); refresh(); } void ShowPos(void) { mvprintw(1,0,"Pos : %8.8x",file_ptr); mvprintw(0,40,"File size : %8.8x",file_len); /* Print Status line */ if (readonly) mvaddstr(1,20,"READ ONLY"); else if (overtype) mvaddstr(1,20,"OVERTYPE"); else mvaddstr(1,20," INSERT "); if (regexp) mvaddstr(1,37,"REGEXP SEARCH"); else mvaddstr(1,37,"STRING SEARCH"); if (casesense) mvaddstr(1,57," CASE SENSITIVE "); else mvaddstr(1,57,"CASE INSENSITIVE"); } int ScanKey(void) { int k; k=getch(); if (k==KEY_BACKSPACE) k=8; if (k==ERR) k=3; /* Message("Read key %9d",k); */ return k; } int GetKey(int allkeys) { int k; k=ScanKey(); if (!allkeys) while(!CTEST(isascii,k)) k=ScanKey(); return k; } void GetString(char s[]) { int k,done,p,x,y; done=FALSE; p=0; s[p]=0; getyx(stdscr,y,x); while(!done) { mvprintw(y,x,"%-*.*s",GETSTR_DISP_LEN,GETSTR_DISP_LEN, Tail(s,GETSTR_DISP_LEN)); move(y,x+((p>=GETSTR_DISP_LEN) ? (GETSTR_DISP_LEN) : (p))); refresh(); switch (k=GetKey(TRUE)) { case 8: case 127: if (p) s[--p]=0; break; case 3: strcpy(s,""); done=TRUE; break; case '\n': done=TRUE; break; default: if (p-1) ret[d--]=s[sl--]; ret[0]='.'; ret[1]='.'; } return ret; } /* END OF FILE */