/* api.c : part of The Bastard disassembly environment ========================G
 *
 * Contains  the bulk of the internal code -- specifically, the API routines
 * provided for internal and scripting use. Functions should be in the same
 * order as in api.h
 */
#include <api/api_main.h>
#include <extension.h>

extern struct DISASM_TGT target;
extern struct DISASM_ENV disasm_env;
extern struct DISASM_PREFS disasm_prefs;

/* API Sections:
 *
 *     7. Strings               :: Creating/manipulating NAME objects
 */


/* ---------------------------------------------------------------Strings */
int make_printable(char *name, int len){
   /* quick function to get rid of spaces, etc in names */
   int x;
   for (x = 0; x < len; x++){
      if ( (name[x] < '0' || name[x] > '9') &&
           (name[x] < 'A' || name[x] > 'Z') &&
           (name[x] < 'a' || name[x] > 'z') &&
           (name[x] != '_' && name[x] != '-') ) {/* add user ctrl later */
         /* replace all unapproved chars with '_' */
         name[x] = '_';
      }
   }
   return(1);
}
int GetString(long rva, char *buf, int len) {
   /* returns length of string, *not* bytes written */
   struct string s;
   
   if (d_keyfind(STRING_RVA, &rva) != S_OKAY)
      return(SetLastError(5000));
   d_recread(&s);
   strncpy( buf, s.text, len);      
   return(s.length);
}

int GetEntireString(long rva, char **buf){
   struct string *s;
   struct address *a, addr;
   char *ptr, *dest;
   int x = 0, y = 0;

   if ( (s = GetStringObject(rva)) && (a = GetAddressObject(rva)) ){
      ptr = target.image + a->pa;
      *buf = calloc(s->length , 2); /* need room for excape chars */
      if (! *buf) return(0);
      for (x = 0; x < s->length ; x++){
         dest = *buf + y;
         if ( ptr[x] == '\n') {
            dest[0]='\\'; dest[1]='n'; y++;
         } else if ( ptr[x] == '\r' ) {
            dest[0]='\\'; dest[1]='r'; y++;
         } else if ( ptr[x] == '\t' ) {
            dest[0]='\\'; dest[1]='t'; y++;
         } else 
            *dest = ptr[x];
         y++;
      }
      free(a);
      free(s);
   }
   return(x);
}

/* TODO: Have this resize addr so it matches string size */
int DefineString(long rva) {
   struct string s;
   struct address *a;

   a = GetAddressObject(rva);
   s.length = (*(makestr_fn)ext_lang->fn_makestr)(target.image + a->pa, 
                  s.text, 256, STR_STD);
   s.rva = rva;
   //s.length = strlen(s.text);
   a->size = s.length; /* this is not wholly accurate: no term char :) */
   DBRecordUpdate(ADDRESS_RVA, &rva, a);
   if (d_keyfind(STRING_RVA, &rva) == S_OKAY)
      d_recwrite(&s);
   else if (d_fillnew(STRING, &s) != S_OKAY)
      return(SetLastError(dbError()) );
   return(s.length);
}

int DumpStrings() {
   struct string s;

   d_keyfrst(STRING_RVA);
   while (db_status == S_OKAY) {
      d_recread(&s);
      printf("%X\t%s\n", s.rva, s.text);
      d_keynext(STRING_RVA);
   }
   return(1);
}

int FindStringsInRange(long rva, int size, int type){
   /* rva : start of range   size: extent of range  type: string type */
   struct address *a = NULL;
   struct string str;
   struct name *n;
   char *ptr, name[64];
   int pos=0, len, *state;
   long pa, str_pa;

   /* 1. Get offset into file image to search for strings */
   state = DBSaveState();
   a = GetAddressObject(rva);
   if (a) {
      pa = a->pa;
      free(a);
   } else if ( rva < target.size ) 
      pa = rva;
   else 
      pa = 0;

   /* 2. Call FindString in language module until 0 is returned */
   len = size;
   ptr = &target.image[pa];
   while( len > 0 && ( str.length = 
            (*(findstr_fn)ext_lang->fn_findstr)(ptr, len, &pos, str.text, 
                                                256,type)) ){
      str.rva = rva + (ptr - &target.image[pa]) + pos;
      str_pa = pa +(ptr - &target.image[pa])+ pos;

      /* ignore string if one already exists */
      if ( d_keyfind(STRING_RVA, &str.rva) != S_OKAY){
         d_fillnew(STRING, &str);

      //   if ( GetPA(str.rva) != str_pa || ( 
      //         (a = GetAddressObject(FindClosestAddr(str.rva))) && 
      //         ! (a->flags & ADDR_CODE) )  ){
         DefineAddr(str.rva, str.length, str_pa, 0);
      //   }
         if (! (n = GetNameObject(str.rva)) ) {
            snprintf(name, 63, "str_%s", str.text);
            make_printable(name, strlen(name));
            SetName(str.rva, name, NAME_AUTO);
         } else free(n);
         //if (a) free(a);
      }
      /* adjust size of buffer */
      len -= (pos + str.length);
      ptr += (pos + str.length);
      ptr = &target.image[str_pa + str.length];
   }

   DBRestoreState(state);
   return(1);
}
