/*----------------------------------------------------------------------------*/ /* Program: hex.c */ /* Date: 27-nov-1988 */ /* Desc: Hex editor source */ /* Author: Dominic Alston */ /* Version: 2.4 */ /* Revision history: */ /* 25-jan-1989 dom: Added terminal independant code */ /* 30-jan-1989 dom: Redesigned screen, added features */ /* 03-feb-1989 dom: Modified code. */ /* 04-feb-1989 dom: Added own mmi routines */ /* 05-feb-1989 dom: Version 2 Increment 0 release finished. */ /* 06-feb-1989 dom: Fixed goto out of band chars being accepted */ /* 20-feb-1989 dom: Added version print and readonly feature */ /* 23-feb-1989 dom: Added screen refresh. */ /*----------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #define VERSION_STAMP "2.4" #define PAGESIZE 1280 #define BUFSIZE 256 #define READING 0 #define WRITING 1 #define GOTO 2 #define DBUFF_SIZE 32 #define FBUFF_SIZE 16 #define X_PRODUCT 30 #define Y_PRODUCT 0 #define X_MENU1 0 #define Y_MENU1 2 #define X_MENU2 0 #define Y_MENU2 3 #define X_STATUS 0 #define Y_STATUS 5 #define X_FORMAT 76 #define X_POSITION 19 #define X_PROMPT 0 #define Y_PROMPT 6 #define X_INPUT 9 #define X_FIND 9 #define Y_FIND 6 #define X_HEX 0 #define Y_HEX 7 #define X_CHAR 52 #define Y_CHAR 7 #define X_EXIT 0 #define Y_EXIT 23 #define X_VERB 36 #define Y_VERB 5 #define CTRL(c) ((c) & 037) #define _KEY_EXIT 'q' #define ENTER '\n' #define KEY_ESC '\033' #define KEY_TAB '\t' static int ch; /* buffer for single character read */ static char page[PAGESIZE]; /* buffer for screen display */ static char *hptr; /* pointer to page for hex display */ static char *cptr; /* pointer to page for character display */ static char buf[BUFSIZE]; /* buffer for input i/o */ static char *bptr; /* pointer to buf */ static char pos[9]; /* buffer for character format of position */ static char find_buff[FBUFF_SIZE]; /* buffer holding the string for searching */ static int find_length; /* size of string searched for */ static char disp_buff[DBUFF_SIZE]; /* buffer holding the search string during */ static int disp_length; static char hexchars[] = "0123456789ABCDEF"; static char head1[] = " Hexpert [v2.4 (c)1988 Dominic Alston] "; static char r_head2[] = "Options: =Page-up =Goto-position =Char-find =Exit "; static char r_head3[] = " =Page-down =Hex-find <^l>=Refresh "; static char head2[] = "Options: =Page-up =Goto-position =Char-find =Exit"; static char head3[] = " =Page-down =Edit-buffer =Hex-find <^l>=Refresh"; static char head4[] = "Status- Position: 00000000 Mode: View File: "; static char head5[] = "Options: =Write-buffer =Toggle hex/char edit "; static char head6[] = " =Restore buffer & goto view mode "; static char head7[] = "Options: =Do-search = Move-left "; static char head8[] = " =Goto view mode =Move-right "; static char edit1[] = "Options: =Goto-position =Move-left "; static char edit2[] = " =Goto view mode =Move-right "; static char msg1[] = "pattern not found!"; static char usage_bnr[]= "Usage: %s [-vr] 'file'\n"; static char version_bnr[]= "HEXPERT V%s, Dominic Alston..\n"; static char error1[] = "internal error - hex unpaired!"; static int x,y; /* screen co-ordinates */ static int input; /* file descriptor for input file */ static int mode; /* current mode of use */ static int readonly; /* true if input file is read only */ static int bytes_written; static int bytes_read; static char hex_find; /* true if find mode is currently hex */ static off_t position; /* displacement of current buffer in input file */ static long lastbyte; /* displacement of end of file (Mod 256) */ static struct stat filedata; /* statistics of the input file,gives file size */ static int bool_hexfind=FALSE; static void initialise(char *filename); static void display(void); static void closedown(void); static void toplevel(void); static int get_position(void); static void pos_print(void); static void editbuffer(void); static void toplev_headings(void); static void char_ed(void); static void hex_ed(void); static void hex_to_buf(void); static int get_string(void); static void set_string(void); static void buftoh(char *out_string, char *in_string, int in_size); static void htobuf(char *out_string, char *in_string, int in_size); static void buftobuf(char *out_string, char *in_string, int in_size); static void find_string(void); static int search(char *sbuf, off_t *start, int size); static void init_term(void); static void reset_term(void); static int get_str(WINDOW *wnd, int row, int col, char *str, char filler, int str_size); static void ctrlc_ast(int sig); static void put_prompt(void); static void edit_headings(void); int main(int argc, char *argv[]) { int c; char *filenm = 0; while ((c=getopt(argc,argv,"vr:"))!=EOF) { switch(c) { case 'v': fprintf(stderr,version_bnr, VERSION_STAMP); exit(-1); case 'r': readonly=TRUE; filenm=optarg; break; default: fprintf(stderr,usage_bnr,argv[0]); exit(-1); } } if (argc==1) { fprintf(stderr,usage_bnr,argv[0]); exit(-1); } else initialise(filenm==0?argv[1]:filenm); toplevel(); closedown(); exit(0); } static void initialise(char *filename) { register int i,j; char *ptr; /* Open file for read & write, if this fails */ /* open file for reading, if fail exit. */ if ((input=open(filename,O_RDWR))==-1) { if ((input=open(filename,O_RDONLY))==-1) { perror(filename); exit(-1); } else readonly=TRUE; } init_term(); /* init curses terminfo */ signal(SIGINT,ctrlc_ast); /* signal handler for contol c */ /* Read the file statistics to find the */ /* file size and put it in 'lastbyte', */ /* after adjusting to a multiple of 256 */ if ((fstat(input,&filedata))==0) lastbyte=(filedata.st_size-1) & 0x7fffff00; else lastbyte = 0; /* Clear the display buffer. */ hptr=page; for (i=0; i33) i=33; for (j=0; j=16)?16:num-i; for (j=0; j>4) & 0xf]; *hptr++=hexchars[*bptr & 0xf]; *hptr++=' '; *cptr++=((*bptr)>0x1f && (*bptr)<0x7f?*bptr:'.'); bptr++; } *((cptr-jlimit)+80)='\n'; hptr+=32; cptr=(hptr+52); } } else for(i=0; i lastbyte) position = lastbyte; lseek(input,position,0); display(); } else beep(); break; case KEY_UP: if (position != 0) { position -= 256; if (position < 0) position = 0; lseek(input,position,0); display(); } else beep(); break; case 'g': case 'G': mode=GOTO; if (get_position()) { lseek(input,position,0); display(); } else pos_print(); toplev_headings(); mode=READING; break; case 'e': case 'E': if (readonly) { beep(); move(6,9); refresh(); } else editbuffer(); break; case 'c': case 'C': case 'h': case 'H': if ((ch=='c') || (ch=='C')) hex_find=FALSE; else hex_find=TRUE; if (get_string()==1) find_string(); toplev_headings(); break; default: beep(); break; } } } static int get_position(void) { char num[9]; char *ptr1,*ptr2; int status; long posit; register int i; edit_headings(); posit=0; ptr1=num; ptr2=pos; for (i=0; i<9; i++) (*(ptr1++))=(*(ptr2++)); move(Y_STATUS,10); disp_length=7; if ((status=get_str(stdscr,Y_STATUS,X_POSITION,num,'0',8))==-1) return(FALSE); for (i=0; i<8; i++) { posit=(posit<<4)+(num[i] & 0xf); if (num[i]>'9') posit+=9; } if (posit<0) posit=0; if (posit<=lastbyte) position=posit; else position=lastbyte; return(TRUE); } static void pos_print(void) { char *ptr; ptr=pos+7; *ptr--=hexchars[(position & 0xf)]; *ptr--=hexchars[((position>>4) & 0xf)]; *ptr--=hexchars[((position>>8) & 0xf)]; *ptr--=hexchars[((position>>12) & 0xf)]; *ptr--=hexchars[((position>>16) & 0xf)]; *ptr--=hexchars[((position>>20) & 0xf)]; *ptr--=hexchars[((position>>24) & 0xf)]; *ptr--=hexchars[((position>>28) & 0xf)]; *(pos+9)=0; mvaddstr(Y_STATUS,X_POSITION,pos); } static void editbuffer(void) { /* Display edit headings */ mvaddstr(Y_MENU1, X_MENU1,head5); mvaddstr(Y_MENU2, X_MENU2,head6); mvaddstr(Y_VERB, X_VERB,"Edit"); hex_ed(); mode = READING; toplev_headings(); } /* read_headings: Display read headings */ static void toplev_headings(void) { if (readonly) { mvaddstr(Y_MENU1, X_MENU1,r_head2); mvaddstr(Y_MENU2, X_MENU2,r_head3); } else { mvaddstr(Y_MENU1, X_MENU1,head2); mvaddstr(Y_MENU2, X_MENU2,head3); } mvaddstr(Y_VERB, X_VERB,"View"); move(Y_PROMPT, X_INPUT); refresh(); } static void char_ed(void) /* Entered from hex_ed() when 'TAB' read. */ { char *ptr; char *eptr; unsigned char c1,c2; int xx; /* get byte by mapping on to physical scale from screen scale */ ptr=page+(y-7)*80+x; move(y,x); refresh(); do { ch=getch(); if ((ch)>=0x20 && (ch)<0x7f) { addch(ch); refresh(); *ptr = ch; c1 = ch & 0xf; c2 = (ch >> 4) & 0xf; xx = (x - 52) * 3; eptr = (ptr - x) + xx; *eptr++ = hexchars[c2]; *eptr = hexchars[c1]; move(y,xx); addch(*--eptr); addch(*++eptr); refresh(); if (x == 67) { if (y < 22) { ptr +=65; x = 52; y++; } else { ptr = page + 52; x = 52; y = 7; } } else { ptr++; x++; } } else if (ch==KEY_RIGHT) if (x==67) { if (y<22) { ptr+=65; x=52; y++; } else { ptr=page+52; x=52; y=7; } } else { ptr++; x++; } else if (ch == KEY_LEFT) if (x == 52) { if (y > 7) { ptr -= 65; x = 67; y--; } else { ptr += 1215; x = 67; y = 22; } } else { ptr--; x--; } else if (ch == KEY_UP) if (y > 7) { ptr -=80; y--; } else { ptr +=1200; y = 22; } else if (ch == KEY_DOWN) if (y < 22) { ptr +=80; y++; } else { ptr -=1200; y = 7; } else if (ch == KEY_ESC) { lseek(input,position,0); display(); } else if ((ch == ENTER) || (ch == KEY_TAB)) /* do nothing */ ; else beep(); move(y,x); refresh(); } while ((ch!=ENTER) && (ch!=KEY_TAB) && (ch!=KEY_ESC)); if (ch==ENTER) { hex_to_buf(); lseek(input,position,0); write(input,buf,bytes_read); } mode=READING; } static void hex_ed(void) { char *ptr; ptr=page; x=X_HEX; y=Y_HEX; move(y,x); refresh(); do { ch=getch(); if (isxdigit(ch)) { addch(toupper(ch)); refresh(); *ptr = ch; { char *eptr,c1,c2; int xx; if ((x%3) == 1) eptr = ptr - 1; else eptr = ptr; c1 = *eptr++; c2 = *eptr; if (c1 > '9') c1 = (c1 + 9) & 0xf; else c1 = c1 & 0xf; if (c2 > '9') c2 = (c2 + 9) & 0xf; else c2 = c2 & 0xf; c1 = (c1 << 4) + c2; xx = (x/3) + 52; move(y,xx); refresh(); if ((c1>=0x20) && (c1<0x7f)) addch(c1); else addch('.'); refresh(); } ptr++; x++; if (((x+1)%3)==0) { if (x==47) { if (y<22) { ptr+=33; x=0; y++; } else { ptr=page; x=0; y=7; } } else { ptr++; x++; } } } else if (ch==KEY_RIGHT) { ptr++; x++; if (((x+1)%3)==0) { if (x==47) { if (y<22) { ptr+=33; x=0; y++; } else { ptr=page; x=0; y=7; } } else { ptr++; x++; } } } else if (ch==KEY_LEFT) if (x==0) { if (y>7) { ptr -= 34; x = 46; y--; } else { ptr += 1246; x = 46; y = 22; } } else { ptr--; x--; if (((x+1)%3)==0) { ptr--; x--; } } else if (ch == KEY_UP) if (y > 7) { ptr -= 80; y--; } else { ptr += 1200; y = 22; } else if (ch == KEY_DOWN) if (y < 22) { ptr += 80; y++; } else { ptr -= 1200; y = 7; } else if (ch == KEY_ESC) { lseek(input,position,0); display(); } else if (ch==ENTER) ; else if (ch==KEY_TAB) { x = (x/3) + 52; char_ed(); x = (x-52) * 3; ptr = page + (y-7)*80 + x; } else beep(); move(y,x); refresh(); } while (ch!=ENTER && ch!=KEY_ESC); if (ch==ENTER) { hex_to_buf(); lseek(input,position,0); write(input,buf,bytes_read); } } static void hex_to_buf(void) { char c1,c2; int i; int j; hptr = page; bptr = buf; for (i=0;i<16;i++) { for (j=0;j<16;j++) { c1 = *hptr++; if (c1 > '9') c1 = (c1 + 9) & 0xf; else c1 = c1 & 0xf; c2 = *hptr++; if (c2 > '9') c2 = (c2 + 9) & 0xf; else c2 = c2 & 0xf; *bptr++ = (c1 << 4) + c2; hptr++; } hptr += 32; } } static int get_string(void) { mvaddstr(Y_MENU1, X_MENU1,head7); mvaddstr(Y_MENU2, X_MENU2,head8); mvaddstr(Y_VERB, X_VERB,"Find"); attron(A_BOLD); mvaddstr(6,0,"search criteria: "); attroff(A_BOLD); if ((bool_hexfind && !hex_find) || (!bool_hexfind && hex_find)) { if (hex_find) bool_hexfind=TRUE; else if (!hex_find) bool_hexfind=FALSE; find_length=0; disp_buff[0]=0; } if (hex_find) { buftoh(disp_buff,find_buff,find_length); disp_length=find_length*2; } else buftobuf(disp_buff,find_buff,disp_length=find_length); if ((disp_length=get_str(stdscr,6,17,disp_buff,'.', hex_find?DBUFF_SIZE:FBUFF_SIZE))==-1) { put_prompt(); return(FALSE); } else if (disp_length==0 && hex_find) disp_length=find_length*2; else if (disp_length==0 && !hex_find) disp_length=find_length; set_string(); return(TRUE); } /* set_string: set up the string for return */ static void set_string(void) { if (hex_find) { htobuf(find_buff,disp_buff,disp_length); find_length=disp_length/2; } else buftobuf(find_buff,disp_buff,find_length=disp_length); } /* buftoh: Converts input buffer to hexadecimal display in output string. * String length is used since zero is legitimate. */ static void buftoh(char *out_string, char *in_string, int in_size) { register int i; for (i=0; i < in_size; i++) { char c = *in_string++; *out_string++ = hexchars[(c >> 4) & 0xf]; /* [c/16]; */ *out_string++ = hexchars[ c & 0xf]; /* [c%16]; */ } } /* htobuf: converts hexadecimal display to binary. String length is used * and only hexadecimal pairs are handled. */ static void htobuf(char *out_string, char *in_string, int in_size) { char i; int h_value, c_value; int byte_val = 0; if (in_size%2 != 0) { put_prompt(); addstr(error1); beep(); refresh(); return; } for (i=0; i < in_size; i++) { if ((h_value = *in_string++) >= '0' && h_value <= '9') c_value = h_value -'0'; else (c_value = 10 + (h_value & 0xf) - ('a' & 0xf)); if (!(i%2)) byte_val = c_value * 16; else *out_string++ = byte_val + c_value; } } /* buftobuf: Copy buffer to buffer. Not quite strncopy since zero is valid * and not a terminator. */ static void buftobuf(char *out_string, char *in_string, int in_size) { register int i; for (i=0; i=position+find_length && found_it!=1) { lseek(input,position,0); num_read=read(input,buf,BUFSIZE); if (search(buf,&position,num_read-find_length)) found_it=1; } /* if still not found then search from beginning */ if (found_it!=1) { position=0; while (position<=start_pos && found_it!=1) { lseek(input,position,0); num_read=read(input,buf,BUFSIZE); if (search(buf,&position,position+inc_length0){ if (--ccol<0) ccol=0; mvwaddch(wnd,row,col+ccol,filler); wmove(wnd,row,col+ccol); *(str+ccol)=' '; wrefresh(wnd); } else beep(); break; case KEY_ESC: /* if escape pressed */ status=(char)-1; leave=TRUE; break; case KEY_LEFT: erase_flg=1; if (ccol>0) { if (--ccol<0) ccol=0; wmove(wnd,row,col+ccol); wrefresh(wnd); } else beep(); break; case KEY_RIGHT: if (ccolstr_size) ccol=str_size; wmove(wnd,row,col+ccol); wrefresh(wnd); } else beep(); break; default: /* other chars */ if ((((hex_find || mode==GOTO) && isxdigit(c)) || ((!hex_find && mode!=GOTO) && (c>=0x20 && c<0x7f))) && ccolstr_size) ccol=str_size; } else beep(); break; } erase_flg=1; } if (status==0) status=ccol; return(status); } static void ctrlc_ast(int sig) { if (sig==SIGINT) closedown(); else signal(SIGINT,ctrlc_ast); } static void put_prompt(void) { move(6,0); clrtoeol(); attron(A_BOLD); mvaddstr(Y_PROMPT, X_PROMPT,"command> "); attroff(A_BOLD); } static void edit_headings(void) { mvaddstr(Y_MENU1, X_MENU1,edit1); mvaddstr(Y_MENU2, X_MENU2,edit2); mvaddstr(Y_VERB, X_VERB,"Goto"); }