#pragma option w32c
#pragma option wsi
#pragma option de-
#parsecommandline TRUE
#codesize

#define _ADVAPI_        TRUE
?define	_WINBASE_	TRUE
?define	_COMMCTRL_	TRUE
?define	_WINGDI_	TRUE
?define	_COMMDLG_	TRUE

#define	SafeLen	8192
#define VERSION "1.0"

#include "windows.h--"
#include "epack.rc"
#includepath "c:\c--\open_lib"
#include <string.h>
#include "msvcrt.h--"

dword consolemode;
dword retcode;
dword hWnd,hStatus;
dword hBar1,hBar2;
dword hS1,hS2,hText3,hText4;
dword F2,xLen;
char cFile[512];
char nFile[512];

void MessageErr(dword mess)
{
	IF(consolemode){
		printf("Error. %s\n",mess);
		retcode=1;
	}
	ELSE MessageBoxA(hWnd,mess,"Error",0);
	DeleteFileA(#nFile);
}

?include	"ctype.h--";
?include	"config.h--";
?include	"protect.h--";

dword BarMax,BarPos;
char classTitle="EPack";
dword temp;
byte help=
"\nUsage: EPACK [options] filename\n"
"\toptions: -0 - compression metod LZSS\n"
"\t\t -1 - compression metod LZSS with RLE\n"
"\t\t -b[-] - create backup file\n"
"\t\t -d[-] - create new DOS stub\n";

int main()
struct WNDCLASSEX WndClassEx;
struct MSG msgStruc;
{
	strcpy(#cFile,PARAMSTR(0));
	IF(strrchr(#cFile,'\\')!=NULL){
		DSBYTE[EAX+1]=0;
	}
	ELSE cFile=0;
	InitCfg();
	ReadCfg();
	retcode=consolemode=0;
	if(@PARAMCOUNT()<2){
		InitCommonControls();
		WndClassEx.cbSize=sizeof(WndClassEx);
		WndClassEx.style=CS_HREDRAW|CS_VREDRAW;
		WndClassEx.lpfnWndProc=#WndProc;
		WndClassEx.cbWndExtra=WndClassEx.cbClsExtra=WndClassEx.hIconSm=0;
		WndClassEx.hInstance=hThisInst;
		WndClassEx.hIcon=LoadIconA(hThisInst,IDI_ICON1);
		WndClassEx.hCursor=LoadCursorA(0,IDC_ARROW);
		WndClassEx.hbrBackground=COLOR_WINDOW;
		WndClassEx.lpszMenuName=IDM_MENU1;
		WndClassEx.lpszClassName=#classTitle;
		RegisterClassExA(#WndClassEx);
		LoadMenuA(hThisInst,IDM_MENU1);
		hWnd=CreateWindowExA(0,#classTitle,#classTitle,
			WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,0,0,420,180,0,EAX,hThisInst,0);
		hStatus = CreateStatusWindowA(WS_CHILD | WS_VISIBLE,"Ready.",hWnd,0);
		hBar1   = CreateWindowExA(0,"msctls_progress32",0,
		   WS_CHILD|WS_BORDER|WS_VISIBLE,10,20,395,20,hWnd,0,hThisInst,0);
		hBar2   = CreateWindowExA(0,"msctls_progress32",0,
		   WS_CHILD|WS_BORDER|WS_VISIBLE,10,80,395,20,hWnd,0,hThisInst,0);
		EBX=CreateWindowExA(0,"STATIC",0,WS_CHILD|WS_VISIBLE,10,0,200,20,hWnd,0,hThisInst,0);
		SetWindowTextA(EBX,"Compression progress");
		EBX=CreateWindowExA(0,"STATIC",0,WS_CHILD|WS_VISIBLE,10,60,200,20,hWnd,0,hThisInst,0);
		SetWindowTextA(EBX,"Compression ratio");
		hS1  = CreateWindowExA(0,"STATIC",0,
		   WS_CHILD|WS_VISIBLE,210,0,50,20,hWnd,0,hThisInst,0);
		SetWindowTextA(hS1,"0%");
		hS2  = CreateWindowExA(0,"STATIC",0,
		   WS_CHILD|WS_VISIBLE,210,60,50,20,hWnd,0,hThisInst,0);
		SetWindowTextA(hS2,"0%");
		hText3  = CreateWindowExA(0,"STATIC",0,
		   WS_CHILD|WS_VISIBLE,280,0,100,20,hWnd,0,hThisInst,0);
		SetWindowTextA(hText3,"(0)");
		hText4  = CreateWindowExA(0,"STATIC",0,
		   WS_CHILD|WS_VISIBLE,280,60,100,20,hWnd,0,hThisInst,0);
		SetWindowTextA(hText4,"(0)");
		ShowWindow(hWnd,SW_SHOW);
		UpdateWindow(hWnd);
		WHILE(GetMessageA(#msgStruc,0,0,0)){
			TranslateMessage(#msgStruc);
			DispatchMessageA(#msgStruc);
		}
	}
	else{
		F2=EAX;
		printf("\n\tEPack v%s %s\nPacker for executables PE-files\nCopyright (C) Deviator//HAZARD 2000, Michael Sheker 2003\n",VERSION,__DATE__);
		consolemode=TRUE;
		for(temp=1;temp<F2;temp++){
			EAX=PARAMSTR(temp);
			IF(DSBYTE[EAX]=='?')||(DSWORD[EAX]=='?/'){
				printf(#help);
				return;
			}
			IF(DSBYTE[EAX]!='-')BREAK;
			DL=DSBYTE[EAX+2];
			SWITCH(DSBYTE[EAX+1]){
				CASE '0':
					cfgpack.CompressionType=0;
					BREAK;
				CASE '1':
					cfgpack.CompressionType=1;
					BREAK;
				CASE 'b':
				CASE 'B':
					EAX=0;
					IF(DL=='-')EAX++;
					cfgpack.KeepBackup=EAX;
					BREAK;
				CASE 'd':
				CASE 'D':
					EAX=1;
					IF(DL=='-')EAX--;
					cfgpack.DosStub=EAX;
					BREAK;
				default:
					printf(#help);
					return;
			}
		}
		$push EAX
		IF(temp+1!=F2){
			$pop EAX
			printf(#help);
			return;
		}
		$pop EAX
		strcpy(#cFile,EAX);
		ProtectFile();
	}
	SaveCfg();
	EAX=retcode;
}

dword	WndProc(dword hwnd,msg,wPar,lPar)
{
struct OPENFILENAME fname;
	switch(msg){
		CASE WM_DESTROY:
			PostQuitMessage(0);
			EAX=0;
			break;
		CASE WM_COMMAND:
			switch (wPar){
				CASE CM_POPUPITEM3:     // About
					DialogBoxParamA(hThisInst,IDD_DIALOG3,hWnd,#AboutProc,0);
					break;
				CASE CM_POPUPITEM2:
					DialogBoxParamA(hThisInst,IDD_DIALOG2,hWnd,#CompOptions,0);
					break;
				CASE CM_FILEITEM2:
					PostQuitMessage(0);
					EAX = 0;
					break;
				CASE  101:               // Compress
					cFile[0] = 0;
					fname.lStructSize	=	sizeof(fname);
					fname.hwndOwner		=	hWnd;
					fname.hInstance		=	hThisInst;
					fname.lpstrFilter="Executables (*.exe,*.dll)\x00*.dll;*.exe\x00";
					fname.lpstrFile		=	#cFile;
					fname.nMaxFile		=	fname.nMaxFileTitle	=	260;
					fname.lpstrTitle="Select file to compress...";
					fname.Flags		=	OFN_EXPLORER | OFN_FILEMUSTEXIST|OFN_NONETWORKBUTTON|OFN_PATHMUSTEXIST;
					fname.lpstrCustomFilter	=	fname.nMaxCustFilter	=
					fname.lpstrFileTitle	=	fname.lpstrInitialDir	=
					fname.nFileOffset	=	fname.nFileExtension	=	fname.lpstrDefExt	=
					fname.lCustData		=	fname.lpfnHook		=	fname.lpTemplateName	=	0;
					fname.nFilterIndex	=	1;
					IF (!GetOpenFileNameA(#fname)) RETURN();
					$pushad
					ProtectFile();
					$popad
					break;
			}
			BREAK;
		default:
			DefWindowProcA(hwnd,msg,wPar,lPar);
	}
}

void ProtectFile()
{
dword dSrc,dDst;
	strcpy(#nFile,#cFile);
	strcat(#nFile,".bak");
	if(MoveFileA(#cFile,#nFile) != 0){
		EBX= CreateFileA(#nFile,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
		xLen = SetFilePointer(EBX,0,0,2);
		IF(EAX<=2048){
			MessageErr("Given file very small for compression");
			CloseHandle(EBX);
			return;
		}
		dSrc = GlobalAlloc(GMEM_FIXED,xLen);
		dDst = GlobalAlloc(GMEM_FIXED,xLen+SafeLen);
		IF(!consolemode){
			SendMessageA(hBar1,PBM_SETPOS,0,0);
			SendMessageA(hBar2,PBM_SETPOS,0,0);
			EAX = xLen/Step << 16;
			$push EAX
			SendMessageA(hBar1,PBM_SETRANGE,0,EAX);
			SendMessageA(hBar1,PBM_SETSTEP,1,0);
		}
		sNum = 0;
		IF (xLen > 0xFFFF){
			EAX = xLen;
			WHILE (EAX > 0xFFFF){
				sNum++;
				EAX>>=1;
			}
		}
		SetFilePointer(EBX,0,0,0);
		ReadFile(EBX,dSrc,xLen,#temp,0);
		CloseHandle(EBX);
		F2=Protect(dSrc,dDst,xLen);
		GlobalFree(dSrc);
		IF(!consolemode)$pop EAX
		if (F2 != 0){
			IF(!consolemode)SendMessageA(hBar1,PBM_SETPOS,EAX,0);
			EBX=CreateFileA(#cFile,GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,0,0);
			WriteFile(EBX,dDst,F2,#temp,0);
			CloseHandle(EBX);
			IF(!consolemode){
				EAX   = xLen;
				ECX   = sNum;
				EAX >>= CL;
				EAX <<= 16;
				BarMax = EAX;
				SendMessageA(hBar2,PBM_SETRANGE,0,EAX);
				EAX   = F2;
				ECX   = sNum;
				EAX >>= CL;
				BarPos = EAX;
				SendMessageA(hBar2,PBM_SETPOS,EAX,0);
			}
			ELSE{
				printf("100%%\nCompression done\nInput size  %d\nOutput size %d\nRatio       %d%%\n",xLen,F2,F2*100/xLen);
			}
			GlobalFree(dDst);
			IF(!consolemode)DialogBoxParamA(hThisInst,IDD_DIALOG4,hWnd,#CompDone,0);
			IF (cfgpack.KeepBackup == 0) DeleteFileA(#nFile);
		}
		ELSE{
			MessageErr("Compression Failed");
			GlobalFree(dDst);
			MoveFileA(#nFile,#cFile);
		}
		if(!consolemode){
			SendMessageA(hBar1,PBM_SETPOS,0,0);
			SendMessageA(hBar2,PBM_SETPOS,0,0);
			SetWindowTextA(hS1,"0%");
			SetWindowTextA(hS2,"0%");
			SetWindowTextA(hText3,"(0)");
			SetWindowTextA(hText4,"(0)");
			SendMessageA(hStatus,SB_SETTEXT,0x00FF0000,"Ready.");
		}
	}
	ELSE MessageErr("Cannot create backup file");
}

dword AboutProc(dword hdlg,msg,wPar,lPar)
{
	EAX = msg;
	SWITCH (AX){
		CASE WM_CLOSE:
		CASE WM_COMMAND:
			EndDialog(hdlg,0);
			BREAK;
	}
	EAX = 0;
}

dword	CompOptions(dword hdlg,msg,wPar,lPar)
{
dword	cType;
	EAX = msg;
	switch (AX){
		case WM_INITDIALOG:
			$pushad
			cType = cfgpack.CompressionType;
			FOR(EBX = 0; EBX<cStyles; EBX++)SendDlgItemMessageA(hdlg,IDC_COMBOBOX1,CB_ADDSTRING,0,cName[EBX*4]);
			EBX=cfgpack.CompressionType*12;
			SetDlgItemTextA(hdlg,IDC_STATICTEXT3,cDesc[EBX]);
			SetDlgItemTextA(hdlg,IDC_STATICTEXT4,cDesc[EBX+4]);
			SetDlgItemTextA(hdlg,IDC_STATICTEXT5,cDesc[EBX+8]);
			SendDlgItemMessageA(hdlg,IDC_COMBOBOX1,CB_SETCURSEL,cfgpack.CompressionType,0);
			IF (cfgpack.DosStub != 0) CheckDlgButton(hdlg,IDC_CHECKBOX1,BST_CHECKED);
			IF (cfgpack.KeepBackup != 0) CheckDlgButton(hdlg,IDC_CHECKBOX5,BST_CHECKED);
			$popad
			break;
		case WM_COMMAND:
			EAX = wPar;
			switch (AX){
				CASE IDC_BUTTON4:
					IF(IsDlgButtonChecked(hdlg,IDC_CHECKBOX1) == BST_CHECKED) EAX = 1;
					ELSE EAX = 0;
					cfgpack.DosStub=EAX;
					IF(IsDlgButtonChecked(hdlg,IDC_CHECKBOX5) == BST_CHECKED) EAX = 1;
					ELSE EAX = 0;
					cfgpack.KeepBackup =EAX;
					EndDialog(hdlg,0);
					BREAK;
				CASE IDC_BUTTON1:
					cfgpack.CompressionType = cType;
					EndDialog(hdlg,0);
					BREAK;
				CASE IDC_COMBOBOX1:
					EAX = wPar;
					EAX >>= 16;
					IF (AX == CBN_SELCHANGE){
						EBX = SendDlgItemMessageA(hdlg,IDC_COMBOBOX1,CB_GETCURSEL,0,0);
						cfgpack.CompressionType = EBX;
						EBX=EBX*12;
						SetDlgItemTextA(hdlg,IDC_STATICTEXT3,cDesc[EBX]);
						SetDlgItemTextA(hdlg,IDC_STATICTEXT4,cDesc[EBX+4]);
						SetDlgItemTextA(hdlg,IDC_STATICTEXT5,cDesc[EBX+8]);
					}
					BREAK;
			}
	}
	EAX = 0;
}

dword CompDone(dword hdlg,msg,wPar,lPar)
{
struct STARTUPINFO psi;
struct PROCESS_INFORMATION pi;
	EAX = msg;
	switch (AX){
		case WM_INITDIALOG:
			$pushad
			SetDlgItemInt(hdlg,IDC_STATICTEXT2,xLen,0);
			SetDlgItemInt(hdlg,IDC_STATICTEXT3,F2,0);
			EAX = F2*100/xLen;
			$push EAX
			SetDlgItemInt(hdlg,IDC_STATICTEXT7,EAX,0);
			$pop  EAX
			ToDec(EAX,#DBuff);
			SetWindowTextA(hS2,#DBuff);
			SetWindowTextA(hS1,"100%");
			ToDecNum(xLen,#DBuff);
			SetWindowTextA(hText3,#DBuff);
			ToDecNum(F2,#DBuff);
			SetWindowTextA(hText4,#DBuff);
			SendDlgItemMessageA(hdlg,IDC_PROGRESSBAR1,PBM_SETRANGE,0,BarMax);
			SendDlgItemMessageA(hdlg,IDC_PROGRESSBAR1,PBM_SETPOS,BarPos,0);
			$popad
			break;
		case WM_CLOSE:
			EndDialog(hdlg,0);
			BREAK;
		case WM_COMMAND:
			SWITCH (wPar){
				CASE IDC_BUTTON3:
					EndDialog(hdlg,0);
					BREAK;
				CASE IDC_BUTTON6:
					DeleteFileA(#cFile);
					MoveFileA(#nFile,#cFile);
					EndDialog(hdlg,0);
					BREAK;
				CASE IDC_BUTTON7:
					EDI = #psi;
					ECX = sizeof(psi);
					EAX = 0;
					$rep $stosb
					EDI = #pi;
					ECX = sizeof(pi);
					$rep $stosb
					CreateProcessA(#cFile,0,0,0,0,NORMAL_PRIORITY_CLASS,0,0,#psi,#pi);
					BREAK;
			}
	}
	EAX = 0;
}
