//              dasm.cpp
//
//
//
//         Borg Disassembler v1.13
//	  	by Cronos
//
//

#include <windows.h>
#include <ctl3d.h>
#include <commctrl.h>

#include "menuids.rh"
#include "pefiles.h"
#include "textout.h"
#include "disasm.h"
#include "xref.h"
#include "imports.h"
#include "exports.h"
#include "resource.h"
#include "comments.h"
#include "analyse.h"
#include "reloc.h"
#include "dasm.h"

CRITICAL_SECTION cs;
pefile pe_exe;
xref xr;
disasm disassemble;
imp imports;
exp exports;
res resources;
reloc relocs;
comments dis_comments;
analysis analyse;
BOOL file_loaded;
BOOL processing;
RECT mainwndsize;
HWND ProgressBar;
BOOL ProgBar;
BOOL ProgBarCanGo;
BOOL KillThread;
BOOL comfile;
BOOL newexe,dosexe,leexe,os2exe,w3exe,szexe;
BOOL loaddata;
BOOL analysecodeflow;

LRESULT CALLBACK dasm(HWND,UINT,WPARAM,LPARAM);
BOOL FAR PASCAL habox(HWND hdwnd,UINT message,WPARAM wParam,LPARAM lParam);
BOOL FAR PASCAL optionsbox(HWND hdwnd,UINT message,WPARAM wParam,LPARAM lParam);
BOOL newfile(HWND hwnd);
void Thread(PVOID pvoid);
BOOL savefile(HWND hwnd);

OPENFILENAME ofn;
char szDirName[MAX_PATH];
char szFile[260];
char szFilter[260];
char szFileTitle[260];
HANDLE hInst;
DWORD ThreadId;
int cxChar,cyChar;

char szWinName[]="Dasm";
char fname[]="Borg Disassembler";

int WINAPI WinMain(HINSTANCE hThisInst,HINSTANCE hPrevInst,LPSTR lpszArgs,int nWinMode)
{ HWND hwnd;
  MSG msg;
  WNDCLASSEX wcl;
  int cx,cy;

  InitCommonControls();
  Ctl3dRegister(hThisInst);
  Ctl3dAutoSubclass(hThisInst);

  cx=GetSystemMetrics(SM_CXFULLSCREEN);
  cy=GetSystemMetrics(SM_CYFULLSCREEN);
  /* Define window class */
  wcl.hInstance=hThisInst;
  wcl.lpszClassName=szWinName;
  wcl.lpfnWndProc=dasm;
  wcl.style=CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;

  wcl.cbSize=sizeof(WNDCLASSEX);

  wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  wcl.hIconSm=LoadIcon(NULL,IDI_WINLOGO);

  wcl.hCursor=LoadCursor(NULL,IDC_ARROW);
  wcl.lpszMenuName=MAKEINTRESOURCE(main_menu);

  wcl.cbClsExtra=0;
  wcl.cbWndExtra=0;

  wcl.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH);

  hInst=hThisInst;

  /* Register window class */
  if(!RegisterClassEx(&wcl))return 0;

  /* Create window */
  hwnd=CreateWindow(szWinName,"Borg Disassembler v1.13",WS_OVERLAPPEDWINDOW,
			 cx/2-320,cy/2-230,640,480,
			 HWND_DESKTOP,NULL,hThisInst,NULL);

  mainwndsize.top=0;
  mainwndsize.bottom=cy-1;
  mainwndsize.left=0;
  mainwndsize.right=cx-1;

  /* Display window */
  ShowWindow(hwnd,nWinMode);
  UpdateWindow(hwnd);

  /* Message Loop */
  while(GetMessage(&msg,NULL,0,0))
  { TranslateMessage(&msg);
	 DispatchMessage(&msg);
  }

  Ctl3dUnregister(hThisInst);
  return msg.wParam;
}

LRESULT CALLBACK dasm(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{ static long vMult;
  int iVScrollInc,iHScrollInc;
  HDC hdc;
  TEXTMETRIC tm;
  RECT scrollarea;
  switch(message)
  { case WM_COMMAND:
		switch(LOWORD(wParam))
		{ case file_exit:
			 PostQuitMessage(0);
			 break;
		  case file_save:
			 if(processing)MessageBox(hwnd,"Processing Not Finished yet",fname,MB_OK);
			 else savefile(hwnd);
			 break;
		  case file_open:
			 newfile(hwnd);
			 if(ProgBar)
			 { ProgressBar=CreateWindow(PROGRESS_CLASS,NULL,CCS_TOP|WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER,
				 0,0,mainwndsize.right,cyChar,hwnd,(HMENU)1,hInst,0);
				Progress_SetRange(ProgressBar,0,1000);
			 }
			 break;
		  case options_set:
			 if(file_loaded)MessageBox(hwnd,"Can't change options after loading file",fname,MB_OK);
			 else DialogBox(hInst,MAKEINTRESOURCE(OPTIONS_DIALOG),hwnd,(DLGPROC)optionsbox);
			 break;
		  case help_about:
			 DialogBox(hInst,MAKEINTRESOURCE(D_help_about),hwnd,(DLGPROC)habox);
			 break;
		  default:
			 return DefWindowProc(hwnd,message,wParam,lParam);
		}
		break;
	 case WM_PAINT:
		if(addedlines==TRUE)
		{ if(!vMult)vMult=1;
		  while(((lastline-mainwndsize.bottom/cyChar)/vMult)>65535L)vMult*=2;
		  SetScrollRange(hwnd,SB_VERT,0,max(0L,(lastline-mainwndsize.bottom/cyChar)/vMult),FALSE);
		  SetScrollPos(hwnd,SB_VERT,min(firstline/vMult,(lastline-1)/vMult),TRUE);
		}
		addedlines=FALSE;
		if(((!processing)&&(ProgBar))||(ProgBarCanGo))
		{ DestroyWindow(ProgressBar);
		  InvalidateRect(hwnd,&mainwndsize,TRUE);
		  ProgBar=FALSE;
		}
		DoPaint(hwnd,cxChar,cyChar);
		break;
	 case WM_DESTROY:
      KillThread=TRUE;
		while(processing)
		{ Sleep(10000);
		  if(processing)
			 MessageBox(hwnd,"Waiting For Processing to end","Borg Disassembler ShutDown Alert",MB_OK);
		}
		DeleteBuff();
		DeleteCriticalSection(&cs);
		PostQuitMessage(0);
		break;
	 case WM_SIZE:
		mainwndsize.top=0;
		mainwndsize.left=0;
		mainwndsize.right=LOWORD(lParam);
		mainwndsize.bottom=HIWORD(lParam);
		if(!vMult)vMult=1;
		while(((lastline-mainwndsize.bottom/cyChar)/vMult)>65535L)vMult*=2;
		SetScrollRange(hwnd,SB_VERT,0,max(0L,(lastline-mainwndsize.bottom/cyChar)/vMult),FALSE);
		SetScrollRange(hwnd,SB_HORZ,0,max(0L,MAXLINELEN-mainwndsize.right/cxChar),FALSE);
		if((lastline-firstline)<mainwndsize.bottom/cyChar)
		  firstline=max(0L,lastline-mainwndsize.bottom/cyChar);
		SetScrollPos(hwnd,SB_VERT,min(firstline/vMult,(lastline-1)/vMult),TRUE);
		if((MAXLINELEN-firstchar)<mainwndsize.right/cxChar)
		  firstchar=max(0L,MAXLINELEN-mainwndsize.right/cxChar);
		SetScrollPos(hwnd,SB_HORZ,max(0L,min((long)firstchar,MAXLINELEN-mainwndsize.right/cxChar)),TRUE);
		if(ProgBar)MoveWindow(ProgressBar,0,0,mainwndsize.right,cyChar,TRUE);
		break;
	 case WM_VSCROLL:
		switch(LOWORD(wParam))
		{ case SB_TOP:
			 iVScrollInc=-firstline;
			 break;
		  case SB_BOTTOM:
			 iVScrollInc=lastline-firstline-1;
			 break;
		  case SB_LINEUP:
			 iVScrollInc=-1;
			 break;
		  case SB_LINEDOWN:
			 iVScrollInc=1;
			 break;
		  case SB_PAGEUP:
			 iVScrollInc=min(-1L,-mainwndsize.bottom/cyChar);
			 break;
		  case SB_PAGEDOWN:
			 iVScrollInc=max(1L,mainwndsize.bottom/cyChar);
			 break;
		  case SB_THUMBTRACK:
			 iVScrollInc=((long)HIWORD(wParam))*vMult-firstline;
			 break;
		  default:
			 iVScrollInc=0;
		}
		iVScrollInc=max(-firstline,iVScrollInc);
		iVScrollInc=min((long)iVScrollInc,lastline-mainwndsize.bottom/cyChar-firstline);
		if(iVScrollInc)
		{ firstline+=iVScrollInc;
		  scrollarea.left=0;
		  scrollarea.right=mainwndsize.right;
		  scrollarea.top=ProgBar ? cyChar:0;
		  scrollarea.bottom=mainwndsize.bottom;
		  ScrollWindow(hwnd,0,-cyChar*iVScrollInc,&scrollarea,&scrollarea);
		  SetScrollPos(hwnd,SB_VERT,firstline/vMult,TRUE);
		  UpdateWindow(hwnd);
		}
		break;
	 case WM_HSCROLL:
		switch(LOWORD(wParam))
		{ case SB_LINEUP:
			 iHScrollInc=-1;
			 break;
		  case SB_LINEDOWN:
			 iHScrollInc=1;
			 break;
		  case SB_PAGEUP:
			 iHScrollInc=-8;
			 break;
		  case SB_PAGEDOWN:
			 iHScrollInc=8;
			 break;
		  case SB_THUMBTRACK:
			 iHScrollInc=((long)HIWORD(wParam))-firstchar;
			 break;
		  default:
			 iHScrollInc=0;
		}
		iHScrollInc=min((long)iHScrollInc,(long)(MAXLINELEN-mainwndsize.right/cxChar-firstchar));
		iHScrollInc=max(-(long)firstchar,(long)iHScrollInc);
		if(iHScrollInc)
		{ firstchar+=iHScrollInc;
		  scrollarea.left=0;
		  scrollarea.right=mainwndsize.right;
		  scrollarea.top=ProgBar ? cyChar:0;
		  scrollarea.bottom=mainwndsize.bottom;
		  ScrollWindow(hwnd,-cxChar*iHScrollInc,0,&scrollarea,&scrollarea);
		  SetScrollPos(hwnd,SB_HORZ,max(0L,min((long)firstchar,MAXLINELEN-mainwndsize.right/cxChar)),TRUE);
		  UpdateWindow(hwnd);
		}
		break;
	 case WM_SYSCOLORCHANGE:
		Ctl3dColorChange();
		break;
	 case WM_CREATE:
		hdc=GetDC(hwnd);
		SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
		GetTextMetrics(hdc,&tm);
		cxChar=tm.tmAveCharWidth;
		cyChar=tm.tmHeight+tm.tmExternalLeading;
		ReleaseDC(hwnd,hdc);
		SetScrollRange(hwnd,SB_HORZ,0,max(0L,MAXLINELEN-mainwndsize.right/cxChar),FALSE);
		SetScrollPos(hwnd,SB_HORZ,0,TRUE);
		InitializeCriticalSection(&cs);
		file_loaded=FALSE;
		processing=FALSE;
		ProgBar=FALSE;
		ProgBarCanGo=FALSE;
		KillThread=FALSE;
		vMult=1;
		loaddata=TRUE;
		analysecodeflow=TRUE;
		break;
	 case WM_KEYDOWN:
		switch(wParam)
		{ case VK_HOME:
			 SendMessage(hwnd,WM_VSCROLL,SB_TOP,0L);
			 break;
		  case VK_PRIOR:
			 SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0L);
			 break;
		  case VK_NEXT:
			 SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0L);
			 break;
		  case VK_DOWN:
			 SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0L);
			 break;
		  case VK_UP:
			 SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0L);
			 break;
		  case VK_LEFT:
			 SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0L);
			 break;
		  case VK_RIGHT:
			 SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0L);
			 break;
		}
		break;
	 default:
		return DefWindowProc(hwnd,message,wParam,lParam);
  }
  return 0;
}

BOOL FAR PASCAL habox(HWND hdwnd,UINT message,WPARAM wParam,LPARAM lParam)
{ switch(message)
  { case WM_COMMAND:
		switch(wParam)
		{ case IDC_BUTTON1:
			 EndDialog(hdwnd,NULL);
			 return TRUE;
		}
  }
  return FALSE;
}

BOOL FAR PASCAL optionsbox(HWND hdwnd,UINT message,WPARAM wParam,LPARAM lParam)
{ switch(message)
  { case WM_INITDIALOG:
		CheckDlgButton(hdwnd,IDC_LOADDATA,loaddata);
		CheckDlgButton(hdwnd,IDC_ANALYSECODEFLOW,analysecodeflow);
		return TRUE;
	 case WM_COMMAND:
		switch(wParam)
		{ case IDOK:
			 loaddata=IsDlgButtonChecked(hdwnd,IDC_LOADDATA);
			 analysecodeflow=IsDlgButtonChecked(hdwnd,IDC_ANALYSECODEFLOW);
			 EndDialog(hdwnd,NULL);
			 return TRUE;
		  case IDCANCEL:
			 EndDialog(hdwnd,NULL);
			 return TRUE;
		  case IDC_LOADDATA:
		  case IDC_ANALYSECODEFLOW:
			 return TRUE;
		}
		break;
  }
  return FALSE;
}

BOOL newfile(HWND hwnd)
{ int cbString;
  char chReplace;
  HMENU hMenu;
  GetCurrentDirectory(sizeof(szDirName),szDirName);
  szFile[0]=0;
  cbString=LoadString(hInst,IDS_FILTERSTRING,szFilter,sizeof(szFilter));
  chReplace=szFilter[cbString-1];
  for(int i=0;szFilter[i]!=0;i++)
  { if(szFilter[i]==chReplace) szFilter[i]=0;
  }

  ofn.lStructSize=sizeof(OPENFILENAME);
  ofn.hwndOwner=hwnd;
  ofn.lpstrFilter=szFilter;
  ofn.nFilterIndex=1;
  ofn.lpstrFile=szFile;
  ofn.nMaxFile=sizeof(szFile);
  ofn.lpstrFileTitle=szFileTitle;
  ofn.nMaxFileTitle=sizeof(szFileTitle);
  ofn.lpstrInitialDir=szDirName;
  ofn.lpstrCustomFilter=NULL;
  ofn.hInstance=NULL;
  ofn.lpTemplateName=NULL;
  ofn.lpstrTitle="Borg Disassembler - Select File";
  ofn.Flags=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_LONGNAMES
				|OFN_EXPLORER;
  comfile=FALSE;
  dosexe=FALSE;
  leexe=FALSE;
  os2exe=FALSE;
  w3exe=FALSE;
  szexe=FALSE;
  newexe=FALSE;
  if(GetOpenFileName(&ofn))
  { if(pe_exe.open(ofn.lpstrFile))
	 { file_loaded=TRUE;
		processing=TRUE;
		ProgBar=TRUE;
		ProgBarCanGo=FALSE;
		CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread,0,0,&ThreadId);
		hMenu=GetMenu(hwnd);
		EnableMenuItem(hMenu,file_open,MF_GRAYED);
		EnableMenuItem(hMenu,file_save,MF_ENABLED);
	 }
	 else if(newexe)
		MessageBox(hwnd,"Borg can't deal with NE (old win) files yet",fname,MB_OK);
	 else if(dosexe)
		MessageBox(hwnd,"Looks like a dos exe, Borg can't handle those yet",fname,MB_OK);
	 else if(leexe)
		MessageBox(hwnd,"Borg can't handle LE files yet",fname,MB_OK);
	 else if(os2exe)
		MessageBox(hwnd,"Borg can't handle OS2 exes yet",fname,MB_OK);
	 else if(w3exe)
		MessageBox(hwnd,"Borg can't handle the old w3 win386.exe files yet",fname,MB_OK);
	 else if(szexe)
		MessageBox(hwnd,"File is sz compressed file, use expand first",fname,MB_OK);
	 else
		MessageBox(hwnd,"File open failed - not a PE file ?",fname,MB_OK);
  }
  return 0;
}

void Thread(PVOID pvoid)
{ pe_exe.peinfo();
  if(!comfile)
  { imports.summary();
	 exports.summary();
	 resources.summary();
  }
  relocs.buildrelocdata();
  InvalidateRect(hInst,&mainwndsize,TRUE);
  disassemble.decode();
  if((!comfile)&&(analysecodeflow))
  { analyse.imported();
	 analyse.codeflow();
  }
  analyse.offsets();
  ProgBarCanGo=TRUE;
  disassemble.dumpasm();
  InvalidateRect(hInst,&mainwndsize,TRUE);
  processing=FALSE;
  ExitThread(0);
}

BOOL savefile(HWND hwnd)
{ int cbString;
  char chReplace;
  GetCurrentDirectory(sizeof(szDirName),szDirName);
  szFile[0]=0;
  cbString=LoadString(hInst,IDS_FILTERSAVE,szFilter,sizeof(szFilter));
  chReplace=szFilter[cbString-1];
  for(int i=0;szFilter[i]!=0;i++)
  { if(szFilter[i]==chReplace) szFilter[i]=0;
  }

  ofn.lStructSize=sizeof(OPENFILENAME);
  ofn.hwndOwner=hwnd;
  ofn.lpstrFilter=szFilter;
  ofn.nFilterIndex=1;
  ofn.lpstrFile=szFile;
  ofn.nMaxFile=sizeof(szFile);
  ofn.lpstrFileTitle=szFileTitle;
  ofn.nMaxFileTitle=sizeof(szFileTitle);
  ofn.lpstrInitialDir=szDirName;
  ofn.lpstrCustomFilter=NULL;
  ofn.lpstrTitle="Borg Disassembler - Select File";
  ofn.Flags=OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_LONGNAMES
				|OFN_EXPLORER;

  if(GetSaveFileName(&ofn))
  { DumpToFile(hwnd,ofn.lpstrFile);
  }
  return 0;
}


