/* * GHEX -- an advanced HEX-Editor * Copyright (C) 1999 by Joerg Tretter * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include struct data // one line in Memory { struct data* plast; struct data* pnext; unsigned char vals[16]; unsigned long line; char len; }; struct cpos // Cursor-Position { char x,y; }pos; char insovr='O'; // Isert/Override-Mode int mode=1; WINDOW *stdscr,*woffs,*whex, *wascii, *wtop, *wbot; const char *topline= " Offset Hex ASCII "; char xoffs[] = "12345678",*soffs; char xhex[] = " 14 15 16 32 32 34 20 54 61 67 65 73 61 6D 74 0D ",*shex; char xascii[] = "1234567890123456",*sascii; char empty78[]=" "; int result; char *filename; char *ptv="12345678"; FILE *fp; int ipoint; data datas, *pdatas, *pfirst, *phelp, *pmax; /*************************************************************************** * FUNCTION: void initvar() * * GOOD FOR: Initialization of basic-variables * ***************************************************************************/ void initvar() { pfirst=&datas; (*pfirst).plast=NULL; (*pfirst).pnext=NULL; (*pfirst).line=0; (*pfirst).len=0; soffs=xoffs; shex=xhex; sascii=xascii; } /*************************************************************************** * FUNCTION: void miniinit() * * GOOD FOR: Initialization of frequent used variables * ***************************************************************************/ void miniinit() { xoffs = " "; xhex = " "; xascii = " "; } /*************************************************************************** * FUNCTION: int screeninit() * * GOOD FOR: Initialization of the n-curses-screen * * RESULTS : 1:There was an error / 2:Everything ok. * ***************************************************************************/ int screeninit() { int retval=0; stdscr= initscr(); if(start_color()) retval=1; nonl(); intrflush(stdscr, FALSE); keypad(stdscr, TRUE); // Create Curses-space for the windows //TODO: check whether creation was fine. woffs =newwin(18,10,3 ,0 ); whex =newwin(18,52,3 ,10); wascii=newwin(18,18,3 ,62); wtop =newwin(3 ,80,0 ,0 ); wbot =newwin(4 ,80,21,0 ); // enable scrolling scrollok(woffs,1); scrollok(whex,1); scrollok(wascii,1); // enable Keyboard-control keypad(stdscr,1); keypad(whex,1); keypad(wascii,1); // disable echoing of input noecho(); // swich cursor to big size // TODO: check why this not works in most cases // if(curs_set(2)==ERR) retval=1 ; // creation of curses "Color-Pairs" if(init_pair(1,COLOR_BLUE,COLOR_BLACK)) retval=1; if(init_pair(2,COLOR_CYAN,COLOR_BLACK)) retval=1; if(init_pair(3,COLOR_MAGENTA,COLOR_BLACK)) retval=1; // join the windows with the color-pairs wattrset(woffs,COLOR_PAIR(1)); wattrset(whex,COLOR_PAIR(1)); wattrset(wascii,COLOR_PAIR(1)); wattrset(wbot,COLOR_PAIR(1)); wattrset(wtop,COLOR_PAIR(1)); // paint the boxes around the windows (in fact it's inside) box(woffs,0,0); box(whex,0,0); box(wascii,0,0); box(wtop,0,0); box(wbot,0,0); // change the color-pairs of the windows again. wattrset(woffs,COLOR_PAIR(2)); wattrset(whex,COLOR_PAIR(2)); wattrset(wascii,COLOR_PAIR(2)); wattrset(wtop,COLOR_PAIR(3)); wattrset(wbot,COLOR_PAIR(2)); return(retval); } /*************************************************************************** * FUNCTION: char* tonumsysx() * * GOOD FOR: Shift a number to another numbering system * * INPUTS : - int base10 -The number in decimal system * * - int newbase -The new system (16->Hex,2->Bin,...) * * RESULTS : The number in the new system as a pointer of char * ***************************************************************************/ char* tonumsysx(int base10,int newbase) { int erg; int rest=0; int pos=0; int i; static char swap[9]; char c[9]; swap="********"; c[pos]='0'+rest; while (base10 > 0) { erg=base10/newbase; rest=base10%newbase; if (rest <= 9) c[pos]='0'+rest; else c[pos]='A'+(rest-10); base10=erg; pos++; c[pos]='\0'; } while(pos < 8) { c[pos]='0'; pos++; } pos--; for (i=0;i<=pos;i++) { swap[i]=c[pos-i]; } return(swap); } /*************************************************************************** * FUNCTION: unsigned long xto10(char *c, int oldbase) * * GOOD FOR: Shift a number from a foreign numbering system to decimal * * INPUTS : - char* c -The number in foreign system * * - int oldbase -The old system (16->Hex,2->Bin,...) * * RESULTS : The number in decimal system as a unsigned long * ***************************************************************************/ unsigned long xto10(char *c, int oldbase) { unsigned long base10=0; int pos=0; int i; for (i=0;c[i];i++, c[i]=toupper(c[i])); while(c[pos++]); pos--; int len=pos-1; while(pos--) { if(isdigit(c[len-pos])) { base10 = base10 + (unsigned long)( (double)(c[len-pos]-'0') * ( pow( (double)oldbase,(double)pos ) ) ) ; } else { base10 = base10 + (unsigned long)( ((double)(c[len-pos]-'A')+10) * ( pow( (double)oldbase,(double)pos ) ) ); } } return(base10); } /*************************************************************************** * FUNCTION: int loadcontents() * * GOOD FOR: Loading the contents of a file into the memory * * RESULTS : The status of the loading (not used yet) * ***************************************************************************/ int loadcontents() { int retval=0; int x; char ch; unsigned long line=0; pdatas=pfirst; ch=fgetc(fp); // Zero-byte-file. if(feof(fp)) { fprintf(stderr,"opening 0-Byte file"); pfirst=pmax=pdatas=(data*)(malloc(sizeof(datas))); (*pdatas).pnext=NULL; (*pdatas).plast=NULL; (*pdatas).line=0; (*pdatas).len=0; } // TODO: how to flush the buffer of stdout??? printf("Printing hashmark for every 8 Kbytes.\n"); while (!(feof(fp))) { for(x=0;x<16;x++) { ((*pdatas).vals[x])=ch; if (feof(fp)) //(*pdatas).vals[x]==EOF) { (*pdatas).vals[x]=0; break; } (*pdatas).len=x+1; ch=fgetc(fp); } (*pdatas).line=line++; if(!(feof(fp))) { phelp=pdatas; if (!(line%500)) {printf("%c",'#');} pdatas=((*pdatas).pnext)=(data*)(malloc(sizeof(datas))); // BUG: Check for Memory-Full does not work. if(!pdatas) {abort();} (*pdatas).plast=phelp; (*pdatas).pnext=NULL; } pmax=pdatas; } return (retval); } /*************************************************************************** * FUNCTION: void endscr() * * GOOD FOR: End the scrren session on curses-level * ***************************************************************************/ void endscr() { delwin(woffs); delwin(whex); delwin(wascii); delwin(wtop); delwin(wbot); endwin(); } /*************************************************************************** * FUNCTION: void unallocmem() * * GOOD FOR: Free the memory from the bits & bytes * ***************************************************************************/ void unallocmem() { pdatas=pmax; while((*pdatas).plast) { phelp=(*pdatas).plast; free(pdatas); pdatas=phelp; } } /*************************************************************************** * FUNCTION: void scrrefresh() * * GOOD FOR: Refreah the basic-screen-elements (not the contents) * ***************************************************************************/ void scrrefresh() { wattrset(woffs,COLOR_PAIR(1)); wattrset(whex,COLOR_PAIR(1)); wattrset(wascii,COLOR_PAIR(1)); wattrset(wbot,COLOR_PAIR(1)); wattrset(wtop,COLOR_PAIR(1)); box(woffs,0,0); box(whex,0,0); box(wascii,0,0); box(wtop,0,0); box(wbot,0,0); wattrset(woffs,COLOR_PAIR(2)); wattrset(whex,COLOR_PAIR(2)); wattrset(wascii,COLOR_PAIR(2)); wattrset(wtop,COLOR_PAIR(3)); wattrset(wbot,COLOR_PAIR(2)); // depending on the mode (ascii/hex) set the cursor-position !mode?wmove(whex,pos.y,pos.x):wmove(wascii,pos.y,pos.x); wrefresh(woffs); wrefresh(wtop); wrefresh(wbot); // the order is given by the mode (ascii/hex). the last window refreshed // it the one, in which the cursor appears and the input-focus is. !mode?wrefresh(wascii):wrefresh(whex); mode?wrefresh(wascii):wrefresh(whex); } /*************************************************************************** * FUNCTION: void lineout(unsigned long line) * * GOOD FOR: Writing one line (the actual one) from the memory to screen * ***************************************************************************/ void lineout(unsigned long line) { int z; miniinit(); ptv = tonumsysx((*pdatas).line*16,16); for(z=0;z<9;z++) { xoffs[z] = *(ptv+z); } mvwaddstr(woffs,line,1,soffs); for (z=0;z<(*pdatas).len;z++) { ptv = tonumsysx((*pdatas).vals[z],16); xhex[z*3+1] = *(ptv+6); xhex[z*3+2] = *(ptv+7); } mvwaddstr(whex,line,1,shex); for (z=0;z<(*pdatas).len;z++) { // TODO: There are many other characters that are displayable. xascii[z] = (isgraph((*pdatas).vals[z]))?((*pdatas).vals[z]):'.'; } mvwaddstr(wascii,line,1,sascii); } /*************************************************************************** * FUNCTION: void initout() * * GOOD FOR: First output after loading the file // home-Key * ***************************************************************************/ void initout() { //Initial output (All) int i; bool toggleswitch=false; pdatas=pfirst; if ((*pdatas).pnext == NULL) toggleswitch=true; for(i=0;i<16;i++) { lineout(i+1); if (toggleswitch) break; pdatas=(*pdatas).pnext; if ((*pdatas).pnext == NULL) toggleswitch=true; } scrrefresh(); if(i>15) pdatas=(*pdatas).plast; } /*************************************************************************** * FUNCTION: int scrolld() * * GOOD FOR: Scrolling the scrren one line down * * RESULTS : 1: no more elements // 0: everything was nice * ***************************************************************************/ int scrolld() { int resval; if ((*pdatas).pnext != NULL) { pdatas=(*pdatas).pnext; wscrl(woffs,1); wscrl(whex,1); wscrl(wascii,1); miniinit(); lineout(16); resval=1; } else { resval=0; } return(resval); } /*************************************************************************** * FUNCTION: int scrollu() * * GOOD FOR: Scrolling the scrren one line up * * RESULTS : 1: at first element // 0: everything was nice * ***************************************************************************/ int scrollu() { int z=0; int result; while(((*pdatas).plast != NULL)&&(z < 16)) { pdatas=(*pdatas).plast; z++; } result= (z!=15)?1:0; if(z>15) { z--; wscrl(woffs,-1); wscrl(whex,-1); wscrl(wascii,-1); miniinit(); lineout(1); } while(z--) { if ((*pdatas).pnext != NULL) { pdatas=(*pdatas).pnext; } } return(result); } /*************************************************************************** * FUNCTION: void switchmode() * * GOOD FOR: recalculation of cursor-position ascii<->hex * ***************************************************************************/ void switchmode() { if(mode==0) { mode=1; // mode-toggle:Hex->Ascii // recalculate cursor-position pos.x=((pos.x+1)/3); } else { mode=0; // mode-toggle:ascii->Hex // recalculate cursor-position pos.x=((pos.x*3)-1); } } /*************************************************************************** * FUNCTION: void moveleft() * * GOOD FOR: move the cursor one position to the left * ***************************************************************************/ void moveleft() { if(mode==0) { if(pos.x > 2) { (pos.x%3)?pos.x-=2:pos.x--; } else { if(pos.y >1) { pos.y--; pos.x=48; } else { if(scrollu())pos.x=48; } } } else { if(pos.x > 1) { pos.x--; } else { if(pos.y >1) { pos.y--; pos.x=16; } else { if(scrollu())pos.x=16; } } } } /*************************************************************************** * FUNCTION: void moveright() * * GOOD FOR: move the cursor one position to the right * ***************************************************************************/ void moveright() { if(mode==0) { if(pos.x < 48) { (pos.x%3)?pos.x++:pos.x+=2; } else { if(pos.y < 16) { pos.x=2; pos.y++; } else { if(scrolld()) pos.x=2; } } } else { if((pos.x < 16)) { pos.x++; } else { if(pos.y < 16) { pos.x=1; pos.y++; } else { if(scrolld()) pos.x=1; } } } } /*************************************************************************** * FUNCTION: unsigned long getactpos() * * GOOD FOR: get the acutal cursor-position as a file-offset * * RESULTS : The file-offset on the cursor-position as unsigned long * ***************************************************************************/ unsigned long getactpos() { int i=0; unsigned long actpos; int distance; int posxsave=9999; if (!mode) { posxsave=pos.x; switchmode(); } // move in Memory to the cursor-position if((pdatas==pmax) && ((*pdatas).line<15)) { distance=(*pdatas).line-pos.y+1; } else { distance=16-pos.y; } while(i<(distance)&&((*pdatas).plast)) { i++; pdatas=(*pdatas).plast; } // get the position actpos=((*pdatas).line*16)+pos.x-1; // and move back while(i--) { pdatas=(*pdatas).pnext; } if (posxsave!=9999) { switchmode(); pos.x=posxsave; } return(actpos); } /*************************************************************************** * FUNCTION: void charin(char ch, int realmode, int realxpos) * * GOOD FOR: insert/override one character in the memory * * INPUTS : - char ch -the char to insert * * - int realmode -the real mode (hex/ascii) * * - int realxpos -the real x-position of the cursor * ***************************************************************************/ void charin(char ch, int realmode, int realxpos) { int i=0; int z=0; int distance=0; bool toggleswitch; data *phelp2; char rbmode; //rollbackmode (if file < 255 chars = 1 else 2) unsigned long zhelp; // im move to the cursor-position in memory // Is the file smaller then one page, it has to be handled in another way. if((pdatas==pmax) && ((*pdatas).line<15)) { distance=(*pdatas).line-pos.y+1; rbmode=1; } else { distance=16-pos.y; rbmode=2; } while(i<(distance)&&((*pdatas).plast)) { i++; pdatas=(*pdatas).plast; } // For the insert-mode if (((insovr=='I') && (realmode==1))||((insovr=='I') && (realmode==0) && (realxpos%3==2)) && (realmode!=3)) { phelp=pdatas; pdatas=pmax; if ((*pdatas).len < 16) { (*pdatas).len++; } else { // allocate new element phelp2=pmax; zhelp=(*pmax).line+1; pdatas=pmax=((*pdatas).pnext)=(data*)(malloc(sizeof(datas))); if(!pmax) {abort();} (*pmax).plast=phelp2; (*pmax).pnext=NULL; (*pmax).len=1; (*pmax).line=zhelp; } while(pdatas!=phelp) { for(z=(*pdatas).len-1;z>=0;z--) { (*pdatas).vals[z]=(*pdatas).vals[z-1]; } (*pdatas).vals[0]=(*(*pdatas).plast).vals[15]; pdatas=(*pdatas).plast; } for(z=(*pdatas).len-1;z+1>pos.x;z--) { (*pdatas).vals[z]=(*pdatas).vals[z-1]; } pdatas=phelp; } // Write value (*pdatas).vals[pos.x-1]=ch; // refresh output of current line (not needed, I think) lineout(pos.y); // moving backwards again and print the lines immediate. if (rbmode==1) { pdatas=pfirst; if ((*pdatas).pnext == NULL) toggleswitch=true; for(z=0;z<16;z++) { lineout(z+1); if (toggleswitch) break; pdatas=(*pdatas).pnext; if ((*pdatas).pnext == NULL) toggleswitch=true; } } else { while(i--) { if((*pdatas).pnext) { pdatas=(*pdatas).pnext; lineout(16-i); } } } } /*************************************************************************** * FUNCTION: int charout() * * GOOD FOR: get the char at the actual cursor-position * * RESULTS : the char as an integer (char should work too normaly) * ***************************************************************************/ int charout() { int i=0; int distance; int posxsave; int ch; // Move in memory to cursor-position if (!mode) { posxsave=pos.x; switchmode(); } // move in Memory to the cursor-position if((pdatas==pmax) && ((*pdatas).line<15)) { distance=(*pdatas).line-pos.y+1; } else { distance=16-pos.y; } while(i<(distance)&&((*pdatas).plast)) { i++; pdatas=(*pdatas).plast; } // get the value ch=((*pdatas).vals[pos.x-1]); // move back while(i--) { pdatas=(*pdatas).pnext; } return(ch); } /*************************************************************************** * FUNCTION: void bottomout() * * GOOD FOR: refreshing the output of the bottom-window * ***************************************************************************/ void bottomout() { int realmode,realposx; realmode=mode; if (realmode == 0) { realposx=pos.x; switchmode(); } mvwaddstr(wbot,1,1,empty78); mvwaddstr(wbot,2,1,empty78); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,1,"CHR:"); wattrset(wbot,COLOR_PAIR(2)); mvwaddch(wbot,1,6,32); mvwaddch(wbot,1,5,(isgraph(charout()))?charout():'.'); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,9,"HEX:"); wattrset(wbot,COLOR_PAIR(2)); mvwaddstr(wbot,1,13,(tonumsysx(charout(),16))+6); mvwaddch(wbot,1,15,'h'); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,18,"DEC:"); wattrset(wbot,COLOR_PAIR(2)); mvwaddstr(wbot,1,22,(tonumsysx(charout(),10))+5); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,27,"OCT:"); wattrset(wbot,COLOR_PAIR(2)); mvwaddstr(wbot,1,31,(tonumsysx(charout(),8))+4); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,37,"BIN:"); wattrset(wbot,COLOR_PAIR(2)); mvwaddstr(wbot,1,41,tonumsysx(charout(),2)); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,52,"Offset:"); wattrset(wbot,COLOR_PAIR(2)); mvwaddstr(wbot,1,59,tonumsysx(getactpos(),16)); wattrset(wbot,COLOR_PAIR(3)); mvwaddstr(wbot,1,67,"h -"); wattrset(wbot,COLOR_PAIR(2)); mvwaddstr(wbot,1,71,tonumsysx(getactpos(),10)); mvwaddstr(wbot,2,1,filename); mvwaddstr(wbot,2,76,(insovr=='O')?"OVR":"INS"); if (realmode == 0) { switchmode(); pos.x=realposx; } } /*************************************************************************** * FUNCTION: void swapbits() * * GOOD FOR: toggle the bit [par1] an the actual position * * INPUTS : - char bit the number (1-8) of the bit to toggle * ***************************************************************************/ void swapbits(char bit) { char bin[]="12345678",*pbin; // for the Bits pbin=bin; int realposx, realmode; realmode=mode; if (realmode==0) { realposx=pos.x; switchmode(); } pbin=tonumsysx(charout(),2); pbin[bit]= (pbin[bit]=='0')?'1':'0'; charin(xto10(pbin,2),3,pos.x); if (realmode==0) { switchmode(); pos.x=realposx; } } /*************************************************************************** * FUNCTION: void delactchar() * * GOOD FOR: delete the char under the actual cursor-position * ***************************************************************************/ void delactchar() { } int main(int argc, char *argv[]) { //Variables unsigned int i; // Public counter int inpch; // The char of input //Preperation printf("GHEX Version 0.5\n"); //Is there a param? if(argc < 2) { fprintf(stderr,"GHEX-MESSAGE:\n\nUSAGE: %s \n",argv[0]); exit(1); } //open the file fp=fopen(argv[1],"r"); if (fp == NULL) { fprintf(stderr,"GHEX-MESSAGE:\n\nERROR opening file: %s \n",argv[1]); exit(2); } // set the pointers initvar(); // init of other useful varibles pos.x = pos.y = 1; filename=argv[1]; //file -> ram if(loadcontents()) { fprintf(stderr,"GHEX-MESSAGE:\n\nERROR reading %s (too less RAM?)\n",argv[1]); exit(3); } // init of terminal if(screeninit()) { endscr(); fprintf(stderr,"!!!Terminal not supported!!! -> Abort \n"); exit(5); } mvwaddstr(wtop,1,1,topline); //Main-procedure initout(); bottomout(); scrrefresh(); //Event-loop while(inpch!=KEY_F(10)) { if (mode==0) { inpch=wgetch(whex); } else { inpch=wgetch(wascii); } switch(inpch) { // The Keys F1-F8 (bit-setting) case KEY_F(9): switchmode(); break; case KEY_F(1): swapbits(0); break; case KEY_F(2): swapbits(1); break; case KEY_F(3): swapbits(2); break; case KEY_F(4): swapbits(3); break; case KEY_F(5): swapbits(4); break; case KEY_F(6): swapbits(5); break; case KEY_F(7): swapbits(6); break; case KEY_F(8): swapbits(7); break; //the delete character-key case KEY_DC : delactchar(); break; //the insert-key, switch insert mode case KEY_EIC: //fallthru case KEY_IC : if (insovr=='O') { insovr='I'; } else { insovr='O'; } break; //Cursor-movement case KEY_LEFT: moveleft(); break; case KEY_RIGHT:moveright(); break; case KEY_DOWN: if(pos.y>15) { scrolld(); } else { pos.y++; } break; case KEY_UP: if(pos.y<2) { scrollu(); } else { pos.y--; } break; case KEY_NPAGE:for(i=0;i<16;i++) { scrolld(); } break; case KEY_PPAGE:for(i=0;i<16;i++) { scrollu(); } break; case KEY_HOME: initout(); break; // BUG: should only work when file > one screen case KEY_END: pdatas=pmax; for(i=0;((*pdatas).plast) && (i < 16);i++) { pdatas=(*pdatas).plast; } while((*pdatas).pnext) { scrolld(); } break; // input characters default: if(mode==0) { if(isdigit(inpch) || (toupper(inpch)>='A' && toupper(inpch)<='F') ) { waddch(whex,toupper(inpch)); char hch[]="00"; // fill hch correct (old values) int xpos=pos.x; // save position switchmode(); // recalc. coordinates ptv=tonumsysx(charout(),16); // actual char in Hex. //* --- DEBUG ONLY mvwaddstr(wbot,2,30,tonumsysx(charout(),16)); // --- END DEBUG switchmode(); // recalc coordinates pos.x=xpos; // restore coorinates if (insovr=='O') // Predef. only in Override! { hch[0] = *(ptv+6); hch[1] = *(ptv+7); } else // In Insert only first char { if(pos.x%3==0) hch[0] = *(ptv+6); } //* --- DEBUG ONLY mvwaddstr(wbot,2,1,hch); mvwaddstr(wbot,2,20,ptv); // --- END DEBUG hch[(pos.x%3)?0:1]=inpch; switchmode(); // recalc coordinates charin(xto10(hch,16),0,xpos); // calc Hex -> Ascii+charin switchmode(); // and back pos.x=xpos; // restore positions moveright(); } } else { if((inpch < 256)) { waddch(wascii,inpch); charin(inpch,1,pos.x); moveright(); } } }; bottomout(); scrrefresh(); } endscr(); unallocmem(); return (fclose(fp)); }