unit fileload;
interface
uses classes,sysutils,windows,common,menus,gname,savefile,datas,
     imports,exports_,relocs,xref,schedule,proctab;

const
  fmt4:pchar='%4.4x';
  fmt8:pchar='%8.8x';
  PE_EXE  =1;
  MZ_EXE  =2;
  OS2_EXE =3;
  COM_EXE =5;
  NE_EXE  =6;
  SYS_EXE =7;
  LE_EXE  =8;
  BIN_EXE =9;

type
  pmzheader=^tmzheader;
  tmzheader=packed record
    sig:word;
    numbytes,numpages:word;
    numrelocs,headersize:word;
    minpara,maxpara:word;
    initialss,initialsp:word;
    csum:word;
    csip:dword;
    relocoffs:word;
    ovlnum:word;
  end;

  pneheader=^tneheader;
  tneheader=packed record
    sig:word;
    linkerver:word;
    entryoffs,entrylen:word;
    filecrc:dword;
    contentflags:word;
    dsnum:word;
    heapsize,stacksize:word;
    csip,sssp:dword;
    numsegs,nummodules:word;
    nonresnamesize:word;
    offs_segments,offs_resources,offs_resnames,offs_module,offs_imports:word;
    nonresnametable:dword;
    movableentries:word;
    shiftcount:word;
    numresources:word;
    targetos,os_info:byte;
    fastloadoffs,fastloadlen:word;
    mincodeswapareasize,winver:word;
  end;

  pnesegtable=^tnesegtable;
  tnesegtable=packed record
    sectoroffs:word;
    seglength:word;
    segflags:word;
    minalloc:word;
  end;
  pnesegtablearr=^tnesegtablearr;
  tnesegtablearr=array[0..100] of tnesegtable;


  pnesegtablereloc=^tnesegtablereloc;
  tnesegtablereloc=packed record
    reloctype,relocsort:byte;
    segm_offs:word;
    indx,indexoffs:word;
  end;
  pnesegtablerelocarr=^tnesegtablerelocarr;
  tnesegtablerelocarr=array[0..100] of tnesegtablereloc;

  ppeheader=^tpeheader;
  tpeheader=packed record
    sigbytes:dword;
    cputype,objects:word;
    timedatestamp:dword;
    reserveda:array[0..1] of dword;
    nt_hdr_size,flags:word; //?
    reserved:word; //?
    lmajor,lminor:byte;
    reserved1:array[0..2] of dword;
    entrypoint_rva:dword;
    reserved2:array[0..1] of dword;
    image_base:dword;
    objectalign:dword;
    filealign:dword;
    osmajor,osminor:word;
    usermajor,userminor:word;
    subsysmajor,subsysminor:word;
    reserved3:dword;
    imagesize:dword;
    headersize:dword;
    filechecksum:dword;
    subsystem,dllflags:word;
    stackreserve,stackcommit:dword;
    heapreserve,heapcommit:dword;
    reserved4:dword;
    numintitems:dword;
    exporttable_rva,export_datasize:dword;
    importtable_rva,import_datasize:dword;
    resourcetable_rva,resource_datasize:dword;
    exceptiontable_rva,exception_datasize:dword;
    securitytable_rva,security_datasize:dword;
    fixuptable_rva,fixup_datasize:dword;
    debugtable_rva,debug_directory:dword;
    imagedesc_rva,imagedesc_datasize:dword;
    machspecific_rva,machspecific_datasize:dword;
    tls_rva,tls_datasize:dword;
  end;

  tpeobjdata=packed record
    nam:array[0..7] of char;
    virt_size,rva:dword;
    phys_size,phys_offset:dword;
    reserved:array[0..2] of dword;
    obj_flags:dword;
  end;
  ppeobjdata=^tpeobjdataa;
  tpeobjdataa=array[0..100] of tpeobjdata;

  tpeimportdirentry=packed record
    originalthunkrva:dword;
    timedatestamp:dword;
    forwarder:dword;
    namerva:dword;
    firstthunkrva:dword;
  end;
  ppeimportdirentry=^tpeimportdirentrya;
  tpeimportdirentrya=array[0..100] of tpeimportdirentry;

  ppeexportdirentry=^tpeexportdirentry;
  tpeexportdirentry=packed record
    characteristics:dword;
    timedatestamp:dword;
    majver,minver:word;
    namerva:dword;
    base:dword;
    numfunctions:dword;
    numnames:dword;
    funcaddrrva,nameaddrrva,ordsaddrrva:dword;
  end;

  pperestable=^tperestable;
  tperestable=packed record
    flags:dword;
    timedatestamp:dword;
    majver,minver:word;
    numnames,numids:word;
  end;

  ppeleafnode=^tpeleafnode;
  tpeleafnode=packed record
    datarva:dword;
    size:dword;
    codepage:dword;
    reserved:dword;
  end;

  pperestableentry=^tperestableentry;
  tperestableentry=packed record
    id:dword;
    offset:dword;
  end;

  pperelocheader=^tperelocheader;
  tperelocheader=packed record
    rva:dword;
    len:dword;
  end;

//loads file and sets up objects using data.cpp
type
  tfileloader=class
  private
    exetype:integer;
    efile:dword;
    fbuff:pchar;
    rawdata:pchar;
    pdatarva:dword;
  public
    constructor create;
    destructor destroy;override;
    function load(fname:pchar):boolean;
    function getexetype:integer;
    procedure setexetype(etype:integer);
    function loaddb(fname,exename:pchar):boolean;
    procedure savedb(fname,exename:pchar);
    function fileoffset(loc:lptr):dword;
    procedure patchfile(file_offs,num:dword; dat:pchar);
    procedure reloadfile(file_offs,num:dword; dat:pchar);
  private
    procedure readcomfile(fsize:dword);
    procedure readsysfile(fsize:dword);
    procedure readpefile(offs:dword);
    procedure readmzfile(fsize:dword);
    procedure readlefile;
    procedure readnefile(offs:dword);
    procedure reados2file;
    procedure readbinfile(fsize:dword);
    procedure subdirsummary(data,impname:pchar; image_base:dword; rtype:dword);
    procedure leaf2summary(data,nam:pchar; image_base:dword; rtype:dword);
    procedure leafnodesummary(data,resname:pchar; image_base:dword; rtype:dword);
  end;

  function savemessbox(hdwnd:hwnd; msg,wParam,lParam:longint):longint;stdcall;

var
  floader:tfileloader;

implementation
uses disasm,disio,decrypt;

constructor tfileloader.create;
begin
  inherited create;
  efile:=dword(INVALID_HANDLE_VALUE);
  exetype:=0;
  fbuff:=nil;
end;

destructor tfileloader.destroy;
begin
  if fbuff<>nil then dispose(fbuff);
  CloseHandle(efile);
end;

function moreoptions(hdwnd:hwnd; msg,wParam,lParam:longint):longint;stdcall;
const brush:HBRUSH=0;
begin
  result:=0;
  case msg of
   WM_COMMAND:
    case wParam of
     IDOK:
      begin
        options.codedetect:=0;
        if IsDlgButtonChecked(hdwnd,advanced_pushbp)    <>0 then options.codedetect:=options.codedetect or CD_PUSHBP;
        if IsDlgButtonChecked(hdwnd,advanced_aggressive)<>0 then options.codedetect:=options.codedetect or CD_AGGRESSIVE;
        if IsDlgButtonChecked(hdwnd,advanced_enter)     <>0 then options.codedetect:=options.codedetect or CD_ENTER;
        if IsDlgButtonChecked(hdwnd,advanced_movbx)     <>0 then options.codedetect:=options.codedetect or CD_MOVBX;
        if IsDlgButtonChecked(hdwnd,advanced_moveax)    <>0 then options.codedetect:=options.codedetect or CD_MOVEAX;
        if IsDlgButtonChecked(hdwnd,advanced_eaxfromesp)<>0 then options.codedetect:=options.codedetect or CD_EAXFROMESP;
        EndDialog(hdwnd,0);
        result:=1; exit;
      end;
     end;
   WM_INITDIALOG:
    begin
      brush:=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
      CheckDlgButton(hdwnd,advanced_pushbp,options.codedetect and CD_PUSHBP);
      CheckDlgButton(hdwnd,advanced_aggressive,options.codedetect and CD_AGGRESSIVE);
      CheckDlgButton(hdwnd,advanced_enter,options.codedetect and CD_ENTER);
      CheckDlgButton(hdwnd,advanced_movbx,options.codedetect and CD_MOVBX);
      CheckDlgButton(hdwnd,advanced_moveax,options.codedetect and CD_MOVEAX);
      CheckDlgButton(hdwnd,advanced_eaxfromesp,options.codedetect and CD_EAXFROMESP);
      exit;
    end;
   WM_DESTROY:
    begin
      DeleteObject(brush); exit;
    end;
   WM_CTLCOLORSTATIC,
   WM_CTLCOLORBTN,
   WM_CTLCOLORDLG,
   WM_SYSCOLORCHANGE:
    begin
      SetBkColor(HDC(wParam),GetSysColor(COLOR_BTNFACE));
      result:=brush; exit;
    end;
  end;
end;

function helpbox1(hdwnd:hwnd; msg,wParam,lParam:longint):longint;stdcall;
const brush:HBRUSH=0;
begin
  result:=0;
  case msg of
   WM_COMMAND:
    case wParam of
     IDOK: begin EndDialog(hdwnd,0); result:=1; end;
    end;
   WM_INITDIALOG: brush:=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
   WM_DESTROY:    DeleteObject(brush);
   WM_CTLCOLORSTATIC, WM_CTLCOLORDLG, WM_SYSCOLORCHANGE:
    begin
      SetBkColor(HDC(wParam),GetSysColor(COLOR_BTNFACE));
      result:=brush;
    end;
  end;
end;

function checktypebox(hdwnd:hwnd; msg,wParam,lParam:longint):longint;stdcall;
const brush:HBRUSH=0;
var
  segtext :array[0..200] of char;
  offstext:array[0..200] of char;
  i,exetype:integer;
begin
  result:=0;
  case msg of
   WM_INITDIALOG:
    begin
      brush:=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
      exetype:=floader.getexetype;
      options.loadaddr.s:=$1000;
      options.loadaddr.o:=$00;
      case exetype of
       NE_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'NE Executable');
          CheckDlgButton(hdwnd,IDC_DEFAULTBUTTON,1);
          options.processor:=PROC_80486; options.mode16:=TRUE;
        end;
       COM_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'COM File');
          CheckDlgButton(hdwnd,IDC_DEFAULTBUTTON,1);
          options.processor:=PROC_80386; options.mode16:=TRUE;
          options.loadaddr.o:=$100;
        end;
       SYS_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'SYS File');
          CheckDlgButton(hdwnd,IDC_DEFAULTBUTTON,1);
          options.processor:=PROC_80386; options.mode16:=TRUE;
          options.loadaddr.o:=$00;
        end;
       PE_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'PE Executable');
          CheckDlgButton(hdwnd,IDC_DEFAULTBUTTON,1);
          options.processor:=PROC_PENTIUM; options.mode16:=FALSE;
        end;
       OS2_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'OS2 Executable');
          CheckDlgButton(hdwnd,IDC_DEFAULTBUTTON,1);
          options.processor:=PROC_PENTIUM; options.mode16:=FALSE;
        end;
       LE_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'LE Executable');
          CheckDlgButton(hdwnd,IDC_DEFAULTBUTTON,1);
          options.processor:=PROC_80486; options.mode16:=FALSE;
        end;
       MZ_EXE:
        begin
          SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'COM File');
          CheckDlgButton(hdwnd,IDC_DOSBUTTON,1);
          options.processor:=PROC_80386; options.mode16:=TRUE;
        end;
       else  // BIN_EXE:
        SetDlgItemText(hdwnd,IDC_DEFAULTBUTTON,'COM File');
        CheckDlgButton(hdwnd,IDC_BINBUTTON,1);
        options.processor:=PROC_8086; options.mode16:=TRUE;
      end;
      options.mode32:=not options.mode16;
      CheckDlgButton(hdwnd,load_debug,ord(options.loaddebug));
      CheckDlgButton(hdwnd,demangle_names,ord(options.demangle));
      CheckDlgButton(hdwnd,IDC_16DASM,ord(options.mode16));
      CheckDlgButton(hdwnd,IDC_32DASM,ord(options.mode32));
      CheckDlgButton(hdwnd,IDC_LOADDATA,ord(options.loaddata));
      CheckDlgButton(hdwnd,IDC_LOADRESOURCES,ord(options.loadresources));
      i:=0;
      while procnames[i].num<>0 do begin
        SendDlgItemMessage(hdwnd,IDC_LISTBOX1,LB_ADDSTRING,0,dword(@procnames[i].nam^));
        if options.processor=procnames[i].num then
          SendDlgItemMessage(hdwnd,IDC_LISTBOX1,LB_SETCURSEL,i,0);
        inc(i);
      end;
      strlfmt(@segtext,200,fmt4,[options.loadaddr.s]);
      strlfmt(@offstext,200,fmt8,[options.loadaddr.o]);
      SendDlgItemMessage(hdwnd,IDC_SEGEDIT,WM_SETTEXT,0,dword(@segtext));
      SendDlgItemMessage(hdwnd,IDC_OFFSEDIT,WM_SETTEXT,0,dword(@offstext));
      result:=1; exit;
    end;
   WM_DESTROY:
    begin
      DeleteObject(brush); exit;
    end;
   WM_CTLCOLORSTATIC,
   WM_CTLCOLORDLG,
   WM_CTLCOLORBTN,
   WM_SYSCOLORCHANGE:
    begin
      SetBkColor(HDC(wParam),GetSysColor(COLOR_BTNFACE));
      result:=brush; exit;
    end;
   WM_COMMAND:
    begin
      case LOWORD(wParam) of
       IDOK:
        begin
          if IsDlgButtonChecked(hdwnd,IDC_DEFAULTBUTTON)=0 then begin
            if IsDlgButtonChecked(hdwnd,IDC_DOSBUTTON)<>0 then floader.setexetype(MZ_EXE)
            else floader.setexetype(BIN_EXE);
          end else
            if (exetype=BIN_EXE)or(exetype=MZ_EXE) then floader.setexetype(COM_EXE);
          options.processor:=procnames[SendDlgItemMessage(hdwnd,IDC_LISTBOX1,LB_GETCURSEL,0,0)].num;
          EndDialog(hdwnd,0);
          result:=1; exit;
        end;
       IDC_SEGEDIT:
        begin
          if HIWORD(wParam)=EN_CHANGE then begin
            fillchar(segtext,sizeof(segtext),0);
            SendDlgItemMessage(hdwnd,IDC_SEGEDIT,WM_GETTEXT,18,dword(@segtext));
            options.loadaddr.s:=strtoint('$'+strpas(segtext));
          end;
          result:=1; exit;
        end;
       IDC_OFFSEDIT:
        begin
          if HIWORD(wParam)=EN_CHANGE then begin
            fillchar(offstext,sizeof(offstext),0);
            SendDlgItemMessage(hdwnd,IDC_OFFSEDIT,WM_GETTEXT,18,dword(@offstext));
            options.loadaddr.o:=strtoint('$'+strpas(offstext));
          end;
          result:=1; exit;
        end;
       IDC_HELPBUTTON1:
        begin
          DialogBox(Inst,MAKEINTRESOURCE(HELPDIALOG_1),hdwnd,@helpbox1);
          result:=1; exit;
        end;
       more_options:
        begin
          DialogBox(Inst,MAKEINTRESOURCE(Advanced_Options),hdwnd,@moreoptions);
          result:=1; exit;
        end;
       load_debug:
        begin
          options.loaddebug:=not options.loaddebug;
          CheckDlgButton(hdwnd,load_debug,ord(options.loaddebug));
          result:=1; exit;
        end;
       demangle_names:
        begin
          options.demangle:=not options.demangle;
          CheckDlgButton(hdwnd,demangle_names,ord(options.demangle));
          result:=1; exit;
        end;
       IDC_16DASM:
        begin
          options.mode16:=not options.mode16;
          CheckDlgButton(hdwnd,IDC_16DASM,ord(options.mode16));
          result:=1; exit;
        end;
       IDC_32DASM:
        begin
          options.mode32:=not options.mode32;
          CheckDlgButton(hdwnd,IDC_32DASM,ord(options.mode32));
          result:=1; exit;
        end;
       IDC_LOADDATA:
        begin
          options.loaddata:=not options.loaddata;
          CheckDlgButton(hdwnd,IDC_LOADDATA,ord(options.loaddata));
          result:=1; exit;
        end;
       IDC_LOADRESOURCES:
        begin
          options.loadresources:=not options.loadresources;
          CheckDlgButton(hdwnd,IDC_LOADRESOURCES,ord(options.loadresources));
          result:=1; exit;
        end;
      end;
    end;
  end;
end;

//checks header info, puts up initial loading dialog box and
//selects info routine for file.
function tfileloader.load(fname:pchar):boolean;
var
  mzhead :array[0..2] of char;
  exthead:array[0..2] of char;
  pe_offset:dword;
  num:long;
  fsize:dword;
begin
  result:=false;
  if efile<>INVALID_HANDLE_VALUE then exit;
  efile:=CreateFile(fname,GENERIC_READ or GENERIC_WRITE,1,nil,OPEN_EXISTING,0,0);
  if efile=INVALID_HANDLE_VALUE then exit;
  if SysfileIsDevice_(efile)<>FILE_TYPE_DISK  then exit;
  exetype:=BIN_EXE;
  if ReadFile(efile,mzhead,2,num,nil) then begin
    if (num=2)and(((mzhead[0]='M')and(mzhead[1]='Z')) or
       ((mzhead[0]='Z')or(mzhead[1]='M')))
    then
      SetFilePointer(efile,$3c,nil,FILE_BEGIN);
      if ReadFile(efile,pe_offset,4,num,nil) then
        SetFilePointer(efile,pe_offset,nil,FILE_BEGIN);
      if ReadFile(efile,exthead,2,num,nil) then begin
        if      pw(@exthead[0])^=$4550 then exetype:=PE_EXE
        else if pw(@exthead[0])^=$454e then exetype:=NE_EXE
        else if pw(@exthead[0])^=$454c then exetype:=LE_EXE
        else if pw(@exthead[0])^=$584c then exetype:=OS2_EXE
        else exetype:=MZ_EXE;
      end;
    end else begin
      if strlen(fname)>3 then begin
        if lstrcmpi(fname+strlen(fname)-3,'com')=0 then begin
          SetFilePointer(efile,0,nil,FILE_BEGIN);
          exetype:=COM_EXE;
        end else if lstrcmpi(fname+strlen(fname)-3,'sys')=0 then begin
          SetFilePointer(efile,0,nil,FILE_BEGIN);
          exetype:=SYS_EXE;
        end;
      end;
  end;
  fsize:=GetFileSize(efile,nil);
  getmem(fbuff,fsize);
  SetFilePointer(efile,0,nil,FILE_BEGIN);
  ReadFile(efile,fbuff^,fsize,num,nil);
  DialogBox(Inst,MAKEINTRESOURCE(D_checktype),mainwindow,@checktypebox);
  if options.loadaddr.s=0 then begin
    options.loadaddr.s:=$1000;
    MessageBox(mainwindow,'Sorry - Can''''t use a zero segment base.\nSegment Base has been set to 0x1000'
     ,'Borg Message',MB_OK);
  end;
  dsm.dissettable;
  case exetype of
   BIN_EXE:     readbinfile(fsize);
   PE_EXE:      readpefile(pe_offset);
   MZ_EXE:      readmzfile(fsize);
   OS2_EXE:
    begin
      reados2file;
      CloseHandle(efile);
      efile:=dword(INVALID_HANDLE_VALUE);
      exetype:=0;
      exit; // at the moment;
    end;
   COM_EXE:    readcomfile(fsize);
   SYS_EXE:    readsysfile(fsize);
   LE_EXE:
    begin
      readlefile;
      CloseHandle(efile);
      efile:=dword(INVALID_HANDLE_VALUE);
      exetype:=0;
      exit; // at the moment;
    end;
   NE_EXE:     readnefile(pe_offset);
   else
     CloseHandle(efile);
     efile:=dword(INVALID_HANDLE_VALUE);
     exetype:=0;
     exit;
  end;
  result:=TRUE;
end;

function tfileloader.getexetype;
begin
  result:=exetype;
end;

procedure tfileloader.setexetype(etype:integer);
begin
  exetype:=etype;
end;

function savemessbox(hdwnd:hwnd; msg,wParam,lParam:longint):longint;
const brush:HBRUSH=0;
var drect:tRECT;
begin
  result:=0;
  case msg of
   WM_INITDIALOG:
    begin
      brush:=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
      GetWindowRect(hdwnd,drect);
      MoveWindow(hdwnd,((mainwnd.right+mainwnd.left)-(drect.right-drect.left)) div 2,
       ((mainwnd.bottom+mainwnd.top)-(drect.bottom-drect.top)) div 2,drect.right-drect.left,drect.bottom-drect.top,TRUE);
      exit;
    end;
   WM_DESTROY:
    begin
      DeleteObject(brush); exit;
    end;
   WM_CTLCOLORSTATIC,
   WM_CTLCOLORDLG,
   WM_SYSCOLORCHANGE:
    begin
      SetBkColor(HDC(wParam),GetSysColor(COLOR_BTNFACE));
      result:=brush;
    end;
  end;
end;

function loadmessbox(hdwnd,msg,wParam,lParam:dword):dword;stdcall;
const brush:HBRUSH=0;
var drect:tRECT;
begin
  result:=0;
  case msg of
   WM_INITDIALOG:
    begin
      brush:=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
      GetWindowRect(hdwnd,drect);
      MoveWindow(hdwnd,((mainwnd.right+mainwnd.left)-(drect.right-drect.left))div 2,
       ((mainwnd.bottom+mainwnd.top)-(drect.bottom-drect.top))div 2,drect.right-drect.left,drect.bottom-drect.top,TRUE);
    end;
   WM_DESTROY: DeleteObject(brush);
   WM_CTLCOLORSTATIC, WM_CTLCOLORDLG, WM_SYSCOLORCHANGE:
    begin
      SetBkColor(HDC(wParam),GetSysColor(COLOR_BTNFACE)); result:=brush;
    end;
  end;
end;

procedure tfileloader.savedb(fname,exename:pchar);
var
  sf:tsavefile;
  flen:dword;
  bver:dword;
  sbox:HWND;
begin
  sf:=tsavefile.create;
  sbox:=CreateDialog(Inst,MAKEINTRESOURCE(save_box),mainwindow,@savemessbox);
try
  assignfile(log,'log.txt'); rewrite(log);
  sf.sopen(fname,GENERIC_WRITE,1,CREATE_ALWAYS,0);
  sf.swrite('BORG',4);
  bver:=BORG_VER;
  sf.swrite(@bver,sizeof(bver));
  flen:=strlen(exename)+1;
  sf.swrite(@flen,sizeof(dword));
  sf.swrite(exename,flen);
  dobool(options.loaddebug);
  dobool(options.mode16);
  dobool(options.mode32);
  dobool(options.loaddata);
  dobool(options.loadresources);
  dobool(options.demangle);
  dobool(options.cfa);
  sf.swrite(@options,sizeof(tglobaloptions));
  sf.swrite(@exetype,sizeof(integer));
  if not dta.savedb(sf,fbuff) then begin  // save segment info
    MessageBox(mainwindow,'Segments:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not import.savedb(sf) then begin     // save asm database
    MessageBox(mainwindow,'Imports:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not expt.savedb(sf) then begin       // save export info
    MessageBox(mainwindow,'Exports:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not nam.savedb(sf) then begin        // save names
    MessageBox(mainwindow,'Names:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not reloc.savedb(sf) then begin      // save relocs
    MessageBox(mainwindow,'Relocs:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not xrefs.savedb(sf) then begin      // save xrefs
    MessageBox(mainwindow,'Xrefs:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not dio.savedb(sf,fbuff) then begin  // save asm database
    MessageBox(mainwindow,'Database:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not decrypter.savedb(sf) then begin  // save decrypter list
    MessageBox(mainwindow,'Decryptors:File write failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  sf.flushfilewrite;
finally
  sf.free;
  DestroyWindow(sbox);
  closefile(log);
end;
end;

function tfileloader.loaddb(fname,exename:pchar):boolean;
var
  sf:tsavefile;
  tbuff:array[0..20] of char;
  bver,num,flen:integer;
  i:dword;
  lbox:HWND;
  compr:boolean;
begin
  result:=FALSE;
  sf:=tsavefile.create;
  sf.compr:=true;
  with tfilestream.create(strpas(fname),fmOpenRead) do try
    read(tbuff,4); if (tbuff[2]='R') and (tbuff[3]='G') then sf.compr:=false;
  finally free;
  end;
try
  lbox:=CreateDialog(Inst,MAKEINTRESOURCE(load_box),mainwindow,@loadmessbox);
  if not sf.sopen(fname,dword(GENERIC_READ),1,OPEN_EXISTING,0) then exit;
  // load header check its a database file
  tbuff[4]:=#0;
  if not sf.sread(tbuff,4,num) then begin
    MessageBox(mainwindow,'File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if strcomp(tbuff,'BORG')<>0 then begin
    MessageBox(mainwindow,'Not A Borg Database File',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  // read BORG_VERSION
  if not sf.sread(@bver,sizeof(bver),num) then begin
    MessageBox(mainwindow,'File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if bver<>BORG_VER then begin
    MessageBox(mainwindow,'Warning:diff version savefile [will attempt load]',fname,MB_OK or MB_ICONEXCLAMATION);
  end;
  // load filename of exe file.
  flen:=strlen(exename)+1;
  if not sf.sread(@flen,sizeof(dword),num) then begin
    MessageBox(mainwindow,'File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not sf.sread(exename,flen,num) then begin
    MessageBox(mainwindow,'File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not sf.sread(@options,sizeof(tglobaloptions),num) then begin // load options.
    MessageBox(mainwindow,'File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not sf.sread(@exetype,sizeof(integer),num) then begin
    MessageBox(mainwindow,'File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  // load exe file.
  with tfilestream.create(strpas(exename),fmOpenReadWrite) do begin
    getmem(fbuff,size); read(fbuff^,size); free;
  end;
  if not dta.loaddb(sf,fbuff) then begin // load segment info
    MessageBox(mainwindow,'Fatal Error'#13#10'Segments:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not import.loaddb(sf) then begin    // load import info
    MessageBox(mainwindow,'Fatal Error'#13#10'Imports:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not expt.loaddb(sf) then begin      // load export info
    MessageBox(mainwindow,'Fatal Error'#13#10'Exports:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not nam.loaddb(sf) then begin       // load names
    MessageBox(mainwindow,'Fatal Error'#13#10'Names:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not reloc.loaddb(sf) then begin     // load relocs
    MessageBox(mainwindow,'Fatal Error'#13#10'Relocs:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not xrefs.loaddb(sf) then begin     // load xrefs
    MessageBox(mainwindow,'Fatal Error'#13#10'Xrefs:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not dio.loaddb(sf,fbuff) then begin // load asm database
    MessageBox(mainwindow,'Fatal Error'#13#10'Database:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not reloc.relocfile then begin
    MessageBox(mainwindow,'Fatal Error'#13#10'Relocating File',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  if not decrypter.loaddb(sf) then begin
    MessageBox(mainwindow,'Fatal Error'#13#10'Decryptors:File read failed ?',fname,MB_OK or MB_ICONEXCLAMATION); exit;
  end;
  result:=TRUE;
finally
  sf.free;
  DestroyWindow(lbox);
end;
end;

procedure tfileloader.readcomfile(fsize:dword);
begin
  options.loadaddr.o:=$100;
  options.dseg:=options.loadaddr.s;
  dta.addseg(options.loadaddr,fsize,fbuff,code16,nil);
  dta.possibleentrycode(options.loadaddr);
  options.mode16:=TRUE;
  options.mode32:=FALSE;
  dio.setcuraddr(options.loadaddr);
  scheduler.addtask(dis_code,priority_definitecode,options.loadaddr,0,nil);
  scheduler.addtask(nameloc,priority_nameloc,options.loadaddr,0,'start');
  scheduler.addtask(windowupdate,priority_window,nlptr,0,nil);
end;

procedure tfileloader.readsysfile(fsize:dword);
var
  t:lptr;
begin
  options.loadaddr.o:=0;
  options.dseg:=options.loadaddr.s;
  dta.addseg(options.loadaddr,fsize,fbuff,code16,nil);
  dta.possibleentrycode(options.loadaddr);
  options.mode16:=TRUE;
  options.mode32:=FALSE;
  dio.setcuraddr(options.loadaddr);
  scheduler.addtask(dis_dataword,priority_data,options.loadaddr,0,nil);
  scheduler.addtask(dis_dataword,priority_data,options.loadaddr,2,nil);
  scheduler.addtask(dis_dataword,priority_data,options.loadaddr,4,nil);
  scheduler.addtask(dis_dataword,priority_data,options.loadaddr,6,nil);
  scheduler.addtask(dis_dataword,priority_data,options.loadaddr,8,nil);
  if (pw(@fbuff^)^<>0)and(pw(@fbuff^)^<fsize) then begin
    t.s:=options.loadaddr.s;
    t.o:=pw(@fbuff[0])^;
    scheduler.addtask(dis_code,priority_definitecode,t,0,nil);
    scheduler.addtask(nameloc,priority_nameloc,t,0,'interrupt_routine');
  end;
  if (pw(@fbuff[3])^<>0)and(pw(@fbuff[3])^<fsize) then begin
    t.s:=options.loadaddr.s;
    t.o:=pw(@fbuff[3])^;
    scheduler.addtask(dis_code,priority_definitecode,t,0,nil);
    scheduler.addtask(nameloc,priority_nameloc,t,0,'strategy');
  end;
  if (pw(@fbuff[4])^<>0)and(pw(@fbuff[4])^<fsize) then begin
    t.s:=options.loadaddr.s;
    t.o:=pw(@fbuff[4])^;
    scheduler.addtask(dis_code,priority_definitecode,t,0,nil);
    scheduler.addtask(nameloc,priority_nameloc,t,0,'interrupt');
  end;
  scheduler.addtask(windowupdate,priority_window,nlptr,0,nil);
end;

procedure tfileloader.readpefile(offs:dword);
var
  peh:ppeheader;
  pdata:ppeobjdata;
  pestart,impname,expname:pchar;
  chktable:pchar;
  lef,leo,len,start_addr:lptr;
  fnaddr,nnaddr:pda;
  onaddr,rdata:pwa;
  numsymbols,numitems,numrelocs:dword;
  impbuff:array[0..99] of char;
  inum:string;
  newimpname:pchar;
  sseg,t:lptr;
  j:dword;
  i,k,k1,clen:integer;
  impdir:ppeimportdirentry;
  uinit:pchar;
  expdir:ppeexportdirentry;
  per:pperelocheader;
  thunkrva,impaddr,impaddr2,numtmp:dword;
  imphint:pda;
  peobjdone:boolean;
  resdir:pperestable;
  rentry:pperestableentry;
begin
  start_addr:=nlptr;
  options.dseg:=options.loadaddr.s;
  sseg.s:=options.loadaddr.s;
  sseg.o:=0;
  pestart:=@fbuff[offs];
  peh:=ppeheader(pestart);
  options.loadaddr.o:=peh.image_base;
  // bugfix ver 2.19
  // pdata:=ppeobjdata(pestart+sizeof(tpeheader)+(peh.numintitems-$0a)*8);
  pdata:=ppeobjdata(pestart+24+peh.nt_hdr_size);
  for i:=0 to peh.objects-1 do begin
    peobjdone:=FALSE;
    if (pdata^[i].rva=peh.exporttable_rva) or  // export info
      (peh.exporttable_rva>pdata^[i].rva)and(peh.exporttable_rva<pdata^[i].rva+pdata^[i].phys_size)
    then begin
      expdir:=ppeexportdirentry(@fbuff[pdata^[i].phys_offset+peh.exporttable_rva-pdata^[i].rva]);
      t.s:=options.loadaddr.s;
      t.o:=peh.image_base+peh.exporttable_rva;
      scheduler.addtask(dis_datadword,priority_data,t,0,nil);
      scheduler.addtask(dis_datadword,priority_data,t,4,nil);
      scheduler.addtask(dis_dataword,priority_data,t,8,nil);
      scheduler.addtask(dis_dataword,priority_data,t,10,nil);
      scheduler.addtask(dis_datadword,priority_data,t,12,nil);
      scheduler.addtask(dis_datadword,priority_data,t,16,nil);
      scheduler.addtask(dis_datadword,priority_data,t,20,nil);
      scheduler.addtask(dis_datadword,priority_data,t,24,nil);
      scheduler.addtask(dis_datadword,priority_data,t,28,nil);
      for k1:=0 to peh.objects-1 do begin
        if (expdir.namerva>=pdata^[k1].rva)and(expdir.namerva<pdata^[k1].rva+pdata^[k1].phys_size)
        then begin
          expname:=@fbuff[expdir.namerva-pdata^[k1].rva+pdata^[k1].phys_offset];
          break;
        end;
      end;
      t.o:=expdir.namerva+peh.image_base;
      scheduler.addtask(dis_datastring,priority_data,t,0,nil);
      numsymbols:=expdir.numfunctions;
      getmem(chktable,numsymbols);
      for j:=0 to numsymbols-1 do chktable[j]:=#0;
      if expdir.numnames<numsymbols then numsymbols:=expdir.numnames;
      for k:=0 to peh.objects-1 do begin
        if (expdir.nameaddrrva>=pdata^[k].rva)and(expdir.nameaddrrva<pdata^[k].rva+pdata^[k].phys_size)
        then begin
          nnaddr:=@fbuff[expdir.nameaddrrva-pdata^[k].rva+pdata^[k].phys_offset]; break;
        end;
      end;
      for k:=0 to peh.objects-1 do begin
        if (expdir.funcaddrrva>=pdata^[k].rva)and(expdir.funcaddrrva<pdata^[k].rva+pdata^[k].phys_size)
        then begin
          fnaddr:=@fbuff[expdir.funcaddrrva-pdata^[k].rva+pdata^[k].phys_offset]; break;
        end;
      end;
      for k:=0 to peh.objects-1 do begin
        if (expdir.ordsaddrrva>=pdata^[k].rva)and(expdir.ordsaddrrva<pdata^[k].rva+pdata^[k].phys_size)
        then begin
          onaddr:=@fbuff[expdir.ordsaddrrva-pdata^[k].rva+pdata^[k].phys_offset]; break;
        end;
      end;
      lef.s:=options.loadaddr.s; lef.o:=expdir.funcaddrrva+peh.image_base;
      leo.s:=options.loadaddr.s; leo.o:=expdir.ordsaddrrva+peh.image_base;
      len.s:=options.loadaddr.s; len.o:=expdir.nameaddrrva+peh.image_base;
      while numsymbols<>0 do begin
        scheduler.addtask(dis_datadword,priority_data,lef,0,nil);
        scheduler.addtask(dis_dataword,priority_data,leo,0,nil);
        scheduler.addtask(dis_datadword,priority_data,len,0,nil);
        chktable[onaddr^[0]]:=#1;
        t.s:=options.loadaddr.s;
        t.o:=peh.image_base+pd(pointer(dword(fnaddr)+onaddr^[0]))^; //???
        scheduler.addtask(dis_export,priority_export,t,0,@fbuff[nnaddr^[pdata^[k].phys_offset-pdata^[k].rva]]);
        t.s:=options.loadaddr.s;
        t.o:=nnaddr^[peh.image_base];
        scheduler.addtask(dis_datastring,priority_data,t,0,nil);
        // actually not definite code since data can be exported too, eg a debug hook address
        // so uses dis_exportcode which will disassemble if its in a code segment only.
        t.s:=options.loadaddr.s;
        t.o:=peh.image_base+fnaddr^[onaddr^[0]];
        scheduler.addtask(dis_exportcode,priority_definitecode,t,0,nil);
        dec(numsymbols);
        inc(dword(onaddr),4);
        inc(dword(nnaddr),4);
        inc(lef.o,4);
        inc(leo.o,2);
        inc(len.o,4);
      end;
      if expdir.numfunctions>expdir.numnames then begin
        for j:=0 to expdir.numfunctions-1 do begin
          if chktable[j]=#0 then begin
            numtmp:=j+expdir.base;
            fmtstr(inum,'%02d',[numtmp]);
            lstrcpyn(impbuff,expname,GNAME_MAXLEN-8);
            k:=0;
            while (impbuff[k]<>#0)and(k<GNAME_MAXLEN-8) do begin
              if impbuff[k]='.' then break;
              inc(k);
            end;
            strcopy(@impbuff[k],'::ord_');
            strpcopy(impbuff+strlen(impbuff),inum);
            getmem(newimpname,strlen(impbuff)+1);
            strcopy(newimpname,impbuff);
            if fnaddr^[j]<>0 then begin
              t.s:=options.loadaddr.s;
              t.o:=fnaddr^[j]+peh.image_base;
              scheduler.addtask(dis_ordexport,priority_export,t,0,newimpname);
              scheduler.addtask(dis_code,priority_definitecode,t,0,nil);
            end;
          end;
        end;
      end;
      freemem(chktable);
    end;
    if (pdata^[i].rva=peh.importtable_rva) or // import info
      ((peh.importtable_rva>pdata^[i].rva)and(peh.importtable_rva<pdata^[i].rva+pdata^[i].phys_size))
    then begin
      impdir:=@fbuff[pdata^[i].phys_offset+peh.importtable_rva-pdata^[i].rva];
      j:=0;
      while impdir^[j].firstthunkrva<>0 do begin
        t.s:=options.loadaddr.s;
        t.o:=peh.image_base+peh.importtable_rva+j*sizeof(tpeimportdirentry);
        scheduler.addtask(dis_datadword,priority_data,t,0,nil);
        scheduler.addtask(dis_datadword,priority_data,t,4,nil);
        scheduler.addtask(dis_datadword,priority_data,t,8,nil);
        scheduler.addtask(dis_datadword,priority_data,t,12,nil);
        scheduler.addtask(dis_datadword,priority_data,t,16,nil);
        for k1:=0 to peh.objects-1 do begin
          if (impdir^[j].namerva>=pdata^[k1].rva)and(impdir^[j].namerva<pdata^[k1].rva+pdata^[k1].phys_size)
          then begin
            impname:=@fbuff[impdir^[j].namerva-pdata^[k1].rva+pdata^[k1].phys_offset]; break;
          end;
        end;
        t.s:=options.loadaddr.s;
        t.o:=impdir^[j].namerva+peh.image_base;
        scheduler.addtask(dis_datastring,priority_data,t,0,nil);
        if impdir^[j].originalthunkrva=0 then thunkrva:=impdir^[j].firstthunkrva
        else thunkrva:=impdir^[j].originalthunkrva;
        for k:=0 to peh.objects-1 do begin
          if (thunkrva>=pdata^[k].rva)and(thunkrva<pdata^[k].rva+pdata^[k].phys_size)
          then begin
            imphint:=@fbuff[thunkrva-pdata^[k].rva+pdata^[k].phys_offset];
            break;
          end;
        end;
        impaddr:=impdir^[j].firstthunkrva+peh.image_base;
        impaddr2:=impdir^[j].originalthunkrva+peh.image_base;
        while imphint^[0]<>0 do begin
          if imphint^[0] and $80000000<>0 then begin
            numtmp:=imphint^[0] and $7fffffff;
            fmtstr(inum,'%02d',[numtmp]);
            strcopy(impbuff,@impname);
            k:=0;
            while impbuff[k]<>#0 do begin
              if impbuff[k]='.' then break;
              inc(k);
            end;
            strcopy(@impbuff[k],'::ord_');
            strpcopy(impbuff+strlen(impbuff),inum);
            getmem(newimpname,strlen(impbuff)+1);
            strcopy(newimpname,impbuff);
            t.s:=options.loadaddr.s;
            t.o:=impaddr;
            scheduler.addtask(dis_ordimport,priority_import,t,0,newimpname);
          end else begin
            t.s:=options.loadaddr.s;
            t.o:=impaddr;
            scheduler.addtask(dis_import,priority_import,t,0,@fbuff[imphint^[0]+2+pdata^[k1].phys_offset-pdata^[k1].rva]);
          end;
          t.s:=options.loadaddr.s;
          t.o:=peh.image_base+imphint^[0];
          scheduler.addtask(dis_dataword,priority_data,t,0,nil);
          scheduler.addtask(dis_datastring,priority_data,t,2,nil);
          t.s:=options.loadaddr.s;
          t.o:=impaddr;
          scheduler.addtask(dis_datadword,priority_data,t,0,nil);
          t.s:=options.loadaddr.s;
          t.o:=impaddr2;
          scheduler.addtask(dis_datadword,priority_data,t,0,nil);
          inc(dword(imphint),4);
          inc(impaddr,4);
          inc(impaddr2,4);
        end;
        t.s:=options.loadaddr.s;
        t.o:=impaddr;
        scheduler.addtask(dis_datadword,priority_data,t,0,nil);
        t.s:=options.loadaddr.s;
        t.o:=impaddr2;
        scheduler.addtask(dis_datadword,priority_data,t,0,nil);
        inc(j);
      end;
      t.s:=options.loadaddr.s;
      t.o:=peh.image_base+peh.importtable_rva+j*sizeof(tpeimportdirentry);
      scheduler.addtask(dis_datadword,priority_data,t,0,nil);
      scheduler.addtask(dis_datadword,priority_data,t,4,nil);
      scheduler.addtask(dis_datadword,priority_data,t,8,nil);
      scheduler.addtask(dis_datadword,priority_data,t,12,nil);
      scheduler.addtask(dis_datadword,priority_data,t,16,nil);
    end;
    if pdata^[i].rva=peh.tls_rva then peobjdone:=TRUE; // tls info
    if (pdata^[i].rva=peh.resourcetable_rva) or // resource info
      ((peh.resourcetable_rva>pdata^[i].rva)and
       (peh.resourcetable_rva<pdata^[i].rva+pdata^[i].phys_size))
    then begin
      // RESOURCE_DATA;
      if (pdata^[i].phys_size<>0)and(options.loadresources) then begin
        resdir:=@fbuff[pdata^[i].phys_offset
          +peh.resourcetable_rva-pdata^[i].rva];
        pdatarva:=peh.resourcetable_rva;  // bugfix  build 14
        rawdata:=@resdir^;
        numitems:=resdir.numnames+resdir.numids;
        rentry:=@resdir^; inc(dword(rentry),sizeof(tperestable));
        while numitems<>0 do begin
          if rentry.id and $80000000<>0 then begin
            impname:=rawdata+(rentry.id and $7fffffff);
            clen:=pw(@impname[0])^;
            WideCharToMultiByte(CP_ACP,0,@impname[2],clen,impbuff,100,nil,nil);
            impbuff[clen]:=#0;
          end else begin case rentry.id of
           1:      strcopy(impbuff,'Cursor');
           2:      strcopy(impbuff,'Bitmap');
           3:      strcopy(impbuff,'Icon');
           4:      strcopy(impbuff,'Menu');
           5:      strcopy(impbuff,'Dialog');
           6:      strcopy(impbuff,'String Table');
           7:      strcopy(impbuff,'Font Directory');
           8:      strcopy(impbuff,'Font');
           9:      strcopy(impbuff,'Accelerators');
           10:     strcopy(impbuff,'Unformatted Resource Data');
           11:     strcopy(impbuff,'Message Table');
           12:     strcopy(impbuff,'Group Cursor');
           14:     strcopy(impbuff,'Group Icon');
           16:     strcopy(impbuff,'Version Information');
           $2002:  strcopy(impbuff,'New Bitmap');
           $2004:  strcopy(impbuff,'New Menu');
           $2005:  strcopy(impbuff,'New Dialog');
           else
                   strcopy(impbuff,'User Defined Id:');
                   numtmp:=rentry.id and $7fffffff;
                   fmtstr(inum,'%02x',[numtmp]);
                   strpcopy(impbuff+strlen(impbuff),inum);
          end;
          end;
          if rentry.offset and $80000000<>0 then begin
            subdirsummary(rawdata+((rentry.offset) and $7fffffff),impbuff,peh.image_base,rentry.id);
          end else begin
            leafnodesummary(rawdata+((rentry.offset) and $7fffffff),impbuff,peh.image_base,0);
          end;
          inc(rentry);
          dec(numitems);
         end;
       end;
       if pdata^[i].rva=peh.resourcetable_rva then peobjdone:=TRUE;
       end;
       if pdata^[i].rva=peh.fixuptable_rva then begin // fixup info
         per:=@fbuff[pdata^[i].phys_offset];
         while per.rva<>0 do begin
           rdata:=@per^; inc(dword(rdata),8);
           numrelocs:=(per.len-sizeof(tperelocheader)) div 2;
           while (numrelocs<>0)and ((rdata^[0])<>0) do begin
             t.s:=options.loadaddr.s;
             t.o:=(rdata^[0] and $0fff)+per.rva+peh.image_base;
             reloc.addreloc(t,0,RELOC_NONE);
             inc(dword(rdata),2);
             dec(numrelocs);
           end;
           inc(dword(per),per.len);
         end;
         peobjdone:=TRUE;
       end;
       if pdata^[i].rva=peh.debugtable_rva then begin // debug info
         // DEBUG_DATA;
         if (pdata^[i].phys_size<>0)and(options.loaddebug) then begin
           sseg.o:=pdata^[i].rva+peh.image_base;
           dta.addseg(sseg,pdata^[i].phys_size,@fbuff[pdata^[i].phys_offset],debugdata,nil);
         end;
         peobjdone:=TRUE;
       end;
       if (pdata^[i].obj_flags and $40<>0)and(not(pdata^[i].obj_flags and $20)<>0)and(not peobjdone)
       then begin
         // INIT_DATA;
         if (pdata^[i].phys_size<>0)and(options.loaddata) then begin
           sseg.o:=pdata^[i].rva+peh.image_base;
           dta.addseg(sseg,pdata^[i].phys_size,@fbuff[pdata^[i].phys_offset],data32,nil);
         end;
         if (pdata^[i].virt_size>pdata^[i].phys_size)and options.loaddata then begin
           sseg.o:=pdata^[i].rva+peh.image_base+pdata^[i].phys_size;
           getmem(uinit,pdata^[i].virt_size-pdata^[i].phys_size);
           for j:=0 to pdata^[i].virt_size-pdata^[i].phys_size-1 do uinit[j]:=#0;
           dta.addseg(sseg,pdata^[i].virt_size-pdata^[i].phys_size,uinit,uninitdata,nil);
         end
       end else if (pdata^[i].obj_flags and $80<>0)and(not peobjdone) then begin
         // UNINIT_DATA;
         if options.loaddata then begin
           sseg.o:=pdata^[i].rva+peh.image_base;
           getmem(uinit,pdata^[i].virt_size);
           for j:=0 to pdata^[i].virt_size-1 do uinit[j]:=#0;
           dta.addseg(sseg,pdata^[i].virt_size,uinit,uninitdata,nil);
         end;
       end else if not peobjdone then begin
         // CODE_DATA;
         if pdata^[i].phys_size<>0 then begin
           sseg.o:=pdata^[i].rva+peh.image_base;
           dta.addseg(sseg,pdata^[i].phys_size,@fbuff[pdata^[i].phys_offset],code32,nil);
           dta.possibleentrycode(sseg);
         end;
       end;
    // default start addr=first seg, in the case of no entry point
    // (eg some dll files). added version 2.20
    if start_addr.s=0 then begin
      start_addr.s:=options.loadaddr.s;
      start_addr.o:=pdata^[i].rva+peh.image_base;
      dio.setcuraddr(start_addr);
    end;
  end;
  start_addr.s:=options.loadaddr.s;
  start_addr.o:=peh.entrypoint_rva+peh.image_base;
  dio.setcuraddr(start_addr);
  scheduler.addtask(dis_code,priority_definitecode,start_addr,0,nil);
  scheduler.addtask(nameloc,priority_nameloc,start_addr,0,'start');
  scheduler.addtask(windowupdate,priority_window,nlptr,0,nil);
end;

procedure tfileloader.readmzfile(fsize:dword);
var
  mzh:pmzheader;
  fs:dword;
  roffs:pchar;
  poffs:pchar;
  nrelocs,nr:word;
  ritem:pwa;
  rchange:pwa;
  rtable:pwa;
  sseg,tseg:lptr;  // current segment limits
  ip:lptr;
  saddr,taddr,ipaddr:dword;
begin
  options.loadaddr.o:=0;
  mzh:=@fbuff;
  fs:=(mzh.numpages-1)*512+mzh.numbytes;
  if fs>fsize then fs:=fsize;
  dec(fs,mzh.headersize*16);
  roffs:=fbuff+mzh.relocoffs;
  poffs:=fbuff+mzh.headersize*16;
  nrelocs:=mzh.numrelocs;
  if nrelocs<>0 then getmem(rtable,nrelocs*2);
  if nrelocs=0 then begin
    MessageBox(mainwindow,'Relocation table is empty\nThis file is probably packed'+
      #13'Borg will not be able to create the segments properly','Borg Warning',MB_OK or MB_ICONEXCLAMATION);
  end;
  while nrelocs<>0 do begin
    ritem:=@roffs[(mzh.numrelocs-nrelocs)*4];
    if ((ritem^[0]) or (ritem^[1]))<>0 then begin
      rchange:=@poffs[ritem^[0]+ritem^[1]*16];
      inc(rchange^[0],options.loadaddr.s);
      rtable^[mzh.numrelocs-nrelocs]:=rchange^[0];
    end else rtable^[mzh.numrelocs-nrelocs]:=options.loadaddr.s;
    dec(nrelocs);
  end;
//  qsort(rtable,mzh.numrelocs,2,mzcmp);
  sseg:=options.loadaddr;
  options.dseg:=options.loadaddr.s;   // need to look for better value for dseg later
  ip:=options.loadaddr;
  ipaddr:=((mzh.csip)+((mzh.csip div $10000)+options.loadaddr.s)*16+options.loadaddr.o) and $fffff;
  for nrelocs:=0 to mzh.numrelocs-1 do begin
    if rtable^[nrelocs]<>sseg.s then begin
      tseg.s:=rtable^[nrelocs]; //???
      tseg.o:=0;
      saddr:=sseg.s*16+sseg.o;
      taddr:=tseg.s*16+tseg.o;
      if (ipaddr>=saddr)and(ipaddr<taddr) then begin
        ip.s:=sseg.s;
        ip.o:=ipaddr-ip.s*16; //???
      end;
      if (saddr<taddr)and(sseg.s>=options.loadaddr.s) then begin
        dta.addseg(sseg,taddr-saddr,fbuff+mzh.headersize*16
         +(sseg.s-options.loadaddr.s)*16,code16,nil);
        dta.possibleentrycode(sseg);
        // go through the reloc items, check if any lie in the seg
        // if they do - add to reloc entries.
        for nr:=0 to mzh.numrelocs-1 do begin
          ritem:=@roffs[(mzh.numrelocs-nr)*4];
          if ((ritem^[0]) or (ritem^[1]))<>0 then begin
            rchange:=@poffs[ritem^[0]+ritem^[1]*16];
            if (dword(rchange^[0])>=
              dword(fbuff[mzh.headersize*16+(sseg.s-options.loadaddr.s)*16]))
              and(byte(rchange^[0])<dword(fbuff[mzh.headersize*16+(sseg.s-options.loadaddr.s)*16+taddr-saddr]))
            then begin
              reloc.addreloc(sseg,byte(rchange^[0])-
              (dword(fbuff[mzh.headersize*16+(sseg.s-options.loadaddr.s)*16])),RELOC_SEG);
            end;
          end;
        end;
        sseg.s:=tseg.s;
      end;
    end;
  end;
  if (sseg.s-options.loadaddr.s)*16<fs then begin
    saddr:=sseg.s*16+sseg.o;
    if ipaddr>=saddr then begin
      ip.s:=sseg.s;
      ip.o:=ipaddr-ip.s*16; //???
    end;
    dta.addseg(sseg,fs-(sseg.s-options.loadaddr.s)*16,
    fbuff+mzh.headersize*16+(sseg.s-options.loadaddr.s)*16,code16,nil);
    for nr:=0 to mzh.numrelocs-1 do begin
      ritem:=@roffs[(mzh.numrelocs-nr)*4];
      if ((ritem^[0])or(ritem^[1]))<>0 then begin
        rchange:=@poffs[ritem^[0]+ritem^[1]*16];
        if (rchange^[0]>=byte(fbuff[mzh.headersize*16+(sseg.s-options.loadaddr.s)*16]))
          and (rchange^[0]<byte(fbuff[mzh.headersize*16+fs]))
        then reloc.addreloc(sseg,rchange^[0]-
          byte(fbuff[mzh.headersize*16+(sseg.s-options.loadaddr.s)*16]),RELOC_SEG);
      end;
    end;
    dta.possibleentrycode(sseg);
  end;
  // need to search for dseg better value.
  options.mode16:=TRUE;
  options.mode32:=FALSE;
  dio.setcuraddr(ip);
  scheduler.addtask(dis_code,priority_definitecode,ip,0,nil);
  scheduler.addtask(nameloc,priority_nameloc,ip,0,'start');
  scheduler.addtask(windowupdate,priority_window,nlptr,0,nil);
  if mzh.numrelocs<>0 then freemem(rtable);
end;

procedure tfileloader.readlefile;
begin
end;

procedure tfileloader.readnefile(offs:dword);
var
  neh:pneheader;
  nestart,importnames,modoffsets:pchar;
  nsegs:word;
  nesegt:pnesegtablearr;
  i,j,k:integer;
  sseg,iaddr,inum:lptr;
  slen,soffs:dword;
  numrelocs:word;
  stable:pwa;
  reloctable:pnesegtablerelocarr;
  iname:array[0..80] of char;
begin
  options.dseg:=options.loadaddr.s;
  sseg.s:=options.loadaddr.s;
  sseg.o:=0;
  nestart:=@fbuff[offs];
  neh:=pneheader(nestart);
  if neh.csip=0 then begin
    MessageBox(mainwindow,'No entry point to executable - assume that Executable'+
     'is a resource only\nUse a resource viewer','Borg Warning',MB_OK or MB_ICONEXCLAMATION);
    CloseHandle(efile);
    efile:=dword(INVALID_HANDLE_VALUE);
    exetype:=0;
    exit;
  end;
  nsegs:=neh.numsegs;
  getmem(stable,nsegs*2);
  nesegt:=@nestart[neh.offs_segments];
  importnames:=@nestart[neh.offs_imports];
  modoffsets :=@nestart[neh.offs_module];
  // add segments
  for i:=0 to nsegs-1 do begin
    slen:=nesegt^[i].seglength;
    if slen=0 then slen:=$10000;
    soffs:=nesegt^[i].sectoroffs;
    // added uninit data borg 2.20
    if soffs<>0 then begin
      if nesegt^[i].segflags and 1<>0 then begin
        dta.addseg(sseg,slen,@fbuff[soffs shl neh.shiftcount],data16,nil);
        options.dseg:=sseg.s;
      end else begin
        dta.addseg(sseg,slen,@fbuff[soffs shl neh.shiftcount],code16,nil);
        dta.possibleentrycode(sseg);
      end;
    end else dta.addseg(sseg,slen,nil,uninitdata,nil); // uninit data
    stable^[i]:=sseg.s;
    inc(sseg.s,word((slen+15) div 16));
    end;
    // relocate data
    // approach to imports:
    // - start with a new segment 0xffff, to be created later, size 0.
    // - for each import, if its an ordinal add it at the current addr in the import segment,
    // - and increase the size of the segment, name it = name+ordinal num
    // - otherwise name=importnames table name, check for if it is already an import
    // - and only add if necessary.
    // - finally create the segment at the end.
    iaddr.s:=$ffff;
    inum.s:=$ffff;
    iaddr.o:=0;
    for i:=0 to nsegs-1 do begin
      slen:=nesegt^[i].seglength;
      if slen=0 then slen:=$10000;
      soffs:=nesegt^[i].sectoroffs;
      if (nesegt^[i].segflags and 100<>0)and(soffs<>0) then begin
        // reloc data present
        numrelocs:=pw(@fbuff[(soffs shl neh.shiftcount)+slen])^;
        reloctable:=@fbuff[(soffs shl neh.shiftcount)+slen+2];
        for j:=0 to numrelocs-1 do begin
          case reloctable^[j].reloctype of
           0: ;    //low byte
           2:      //16bit selector
            if (reloctable^[j].relocsort=0)and(reloctable^[j].indx<$ff) then begin
              pw(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs])^:=stable^[reloctable^[j].indx-1];
            end;
           3:      //32bit pointer
            if (reloctable^[j].relocsort=0)and(reloctable^[j].indx<$ff) then begin
              pw(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs+2])^:=stable^[reloctable^[j].indx-1];
              pw(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs])^:=reloctable^[j].indexoffs;
            end else if reloctable^[j].relocsort=2 then begin // import by name
              for k:=0 to 78 do begin
                if importnames[reloctable^[j].indexoffs]=#0 then break;
                iname[k]:=importnames[reloctable^[j].indexoffs+1+k];
                iname[k+1]:=#0;
              end;
              inum.o:=import.importaddr(iname);
              if inum.o=0 then begin
                inc(iaddr.o);
                import.addname(iaddr,iname);
                inum.o:=iaddr.o;
              end;
              PW(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs+2])^:=inum.s;
              PW(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs])^:=inum.o;
            end;
           5:      //16bit offset
            if (reloctable^[j].relocsort=0)and(reloctable^[j].indx<$ff) then begin
              pw(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs])^:=reloctable^[j].indexoffs;
            end;
          11:     //48bit pointer
            if (reloctable^[j].relocsort=0)and(reloctable^[j].indx<$ff) then begin
              pw(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs+4])^:=stable^[reloctable^[j].indx-1];
              pd(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs])^:=reloctable^[j].indexoffs;
            end;
          13:     //32bit offset
            if (reloctable^[j].relocsort=0)and(reloctable^[j].indx<$ff) then begin
              pd(fbuff[(soffs shl neh.shiftcount)+reloctable^[j].segm_offs])^:=reloctable^[j].indexoffs;
            end;
         end;
       end;
    end;
  end;
  inum.o:=0;
  if iaddr.o<>0 then dta.addseg(inum,iaddr.o+1,nil,uninitdata,'Import Segment <Borg>');
  // set up disassembly
  options.loadaddr.s:=stable^[(neh.csip shr 16)-1];
  options.loadaddr.o:=neh.csip and $ffff;
  dio.setcuraddr(options.loadaddr);
  scheduler.addtask(dis_code,priority_definitecode,options.loadaddr,0,nil);
  scheduler.addtask(nameloc,priority_nameloc,options.loadaddr,0,'start');
  scheduler.addtask(windowupdate,priority_window,nlptr,0,nil);
  freemem(stable);
end;

procedure tfileloader.reados2file;
begin
end;

//marks data as a binary file.
// sets up entry point and
// data objects (jusr one here)
procedure tfileloader.readbinfile(fsize:dword);
begin
  options.mode32:= not options.mode16;
  options.dseg:=options.loadaddr.s;
  if options.mode32 then dta.addseg(options.loadaddr,fsize,fbuff,code32,nil)
  else dta.addseg(options.loadaddr,fsize,fbuff,code16,nil);
  dta.possibleentrycode(options.loadaddr);
  dio.setcuraddr(options.loadaddr);
  scheduler.addtask(dis_code,priority_definitecode,options.loadaddr,0,nil);
  scheduler.addtask(nameloc,priority_nameloc,options.loadaddr,0,'start');
  scheduler.addtask(windowupdate,priority_window,nlptr,0,nil);
end;

procedure tfileloader.subdirsummary(data,impname:pchar; image_base:dword; rtype:dword);
var
  resdir:pperestable;
  rentry:pperestableentry;
  nam:pchar;
  nbuff:array[0..100] of char;
  nbuff2:array[0..100] of char;
  inum:string;
  clen:integer;
  numtmp:dword;
  numitems:dword;
begin
  resdir:=@data^;
  numitems:=resdir.numnames+resdir.numids;
  rentry:=@resdir^; inc(dword(rentry),sizeof(tperestable));
  while numitems<>0 do begin
    if rentry.id and $80000000<>0 then begin
      nam:=rawdata+((rentry.id)and $7fffffff);
      clen:=pw(@nam[0])^;
      WideCharToMultiByte(CP_ACP,0,@nam[2],clen,nbuff,100,nil,nil);
      nbuff[clen]:=#0;
      if impname<>nil then begin
        strcopy(nbuff2,nbuff);
        strcopy(nbuff,impname);
        strcat(nbuff,' ');
        strcat(nbuff,nbuff2);
      end;
    end else begin
      numtmp:=rentry.id and $7fffffff;
      fmtstr(inum,'%02x',[numtmp]);
      strcopy(nbuff,impname);
      strcat(nbuff,' Id:');
      strpcopy(nbuff+strlen(nbuff),inum);
    end;
    if (rentry.offset and $80000000<>0)
    then leaf2summary(rawdata+((rentry.offset) and $7fffffff),nbuff,image_base,rtype)
    else leafnodesummary(rawdata+((rentry.offset) and $7fffffff),nbuff,image_base,rtype);
    inc(rentry);
    dec(numitems);
  end;
end;

procedure tfileloader.leaf2summary(data,nam:pchar; image_base:dword; rtype:dword);
var
  resdir:pperestable;
  rentry:pperestableentry;
  numitems:dword;
begin
  resdir:=@data^;
  numitems:=resdir.numnames+resdir.numids;
  rentry:=@resdir^; inc(dword(rentry),sizeof(tperestable));
  while numitems<>0 do begin
    leafnodesummary(rawdata+((rentry.offset) and $7fffffff),nam,image_base,rtype);
    inc(rentry);
    dec(numitems);
  end;
end;

procedure tfileloader.leafnodesummary(data,resname:pchar; image_base:dword; rtype:dword);
var
  leaf:ppeleafnode;
  t:lptr;
  rname:pchar;
begin
  leaf:=@data^;
  t.s:=options.loadaddr.s;
  t.o:=leaf.datarva+image_base;
  // bugfix to third arg - build 14
  dta.addseg(t,leaf.size,@rawdata[leaf.datarva-pdatarva],resourcedata,resname);
  case rtype of
   5: // dialog
    begin
      getmem(rname,strlen(resname)+1);
      strcopy(rname,resname);
      scheduler.addtask(dis_dialog,priority_data,t,0,rname);
    end;
   6: // stringtable
    begin
      getmem(rname,strlen(resname)+1);
      strcopy(rname,resname);
      scheduler.addtask(dis_stringtable,priority_data,t,0,rname);
    end;
  end;
end;

// added Borg v2.19
// returns file offset of a loc, or 0 if cant find.
function tfileloader.fileoffset(loc:lptr):dword;
var ds:pdsegitem;
begin
  result:=0;
  ds:=dta.findseg(loc);
  if ds=nil then exit;
  result:=(loc.o-ds.addr.o)+(ds.data-fbuff);
end;

// file patcher function added v2.19
procedure tfileloader.patchfile(file_offs,num:dword; dat:pchar);
var written:long;
begin
  SetFilePointer(efile,file_offs,nil,FILE_BEGIN);
  WriteFile(efile,dat,num,written,nil);
end;

procedure tfileloader.reloadfile(file_offs,num:dword; dat:pchar);
var rd:long;
begin
  SetFilePointer(efile,file_offs,nil,FILE_BEGIN);
  ReadFile(efile,dat,num,rd,nil);
end;

initialization
  floader:=tfileloader.create;
finalization
  floader.free;
end.

