1 /**
2  * @namespace   biew
3  * @file        bin_util.c
4  * @brief       This file contains common functions of plugins/bin of BIEW project.
5  * @version     -
6  * @remark      this source file is part of Binary vIEW project (BIEW).
7  *              The Binary vIEW (BIEW) is copyright (C) 1995 Nickols_K.
8  *              All rights reserved. This software is redistributable under the
9  *              licence given in the file "Licence.en" ("Licence.ru" in russian
10  *              translation) distributed in the BIEW archive.
11  * @note        Requires POSIX compatible development system
12  *
13  * @author      Nickols_K
14  * @since       1995
15  * @note        Development, fixes and improvements
16 **/
17 #include <limits.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 
23 #include "bin_util.h"
24 #include "reg_form.h"
25 #include "biewutil.h"
26 #include "bmfile.h"
27 #include "bconsole.h"
28 #include "tstrings.h"
29 #include "plugins/disasm.h"
30 
31 unsigned fmtActiveState = 0;
32 
33 linearArray *PubNames = NULL;
34 
fmtSetState(int state)35 void __FASTCALL__ fmtSetState(int state)
36 {
37    if(state == PS_ACTIVE) { if(fmtActiveState < UINT_MAX) fmtActiveState++; }
38    else  { if(fmtActiveState) fmtActiveState--; }
39 }
40 
fmtComparePubNames(const void __HUGE__ * v1,const void __HUGE__ * v2)41 tCompare __FASTCALL__ fmtComparePubNames(const void __HUGE__ *v1,const void __HUGE__ *v2)
42 {
43   const struct PubName __HUGE__ *pnam1,__HUGE__ *pnam2;
44   pnam1 = (const struct PubName __HUGE__ *)v1;
45   pnam2 = (const struct PubName __HUGE__ *)v2;
46   return __CmpLong__(pnam1->pa,pnam2->pa);
47 }
48 
fmtFindPubName(BGLOBAL fmt_cache,char * buff,unsigned cb_buff,__filesize_t pa,ReadPubNameList fmt_readlist,ReadPubName fmt_readpub)49 tBool __FASTCALL__ fmtFindPubName(BGLOBAL fmt_cache,char *buff,unsigned cb_buff,
50                    __filesize_t pa,
51                    ReadPubNameList fmt_readlist,
52                    ReadPubName fmt_readpub)
53 {
54   struct PubName *ret,key;
55   key.pa = pa;
56   if(!PubNames) (*fmt_readlist)(fmt_cache,MemOutBox);
57   ret = la_Find(PubNames,&key,fmtComparePubNames);
58   if(ret)
59   {
60     (*fmt_readpub)(fmt_cache,ret,buff,cb_buff);
61     return True;
62   }
63   return udnFindName(pa,buff,cb_buff);
64 }
65 
fmtGetPubSym(BGLOBAL fmt_cache,char * str,unsigned cb_str,unsigned * func_class,__filesize_t pa,tBool as_prev,ReadPubNameList fmt_readlist,ReadPubName fmt_readpub)66 __filesize_t __FASTCALL__ fmtGetPubSym(BGLOBAL fmt_cache,char *str,unsigned cb_str,
67                            unsigned *func_class,__filesize_t pa,tBool as_prev,
68                            ReadPubNameList fmt_readlist,
69                            ReadPubName fmt_readpub)
70 {
71   __filesize_t cfpos,ret_addr,cur_addr;
72   unsigned long i,idx,nitems;
73   struct PubName key,*it;
74   cfpos = bmGetCurrFilePos();
75   if(!PubNames) (*fmt_readlist)(fmt_cache,NULL);
76   if(!PubNames->nItems) return 0;
77   ret_addr = 0L;
78   idx = UINT_MAX;
79   key.pa = pa;
80   i = (unsigned)la_FindNearest(PubNames,&key,fmtComparePubNames);
81   nitems = PubNames->nItems;
82   if(as_prev) idx = i;
83   else
84   {
85     static unsigned long multiref_i = 0;
86     get_next:
87     while((cur_addr = ((struct PubName __HUGE__ *)PubNames->data)[i].pa) <= pa)
88     {
89       i++;
90       if((cur_addr == pa && i > multiref_i) || (i >= nitems - 1)) break;
91     }
92     idx = i;
93     if(idx < PubNames->nItems) ret_addr = cur_addr;
94     else ret_addr = 0L;
95     if(ret_addr && ret_addr == pa)
96     {
97       if(idx <= multiref_i) { i = idx; goto get_next; }
98       else multiref_i = idx;
99     }
100     else multiref_i = 0;
101   }
102   if(idx < PubNames->nItems)
103   {
104     ret_addr = ((struct PubName __HUGE__ *)PubNames->data)[idx].pa;
105     *func_class = ((struct PubName __HUGE__ *)PubNames->data)[idx].attr;
106     if(!idx && pa < ret_addr && as_prev)
107     {
108       ret_addr = 0;
109     }
110     else
111     {
112       it = &((struct PubName __HUGE__ *)PubNames->data)[idx];
113       (*fmt_readpub)(fmt_cache,it,str,cb_str);
114       str[cb_str-1] = 0;
115     }
116   }
117   bmSeek(cfpos,BIO_SEEK_SET);
118   return ret_addr;
119 }
120 
ReopenSeek(__filesize_t dist)121 static BGLOBAL __NEAR__ __FASTCALL__ ReopenSeek(__filesize_t dist)
122 {
123  BGLOBAL handle;
124  handle = bioDupEx(bmbioHandle(),BBIO_SMALL_CACHE_SIZE);
125  if(handle != &bNull) bioSeek(handle,dist,BIO_SEEK_SET);
126  else                 errnoMessageBox(READ_FAIL,NULL,errno);
127  return handle;
128 }
129 
fmtShowList(GetNumItems gni,ReadItems ri,const char * title,int flags,unsigned * ordinal)130 int __FASTCALL__ fmtShowList( GetNumItems gni,ReadItems ri,const char * title,int flags,unsigned * ordinal)
131 {
132  int ret;
133  tBool bval;
134  BGLOBAL handle;
135  unsigned nnames;
136  memArray * obj;
137  TWindow* w;
138  ret = -1;
139  if((handle = ReopenSeek(0)) == &bNull) return ret;
140  nnames = gni ? (*gni)(handle) : (unsigned)-1;
141  if(!(obj = ma_Build(nnames,True))) goto exit;
142  w = PleaseWaitWnd();
143  bval = (*ri)(handle,obj,nnames);
144  CloseWnd(w);
145  if(bval)
146  {
147    if(!obj->nItems) { NotifyBox(NOT_ENTRY,title); goto exit; }
148    if(flags)
149    {
150      ret = ma_Display(obj,title,flags,-1);
151      if(ordinal && ret != -1)
152      {
153        char * cptr;
154        char buff[40];
155        cptr = strrchr(obj->data[ret],LB_ORD_DELIMITER);
156        cptr++;
157        strcpy(buff,cptr);
158        *ordinal = atoi(buff);
159      }
160    }
161    else    { ret = -1; ma_Display(obj,title,LB_SORTABLE,-1); }
162  }
163  ma_Destroy(obj);
164  exit:
165  bioClose(handle);
166  return ret;
167 }
168 
169 /* User Defined names (UDN) */
170 
171 typedef struct tagUDN {
172     char		name[256];
173     __filesize_t	offset;
174 }udn;
175 
udn_compare(const void __HUGE__ * e1,const void __HUGE__ * e2)176 static tCompare __FASTCALL__ udn_compare(const void __HUGE__ *e1,const void __HUGE__ *e2)
177 {
178     const udn __HUGE__ *p1 = (const udn __HUGE__ *)e1;
179     const udn __HUGE__ *p2 = (const udn __HUGE__ *)e2;
180     return p1->offset<p2->offset?-1:p1->offset>p2->offset?1:0;
181 }
182 
183 static linearArray *udn_list=NULL;
184 static tBool udn_modified=False;
185 static char udn_fname[4096];
186 
udnAddItem(void)187 static tBool __FASTCALL__ udnAddItem( void ) {
188     __filesize_t off;
189     udn item,*prev;
190     char ud_name[256],prompt[256];
191     off = BMGetCurrFilePos();
192     sprintf(prompt," Name for %08X offset: ",off);
193     prev=NULL;
194     ud_name[0]='\0';
195     if(udn_list) {
196 	item.name[255]='\0';
197 	item.offset=off;
198 	prev = la_Find(udn_list,&item,udn_compare);
199 	if(prev) strcpy(ud_name,prev->name);
200     }
201     if(GetStringDlg(ud_name,prompt," [ENTER] - Proceed ",NAME_MSG))
202     {
203 	if(!udn_list) udn_list=la_Build(0,sizeof(udn),NULL);
204 	if(udn_list) {
205 	    if(prev) strcpy(prev->name,ud_name);
206 	    else {
207 		strcpy(item.name,ud_name);
208 		item.offset=off;
209 		la_AddData(udn_list,&item,NULL);
210 	    }
211 	    la_Sort(udn_list,udn_compare);
212 	}
213 	udn_modified=True;
214 	return True;
215     }
216     return False;
217 }
218 
udnGetNumItems(BGLOBAL handle)219 static unsigned __FASTCALL__ udnGetNumItems(BGLOBAL handle) {
220     UNUSED(handle);
221     return udn_list->nItems;
222 }
223 
udnReadItems(BGLOBAL handle,memArray * names,unsigned nnames)224 static tBool    __FASTCALL__ udnReadItems(BGLOBAL handle,memArray * names,unsigned nnames)
225 {
226     char stmp[256];
227     unsigned i;
228     UNUSED(handle);
229     for(i=0;i<nnames;i++) {
230 	sprintf(stmp,"%-40s %08lX"
231 		,((udn *)udn_list->data)[i].name
232 		,(unsigned long)((udn *)udn_list->data)[i].offset);
233 	if(!ma_AddString(names,stmp,True)) break;
234     }
235     return True;
236 }
237 
udnDeleteItem(void)238 static tBool __FASTCALL__ udnDeleteItem( void ) {
239   int rval=-1;
240   if(udn_list) {
241     rval = fmtShowList(udnGetNumItems,udnReadItems,
242                     " User-defined Names (aka bookmarks) ",
243                     LB_SELECTIVE,NULL);
244     if(rval!=-1) {
245 	la_DeleteData(udn_list,rval);
246 	la_Sort(udn_list,udn_compare);
247 	udn_modified=True;
248     }
249   }
250   else ErrMessageBox("UDN list is empty!",NULL);
251   return rval==-1?False:True;
252 }
253 
udnSelectName(__filesize_t * off)254 tBool __FASTCALL__ udnSelectName(__filesize_t *off) {
255   int rval=-1;
256   if(udn_list) {
257     rval = fmtShowList(udnGetNumItems,udnReadItems,
258                     " User-defined Names (aka bookmarks) ",
259                     LB_SELECTIVE,NULL);
260     if(rval!=-1) *off = ((udn *)udn_list->data)[rval].offset;
261   }
262   else ErrMessageBox("UDN list is empty!",NULL);
263   return rval==-1?False:True;
264 }
265 
udnFindName(__filesize_t pa,char * buff,unsigned cb_buff)266 tBool __FASTCALL__ udnFindName(__filesize_t pa,char *buff, unsigned cb_buff) {
267     udn *item;
268     udn key;
269     if(udn_list) {
270 	key.name[0]='\0';
271 	key.offset = pa;
272 	item=la_Find(udn_list,&key,udn_compare);
273 	if(item) {
274 	    strncpy(buff,item->name,cb_buff);
275 	    buff[cb_buff-1]='\0';
276 	    return True;
277 	}
278     }
279     return False;
280 }
281 
__udnSaveList(void)282 tBool __FASTCALL__ __udnSaveList( void )
283 {
284     unsigned i;
285     if(udn_list) {
286 	FILE *out;
287 	if((out = fopen(udn_fname,"wt"))!=NULL) {
288 	    fprintf(out,"; This is an automatically generated list of user-defined names\n"
289 			"; for: %s\n"
290 			"; by Biew-%s\n"
291 			,BMName()
292 			,BIEW_VERSION);
293 	    for(i=0;i<udn_list->nItems;i++)
294 		fprintf(out,"%016llX:%s\n"
295 		,((udn *)udn_list->data)[i].offset
296 		,((udn *)udn_list->data)[i].name);
297 	    fclose(out);
298 	    udn_modified=False;
299 	    return True;
300 	}
301 	else {
302 	    char stmp[256];
303 	    sprintf(stmp,"Can't open file: %s\n",strerror(errno));
304 	    ErrMessageBox(udn_fname,stmp);
305 	}
306     }
307     return False;
308 }
309 
310 
udnSaveList(void)311 tBool __FASTCALL__ udnSaveList( void ) {
312     if(GetStringDlg(udn_fname," Please enter file name: "," [ENTER] - Proceed ",NAME_MSG))
313     {
314 	if(udn_list)	return __udnSaveList();
315 	else		ErrMessageBox("UDN list is empty!",NULL);
316     }
317     return False;
318 }
319 
__udnLoadList(void)320 tBool __FASTCALL__  __udnLoadList( void ) {
321     unsigned i;
322     udn item;
323     FILE *in;
324     if((in = fopen(udn_fname,"rt"))!=NULL) {
325 	    char buff[4096],*brk;
326 	    unsigned blen;
327 	    i = 0;
328 	    while(!feof(in)) {
329 		buff[0]='\0';
330 		fgets(buff,sizeof(buff),in);
331 		i++;
332 		if(buff[0]==';'||buff[0]=='\0') continue;
333 		brk=strchr(buff,':');
334 		if(!brk) {
335 		    char stmp[256];
336 		    sprintf(stmp,"Can't recognize line: %u",i);
337 		    ErrMessageBox(stmp,NULL);
338 		    return True;
339 		}
340 		*brk='\0';
341 		sscanf(buff,"%016llX",&item.offset);
342 		strncpy(item.name,brk+1,sizeof(item.name));
343 		item.name[sizeof(item.name)-1]='\0';
344 		blen = strlen(item.name);
345 		while(item.name[blen-1]==10||item.name[blen-1]==13) {
346 		    item.name[blen-1]='\0'; blen--;
347 		}
348 		if(!udn_list) udn_list = la_Build(0,sizeof(udn),NULL);
349 		if(udn_list)  la_AddData(udn_list,&item,NULL);
350 		else break;
351 	    }
352 	    fclose(in);
353 	    if(udn_list) la_Sort(udn_list,udn_compare);
354 	    return True;
355 	}
356 	else {
357 	    char stmp[256];
358 	    sprintf(stmp,"Can't open file: %s\n",strerror(errno));
359 	    ErrMessageBox(udn_fname,stmp);
360     }
361     return False;
362 }
363 
udnLoadList(void)364 tBool __FASTCALL__ udnLoadList( void ) {
365     if(GetStringDlg(udn_fname," Please enter file name: "," [ENTER] - Proceed ",NAME_MSG))
366     {
367 	if(udn_list)	return __udnLoadList();
368 	else		ErrMessageBox("UDN list is empty!",NULL);
369     }
370     return False;
371 }
372 
373 static const char *udn_operations[] =
374 {
375     "~Add item",
376     "~Delete item",
377     "~Load list from file",
378     "~Save list to file"
379 };
380 typedef tBool (__FASTCALL__ *udnFunc)( void );
381 
382 static udnFunc udn_funcs[] =
383 {
384     udnAddItem,
385     udnDeleteItem,
386     udnLoadList,
387     udnSaveList
388 };
389 
udnUserNames(void)390 tBool __FASTCALL__ udnUserNames( void ) {
391   unsigned nModes;
392   int i;
393   nModes = sizeof(udn_operations)/sizeof(char *);
394   i = 0;
395   i = SelBoxA(udn_operations,nModes," Select operation: ",i);
396   if(i != -1)
397   {
398      int ret;
399      TWindow * w;
400      w = PleaseWaitWnd();
401      ret = (*udn_funcs[i])();
402      CloseWnd(w);
403      return ret;
404   }
405   return False;
406 }
407 
udnInit(hIniProfile * ini)408 void __FASTCALL__ udnInit( hIniProfile *ini ) {
409   udn_fname[0]='\0';
410   if(isValidIniArgs())
411   {
412     biewReadProfileString(ini,"Biew","Browser","udn_list","",udn_fname,sizeof(udn_fname));
413     if(udn_fname[0]) __udnLoadList();
414   }
415 }
416 
udnTerm(hIniProfile * ini)417 void __FASTCALL__ udnTerm( hIniProfile *ini ) {
418   if(udn_list) {
419     if(udn_modified) {
420 	WarnMessageBox("User-defined list of names was not saved",NULL);
421 	udnSaveList();
422     }
423     la_Destroy(udn_list);
424   }
425   biewWriteProfileString(ini,"Biew","Browser","udn_list",udn_fname);
426 }
427