// BigFileToolDlg.cpp : implementation file
//

#include "stdafx.h"
#include "BigFileTool.h"
#include "BigFileToolDlg.h"

#include  <io.h>
#include  <stdio.h>
#include  <stdlib.h>
#include <direct.h>
#include <shlobj.h>

#include "Scripts.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include <math.h>

#define C_szBigFileName		"data.000"

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
long PTC_g_lCurrentRandom;

//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				26 mars 1999
// 
// Prototype		PTC_fn_lGetCryptKey
// Parameters		_lValue : 
// Return Type		DWORD
// 
// Description		Get the key used to crypt the file
// 
//------------------------------------------------------------------------
DWORD PTC_fn_lGetCryptKey(DWORD _lValue)
{
	DWORD lTmp;

    _lValue ^= 123459876;
    lTmp = _lValue / 127773;
    _lValue = 16807 * (_lValue - lTmp * 127773) - 2836 * lTmp;
    if (_lValue < 0) _lValue += 2147483647;

	return _lValue;
}

//------------------------------------------------------------------------
long PTC_fn_lGetRandom()
{
	long lTmp;

    PTC_g_lCurrentRandom ^= 123459876;
    lTmp = PTC_g_lCurrentRandom / 127773;
    PTC_g_lCurrentRandom = 16807 * (PTC_g_lCurrentRandom - lTmp * 127773) - 2836 * lTmp;
    if (PTC_g_lCurrentRandom < 0) PTC_g_lCurrentRandom += 2147483647;

	return PTC_g_lCurrentRandom;
}

//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				26 mars 1999
// 
// Prototype		PTC_fn_lGetProtectionKey
// Parameters		_lValue : 
// Return Type		DWORD
// 
// Description		Get the key added to the file
// 
//------------------------------------------------------------------------
DWORD PTC_fn_lGetProtectionKey(DWORD _lValue)
{
	DWORD lTmp;

    _lValue ^= 123459876;
    lTmp = _lValue / 44488;
    _lValue = 48271 * (_lValue - lTmp * 44488) - 3399 * lTmp;
    if (_lValue < 0) _lValue += 2147483647;

	return _lValue;
}

//------------------------------------------------------------------------
long PTC_fn_lGetRandomRange(long _lMin , long _lMax)
{
	return (_lMin + (PTC_fn_lGetRandom() % (_lMax - _lMin)));
}

//------------------------------------------------------------------------
DWORD fn_dwAlignToSectorSize(DWORD dwSize, DWORD dwSectorSize)
{
	return ((1 + (dwSize / dwSectorSize)) * dwSectorSize);
}

//------------------------------------------------------------------------
DWORD fn_dwGetTotalHeaderSize(DWORD dwFileNumber, DWORD dwOccur, DWORD dwSectorSize)
{
	// Keys (4 DWORD) + MapNumber (DWORD) + OccurNumber (DOWRD) + Offset (DWORD)
	return fn_dwAlignToSectorSize(16 + 4 + 4 + (dwOccur* dwFileNumber) * 4 , dwSectorSize);
}

//------------------------------------------------------------------------
DWORD fn_dwGetHeaderSizeForAFile(DWORD dwOccur, DWORD dwSectorSize)
{
	// Keys (4 DWORD) + Offset
	return fn_dwAlignToSectorSize(16 + dwOccur * 4 , dwSectorSize);
}
//------------------------------------------------------------------------
DWORD fn_dwGetHeaderSizeforAnOccur(DWORD dwFileNumber, DWORD dwSectorSize)
{
	// Keys (4 DWORD) + Offset
	return fn_dwAlignToSectorSize(16 + dwFileNumber * 4 , dwSectorSize);
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBigFileToolDlg dialog

#define M_SPIN(nID)		((CSpinButtonCtrl*) GetDlgItem (nID))
#define M_EDIT(nID)		((CEdit*)GetDlgItem(nID))
#define M_LIST(nID)		((CListBox*)GetDlgItem(nID))
#define M_BT(nID)		((CButton*)GetDlgItem(nID))

CBigFileToolDlg::CBigFileToolDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CBigFileToolDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CBigFileToolDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CBigFileToolDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBigFileToolDlg)
	DDX_Control(pDX, IDC_PROGRESS, m_Ctrl_ProgressBar);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBigFileToolDlg, CDialog)
	//{{AFX_MSG_MAP(CBigFileToolDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_BROWSE, OnButtonBrowse)
	ON_BN_CLICKED(IDC_BUTTON_RUN, OnButtonRun)
	ON_BN_CLICKED(IDC_BUTTON_BROWSESCRIPT, OnButtonBrowsescript)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBigFileToolDlg message handlers

BOOL CBigFileToolDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// Init Scripts
	fn_vInitScr();

    // Init Controls
	M_SPIN(IDC_SPIN_SIZE) -> SetRange (1 , 500);
	M_LIST(IDC_LIST_WORK) -> ResetContent ();
	M_BT(IDC_CHECK_DELETEFILES) -> SetCheck (FALSE);
	if (AfxGetApp () -> m_lpCmdLine[0] == '\0')
	{
		ReadINIFile ();
	}
	else
	{
		InitWithCommandLine ();
	}

	if (m_bAutoRun)
	{
		PostMessage(WM_COMMAND , MAKEWPARAM(IDC_BUTTON_RUN,BN_CLICKED) , (LPARAM)GetDlgItem (IDC_BUTTON_RUN) -> m_hWnd);
	}

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CBigFileToolDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CBigFileToolDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CBigFileToolDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

/*=======================================================================================
 * Description      BN_CLICKED message handles : button "Run"
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::OnButtonRun()
{
	BOOL bResult;

    // Disables buttons
	GetDlgItem (IDC_BUTTON_RUN)	-> EnableWindow (FALSE);
	GetDlgItem (IDOK)	-> EnableWindow (FALSE);

	m_bGenerateInfoFiles = M_BT(IDC_CHECK_INFO) -> GetCheck ();

    // Save choices
	WriteINIFile ();

    // Run process
	bResult = Run();

    // Restore buttons
	GetDlgItem (IDC_BUTTON_RUN)	-> EnableWindow (TRUE);
	GetDlgItem (IDOK)	-> EnableWindow (TRUE);

	if (m_bAutoRun)
	{
		if (bResult)	OnOK ();
		else					OnCancel();
	}
}

/*=======================================================================================
 * Description      BN_CLICKED message handles : button "Browse Script"
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::OnButtonBrowsescript()
{
	OnBrowse (IDC_EDIT_SCRIPTDATAPATH);
}

/*=======================================================================================
 * Description      BN_CLICKED message handles : button "Browse Binary"
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::OnButtonBrowse()
{
	OnBrowse (IDC_EDIT_DATAPATH);
}

/*=======================================================================================
 * Description      Open a Browse dialog and update nID control with result
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::OnBrowse(UINT nID)
{
    BROWSEINFO bi;
    LPSTR lpBuffer = (LPSTR)malloc(_MAX_PATH);
    LPITEMIDLIST pidlBrowse;    // PIDL selected by user


    // Fill in the BROWSEINFO structure.
    bi.hwndOwner = m_hWnd;
    bi.pidlRoot = NULL;
    bi.pszDisplayName = lpBuffer;
    bi.lpszTitle = "Choose a Path";
    bi.ulFlags = 0;
    bi.lpfn = NULL;
    bi.lParam = 0;

    // Browse for a folder and return its PIDL.
    pidlBrowse = SHBrowseForFolder(&bi);
    if (pidlBrowse != NULL)
    {
        if (SHGetPathFromIDList(pidlBrowse, lpBuffer))
        {
            M_EDIT(nID) -> SetWindowText(lpBuffer);
        }
    }

    // Clean up.
    free(lpBuffer);
}

/*=======================================================================================
 * Description      BN_CLICKED message handles : button "Cancel"
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::OnCancel()
{
	fn_vDesinitScr();
	CDialog::OnCancel();
}

/*=======================================================================================
 * Description      BN_CLICKED message handles : button "OK"
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::OnOK()
{
	fn_vDesinitScr();
	CDialog::OnOK();
}


#define M_Run_Assert(bTest,szTitle,szMessage) \
if(!(bTest)) \
{ \
	MessageBox (szMessage,szTitle,MB_OK + MB_ICONERROR); \
	return FALSE; \
}
/*=======================================================================================
 * Description      Run process
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
BOOL CBigFileToolDlg::Run()
{
	char				szDataPath[MAX_PATH];
	char				szScriptDataPath[MAX_PATH];
	CListOfFileInfo		oFIList;
	tdstMixUpInfo		*_a_MUITab;
	DWORD				dwBigFileSize;
	char				szText[128];
	char				szBigFileName[MAX_PATH];
	CStringList			oListOfMaps;
	tdstHeaderInfo		*_a_HITab;
	tdstBigFileInfo		stBFI;
	BOOL				bResult;

	// Get script data path
	M_EDIT(IDC_EDIT_SCRIPTDATAPATH) -> GetWindowText (szScriptDataPath , MAX_PATH);
	if(szScriptDataPath[strlen (szScriptDataPath) - 1] != '\\')
	{
		strcat (szScriptDataPath , "\\");
	}

	M_LIST(IDC_LIST_WORK) -> AddString ("Read Game.dsc");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

    // read Game.dsc to get list of maps
	bResult = fn_bReadGameDsc (szScriptDataPath , &oListOfMaps);

	M_Run_Assert(bResult,"ERROR","Can't find Game.dsc file");

	sprintf (szText , "\t%d maps in Game.dsc" , oListOfMaps . GetCount ());
	M_LIST(IDC_LIST_WORK) -> AddString (szText);

	// Message Pump
	PeekAndPump ();

	// Get Data Path
	M_EDIT(IDC_EDIT_DATAPATH) -> GetWindowText (szDataPath , MAX_PATH);
	if(szDataPath[strlen (szDataPath) - 1] != '\\')
	{
		strcat (szDataPath , "\\");
	}
	strcat (szDataPath , "World\\Levels\\");

	// Get BigfileSize;
	M_EDIT(IDC_EDIT_SIZE) -> GetWindowText (szText , 10);
	dwBigFileSize = 1024 * 1024 * atol (szText);

	// get list of rt* files and total size
	ReadListOfFiles (szDataPath , &oListOfMaps , &oFIList);

	// Message Pump
	PeekAndPump ();

	/*
	// mix up files
	bResult = MixUpFiles (dwBigFileSize , &oFIList , &_a_MUITab, &stBFI);

	// Message Pump
	PeekAndPump ();

	// create Big File
	strcpy (szBigFileName , szDataPath);
	strcat (szBigFileName , C_szBigFileName);
	HANDLE hFile = CreateFile (szBigFileName , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);

	// Message Pump
	PeekAndPump ();

	// Write Header
	bResult = WriteHeader (hFile , &oFIList , _a_MUITab , &stBFI);

	// Write rt* Files
	bResult = WriteFiles (szDataPath , hFile , &oFIList , _a_MUITab , &stBFI);
	*/

	// mix up files
	bResult = MixUpFilesWithExplodedHeader(dwBigFileSize , &oFIList , &_a_MUITab, &stBFI , &_a_HITab);
	M_Run_Assert(bResult,"Error",m_csErrorMessage);

	// Message Pump
	PeekAndPump ();

	// create Big File
	strcpy (szBigFileName , szDataPath);
	strcat (szBigFileName , C_szBigFileName);
	HANDLE hFile = CreateFile (szBigFileName , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);

	M_Run_Assert(hFile != INVALID_HANDLE_VALUE,"Error","Can't create data.000 file");

	// Message Pump
	PeekAndPump ();

	// Write file
	bResult = WriteBigFileWithExplodedHeader(szDataPath , hFile, &oFIList, _a_MUITab, &stBFI , _a_HITab);
	M_Run_Assert(bResult,"Error",m_csErrorMessage);
	
	{
		CString csText;

		csText . Format ("\tSize of Big File : %ld" , GetFileSize (hFile , NULL));
		M_LIST(IDC_LIST_WORK) -> AddString (csText);
	}

	// Close Big File
	CloseHandle (hFile);

	if (M_BT(IDC_CHECK_DELETEFILES) -> GetCheck ())
	{
		DeleteFiles (szScriptDataPath , &oFIList);
	}

	if (M_BT(IDC_CHECK_STARTPRG) -> GetCheck ())
	{
		UpdateStartPrg ();
	}

	// free
	while (oFIList . GetCount ())	free (oFIList . RemoveHead ());
	free (_a_MUITab);

	M_LIST(IDC_LIST_WORK) -> AddString ("=================================================");
	M_LIST(IDC_LIST_WORK) -> AddString ("BigFile Generated");
	M_LIST(IDC_LIST_WORK) -> AddString ("=================================================");

	return TRUE;
}

//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				24 mars 1999
// 
// Prototype		CBigFileToolDlg::PeekAndPump
// Return Type		void
// 
// Description		
// 
//------------------------------------------------------------------------
void CBigFileToolDlg::PeekAndPump()
{
	MSG		msg;
	LONG	lIdle = 0;

	while (::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
	{
		if (!AfxGetApp()->PumpMessage())
		{
			::PostQuitMessage(0);
			return;
		}
	}
	while(AfxGetApp()->OnIdle(lIdle++));
}

/*=======================================================================================
 * Description      Read default values on INI file
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::ReadINIFile()
{
	CString csText;

	// Script Data Path
	csText = AfxGetApp () -> GetProfileString("Default" , "ScriptDataPath");
	M_EDIT(IDC_EDIT_SCRIPTDATAPATH) -> SetWindowText (csText);

	// Binary Data Path
	csText = AfxGetApp () -> GetProfileString("Default" , "BinaryDataPath");
	M_EDIT(IDC_EDIT_DATAPATH) -> SetWindowText (csText);

	// BigFile Size
	csText = AfxGetApp () -> GetProfileString("Default" , "BigFileSize");
	M_EDIT(IDC_EDIT_SIZE) -> SetWindowText (csText);
	M_SPIN(IDC_SPIN_SIZE) -> SetPos (atol ((char*)(LPCTSTR)csText));

	// Generate Info
	M_BT(IDC_CHECK_INFO) -> SetCheck (AfxGetApp () -> GetProfileInt("Default" , "GenerateInfo" , 0));

	// Delete File
	M_BT(IDC_CHECK_DELETEFILES) -> SetCheck (AfxGetApp () -> GetProfileInt("Default" , "DeleteFiles" , 0));

	// AutoRun
	m_bAutoRun = FALSE;

	// Update StartPrg.ini
	M_BT(IDC_CHECK_STARTPRG) -> SetCheck (AfxGetApp () -> GetProfileInt("Default" , "UpdateStartPrg" , 0));
}

/*=======================================================================================
 * Description      Save current values on INI file
 *
 * Creation date    23/03/99
 * Author           Marc Trabucato
 *=====================================================================================*/
void CBigFileToolDlg::WriteINIFile()
{
	CString csText;

	// Script Data Path
	M_EDIT(IDC_EDIT_SCRIPTDATAPATH) -> GetWindowText (csText);
	AfxGetApp () -> WriteProfileString("Default" , "ScriptDataPath" , csText);

	// Binary Data Path
	M_EDIT(IDC_EDIT_DATAPATH) -> GetWindowText (csText);
	AfxGetApp () -> WriteProfileString("Default" , "BinaryDataPath" , csText);

	// BigFile Size
	M_EDIT(IDC_EDIT_SIZE) -> GetWindowText (csText);
	AfxGetApp () -> WriteProfileString("Default" , "BigFileSize" , csText);

	// Generate Info
	AfxGetApp () -> WriteProfileInt("Default" , "GenerateInfo" , M_BT(IDC_CHECK_INFO) -> GetCheck ());

	// Delete File
	AfxGetApp () -> WriteProfileInt("Default" , "DeleteFiles" , M_BT(IDC_CHECK_DELETEFILES) -> GetCheck ());

	// Update StartPrg.ini
	AfxGetApp () -> WriteProfileInt("Default" , "UpdateStartPrg" , M_BT(IDC_CHECK_STARTPRG) -> GetCheck ());
}


//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				23 mars 1999
// 
// Prototype		CBigFileToolDlg::InitWithCommandLine
// Return Type		void
// 
// Description		
// 
//------------------------------------------------------------------------
void CBigFileToolDlg::InitWithCommandLine()
{
	LPSTR lpCommandLine = AfxGetApp () -> m_lpCmdLine;
	char szParam[MAX_PATH];

	char *p_cScriptDataPath = strstr (lpCommandLine , "-scriptpath:");
	char *p_cBinaryDataPath = strstr (lpCommandLine , "-binarypath:");
	char *p_cBigFileSize    = strstr (lpCommandLine , "-bigfilesize:");
	char *p_cDeleteFile		= strstr (lpCommandLine , "-deletefile");
	char *p_cGenerateInfo	= strstr (lpCommandLine , "-generateinfo");
	char *p_cAutoRun		= strstr (lpCommandLine , "-autorun");
	char *p_cStartPrg		= strstr (lpCommandLine , "-startprg");
	
	// Script Data Path
	if (p_cScriptDataPath)
	{
		sscanf(p_cScriptDataPath + 12 , "%s" , szParam);
		M_EDIT(IDC_EDIT_SCRIPTDATAPATH) -> SetWindowText (szParam);
	}

	// Binary Data Path
	if (p_cBinaryDataPath)
	{
		sscanf(p_cBinaryDataPath + 12 , "%s" , szParam);
		M_EDIT(IDC_EDIT_DATAPATH) -> SetWindowText (szParam);
	}

	// Big File Size
	if (p_cBigFileSize)
	{
		sscanf(p_cBigFileSize + 13 , "%s" , szParam);
		M_EDIT(IDC_EDIT_SIZE) -> SetWindowText (szParam);
		M_SPIN(IDC_SPIN_SIZE) -> SetPos (atol (szParam));
	}

	// Delete File
	M_BT(IDC_CHECK_DELETEFILES) -> SetCheck (p_cDeleteFile != NULL);

	// Generate Info
	M_BT(IDC_CHECK_INFO) -> SetCheck (p_cGenerateInfo != NULL);

	// AutoRun
	m_bAutoRun = (p_cAutoRun != NULL);

	// Update StartPrg.ini
	M_BT(IDC_CHECK_STARTPRG) -> SetCheck (p_cStartPrg != NULL);
}


/*------------------------------------------------------------------------
 *
 * Author			Marc Trabucato
 * Date				14 avr. 1999
 * 
 * Prototype		CBigFileToolDlg::UpdateStartPrg
 * Return Type		void
 * 
 * Description		
 * 
 *------------------------------------------------------------------------*/
void CBigFileToolDlg::UpdateStartPrg()
{
	char szScriptDataPath[MAX_PATH];


	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Update StartPrg.ini");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

	// Get script data path
	M_EDIT(IDC_EDIT_SCRIPTDATAPATH) -> GetWindowText (szScriptDataPath , MAX_PATH);
	if(szScriptDataPath[strlen (szScriptDataPath) - 1] == '\\')
	{
		szScriptDataPath[strlen (szScriptDataPath) - 1] = 0;
	}

	// compute StartPrg.ini FileName
	char *p_cSeparator = strrchr (szScriptDataPath , '\\');
	if (p_cSeparator)
	{
		p_cSeparator++;
		sprintf (p_cSeparator , "%s" , "StartPrg.ini");

		//
		WritePrivateProfileString ("Start" , "UsesBigFile" , "Yes" , szScriptDataPath);
	}
}

////////////////////////////////////////////////////////////////////////////


//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				22 mars 1999
//
// Prototype		CBigFileToolDlg::ReadListOfFiles
// Parameters		_p_oList :
// Return Type		void
//
// Description		Read List of rt* files
//
//------------------------------------------------------------------------
void CBigFileToolDlg::ReadListOfFiles(char *_szDataPath , CStringList *_p_oMapList , CListOfFileInfo *_p_oList)
{
    WIN32_FIND_DATA stWFDFile;
    HANDLE          hFDFile;
	char			szFileName[MAX_PATH];
	DWORD			dwMapNumber;
	CListBox		*pLB = M_LIST(IDC_LIST_WORK);
	char			szText[128];

	pLB -> AddString ("");
	pLB -> AddString ("Search rt* files");
	pLB -> AddString ("");

	m_Ctrl_ProgressBar . SetRange (0 , _p_oMapList -> GetCount ());
	m_Ctrl_ProgressBar . SetPos (0);
	m_Ctrl_ProgressBar . SetStep (1);

	POSITION xPos = _p_oMapList -> GetHeadPosition ();
	while (xPos)
	{
		char			*p_cMapName = (char*)(LPCTSTR) _p_oMapList -> GetNext (xPos);
		tdstFileInfo	*p_stFI;

		// rtb file
		p_stFI		= (tdstFileInfo*) malloc (sizeof tdstFileInfo);
		sprintf (szFileName , "%s%s\\%s.rtb" , _szDataPath , p_cMapName , p_cMapName);
		sprintf (p_stFI -> szFileName , "%s\\%s.rtb" , p_cMapName , p_cMapName);

		hFDFile = FindFirstFile (szFileName, &stWFDFile);
		p_stFI -> dwSize = (hFDFile != INVALID_HANDLE_VALUE ? stWFDFile . nFileSizeLow : 0);
		_p_oList -> AddTail (p_stFI);
		FindClose (hFDFile);

		// rtp file
		p_stFI		= (tdstFileInfo*) malloc (sizeof tdstFileInfo);
		sprintf (szFileName , "%s%s\\%s.rtp" , _szDataPath , p_cMapName , p_cMapName);
		sprintf (p_stFI -> szFileName , "%s\\%s.rtp" , p_cMapName , p_cMapName);

		hFDFile = FindFirstFile (szFileName, &stWFDFile);
		p_stFI -> dwSize = (hFDFile != INVALID_HANDLE_VALUE ? stWFDFile . nFileSizeLow : 0);
		_p_oList -> AddTail (p_stFI);
		FindClose (hFDFile);

		// rts file
		p_stFI		= (tdstFileInfo*) malloc (sizeof tdstFileInfo);
		sprintf (szFileName , "%s%s\\%s.rts" , _szDataPath , p_cMapName , p_cMapName);
		sprintf (p_stFI -> szFileName , "%s\\%s.rts" , p_cMapName , p_cMapName);

		hFDFile = FindFirstFile (szFileName, &stWFDFile);
		p_stFI -> dwSize = (hFDFile != INVALID_HANDLE_VALUE ? stWFDFile . nFileSizeLow : 0);
		_p_oList -> AddTail (p_stFI);
		FindClose (hFDFile);

		// rtt file
		p_stFI		= (tdstFileInfo*) malloc (sizeof tdstFileInfo);
		sprintf (szFileName , "%s%s\\%s.rtt" , _szDataPath , p_cMapName , p_cMapName);
		sprintf (p_stFI -> szFileName , "%s\\%s.rtt" , p_cMapName , p_cMapName);

		hFDFile = FindFirstFile (szFileName, &stWFDFile);
		p_stFI -> dwSize = (hFDFile != INVALID_HANDLE_VALUE ? stWFDFile . nFileSizeLow : 0);
		_p_oList -> AddTail (p_stFI);
		FindClose (hFDFile);

		m_Ctrl_ProgressBar . StepIt ();
	}

    //
    dwMapNumber = 0;
    xPos = _p_oList -> GetHeadPosition ();
    while (xPos)
    {
        tdstFileInfo *p_stFI = _p_oList -> GetNext (xPos);
        p_stFI -> dwMapNumber = dwMapNumber++;
    }
	sprintf (szText , "\t%d rt? files" , _p_oList -> GetCount ());
	pLB -> AddString (szText);
}

#define M_SECTOR_SIZE	2048

//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				22 mars 1999
//
// Prototype		CBigFileToolDlg::MixUpFiles
// Parameters		_p_oFIList :
//					_p_oMUIList :
// Return Type		void
//
// Description
//
//------------------------------------------------------------------------
BOOL CBigFileToolDlg::MixUpFiles(DWORD _dwBigFileSize , CListOfFileInfo *_p_oFIList , tdstMixUpInfo **_a_MUITab, tdstBigFileInfo *p_stBFI)
{
	DWORD dwArraySize;
	POSITION xPos;
	tdstMixUpInfo *p_stMUI;
	DWORD dwOffSet;
	DWORD dwMaxSize = 0;

	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Mix up files");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

	// compute total size
	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute total size");
	p_stBFI -> dwTotalSize = 0;
	xPos = _p_oFIList -> GetHeadPosition ();
	while (xPos)
	{
		DWORD dwSize = _p_oFIList -> GetNext (xPos) -> dwSize;

		dwSize = fn_dwAlignToSectorSize(dwSize + 4, M_SECTOR_SIZE);	// add protect-key to each file

		p_stBFI -> dwTotalSize += dwSize;
	}
    p_stBFI -> dwNbFile = _p_oFIList -> GetCount ();

	// compute number of occurrences
	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute number of occurrences");
	p_stBFI -> dwNbOccur = 1 + (_dwBigFileSize / p_stBFI -> dwTotalSize);

	{
		CString csText;

		csText . Format ("\t%d occurrences of %d files" , p_stBFI -> dwNbOccur , p_stBFI -> dwNbFile);
		M_LIST(IDC_LIST_WORK) -> AddString (csText);
	}

	//
	LARGE_INTEGER PerformanceCount;
	QueryPerformanceCounter (&PerformanceCount);
	PTC_g_lCurrentRandom = PerformanceCount . LowPart;

	// Create Array
	dwArraySize = p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile;
	*_a_MUITab = (tdstMixUpInfo*) malloc (dwArraySize * sizeof(tdstMixUpInfo));

	// Fill Array
	p_stMUI = *_a_MUITab;
	p_stBFI -> dwMaxFileSize = 0;
	for (DWORD dwOccur = 0 ; dwOccur < p_stBFI -> dwNbOccur ; dwOccur++)
	{
		xPos = _p_oFIList -> GetHeadPosition ();
		while (xPos)
		{
			tdstFileInfo *p_stFI = _p_oFIList -> GetAt (xPos);

			p_stMUI -> xFileInfoPosition = xPos;
			p_stMUI -> dwOccur		= dwOccur;
			p_stMUI -> dwOffSet		= 0;
			p_stMUI -> dwMapNumber	= p_stFI -> dwMapNumber;
			p_stMUI -> dwSize		= fn_dwAlignToSectorSize(p_stFI -> dwSize + 4, M_SECTOR_SIZE);	// add protect-key to each file
			p_stMUI -> p_cFileName  = p_stFI -> szFileName;

			p_stBFI -> dwMaxFileSize = max (p_stBFI -> dwMaxFileSize, p_stMUI -> dwSize);
			_p_oFIList -> GetNext (xPos);
			p_stMUI++;
		}
	}

	// MixUp Array
	//
	M_LIST(IDC_LIST_WORK) -> AddString ("\tMix up files and Compute OffSets");

	// Init Offset
	p_stBFI -> dwBigHeaderSize = fn_dwGetTotalHeaderSize(p_stBFI -> dwNbFile , p_stBFI -> dwNbOccur , M_SECTOR_SIZE);
	dwOffSet = p_stBFI -> dwBigHeaderSize;

    for (DWORD dwIndex = 0 ; dwIndex < dwArraySize-1 ; dwIndex++)
    {
        DWORD dwNewPosition = PTC_fn_lGetRandomRange (dwIndex+1 , dwArraySize);
      
        // swap
        tdstMixUpInfo stMUITmp;
		
        stMUITmp                    = (*_a_MUITab)[dwIndex];
        (*_a_MUITab)[dwIndex]       = (*_a_MUITab)[dwNewPosition];
        (*_a_MUITab)[dwNewPosition] = stMUITmp;

		// compute OffSet
		(*_a_MUITab)[dwIndex] . dwOffSet = dwOffSet;
		// increase OffSet
		dwOffSet += (*_a_MUITab)[dwIndex] . dwSize;
    }
	// compute OffSet of last one
	(*_a_MUITab)[dwArraySize-1] . dwOffSet = dwOffSet;

	return TRUE;
}


//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------

BOOL CBigFileToolDlg::WriteHeader(HANDLE hFile, CListOfFileInfo *_p_oFIList, tdstMixUpInfo *_a_MUITab, tdstBigFileInfo *p_stBFI)
{
	DWORD dwNumberOfMUI = p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile;
	tdstMixUpInfo *p_stMUI    = _a_MUITab;
	tdstMixUpInfo *p_stMUIEnd = _a_MUITab + dwNumberOfMUI;
	DWORD *a_OffSet;
	DWORD dwWritten;
    DWORD dwKeys[4];
	DWORD dwCount;
	DWORD *p_dwHeader,*p_dwCurrentPos,*p_dwBeginOfCryptHeader,*p_dwEndHeader;

	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Write Header");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

    // Compute Header Size : Keys + MapNumber + OccurNumber + Offset	
	p_dwCurrentPos = p_dwHeader = (DWORD*) malloc (p_stBFI -> dwBigHeaderSize);
	p_dwEndHeader  = p_dwHeader + (p_stBFI -> dwBigHeaderSize>>2);

	m_Ctrl_ProgressBar . SetRange (0 , p_stBFI -> dwBigHeaderSize << 2);
	m_Ctrl_ProgressBar . SetPos (2);
	{
		CString csText;

		csText . Format ("\tSize of header : %d" , p_stBFI -> dwBigHeaderSize);
		M_LIST(IDC_LIST_WORK) -> AddString (csText);
	}


    // Compute and write keys
	dwCount = 0;
	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute keys");
    for (int i=0 ; i<4 ; i++ )
    {
		dwKeys[i] = PTC_fn_lGetRandom();
		*p_dwCurrentPos++ = dwKeys[i];
		m_Ctrl_ProgressBar . SetStep (1);
		dwCount++;
    }
	p_dwBeginOfCryptHeader = p_dwCurrentPos;

	// Write Number of map
	M_LIST(IDC_LIST_WORK) -> AddString ("\tWrite Number of files");
	*p_dwCurrentPos++ = p_stBFI -> dwNbFile;
	m_Ctrl_ProgressBar . SetStep (1);
	dwCount++;

	// Write number of occur
	M_LIST(IDC_LIST_WORK) -> AddString ("\tWrite number of occur");
    *p_dwCurrentPos++ = p_stBFI -> dwNbOccur;
	m_Ctrl_ProgressBar . SetStep (1);
	dwCount++;

	// Compute OffSet
	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute OffSet");
	a_OffSet = p_dwCurrentPos;

	while (p_stMUI != p_stMUIEnd)
	{
		//
		DWORD dwIndex = p_stBFI -> dwNbOccur * p_stMUI -> dwMapNumber + p_stMUI -> dwOccur;
        a_OffSet [ dwIndex ] = p_stMUI -> dwOffSet ;

		// next
		p_stMUI++;
		m_Ctrl_ProgressBar . SetStep (1);
	}

	if (m_bGenerateInfoFiles)
	{
		char szText[255];
		HANDLE hDebugFile = CreateFile ("BigFile.txt" , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);
		DWORD dwMap , dwOcc, dwW;

		sprintf (szText , "Keys : 0x%08x  -  0x%08x  -  0x%08x  -  0x%08x\x0D\x0A" , dwKeys[0] , dwKeys[1] , dwKeys[2] , dwKeys[3]);
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

		for (dwOcc = 0 ; dwOcc < p_stBFI -> dwNbOccur ; dwOcc++)
		{
			sprintf (szText , "==============================================================================\x0D\x0A");
			WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

			for (dwMap = 0 ; dwMap < p_stBFI -> dwNbMap ; dwMap+=4)
			{
				DWORD dwIndex = p_stBFI -> dwNbOccur * dwMap + dwOcc;

				sprintf (szText , "Map : %02d : Occur %02d : 0x%08x  -  0x%08x  -  0x%08x  -  0x%08x\x0D\x0A" , dwMap >> 2, dwOcc , a_OffSet [dwIndex] , a_OffSet [dwIndex + p_stBFI -> dwNbOccur] ,a_OffSet [dwIndex + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur] ,a_OffSet [dwIndex + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur]);
				WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
			}
		}
		sprintf (szText , "==============================================================================\x0D\x0A");
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

		CloseHandle (hDebugFile);
	}

	p_dwCurrentPos = a_OffSet + (p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile);
	dwCount += p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile;

	// fill to align to Sector Size
	while (p_dwCurrentPos != p_dwEndHeader)
	{
		*p_dwCurrentPos++ = PTC_fn_lGetRandom();
		m_Ctrl_ProgressBar . SetStep (1);
		dwCount++;
	}

	ASSERT(dwCount == (p_stBFI -> dwBigHeaderSize>>2));
	// crypt file
	p_dwCurrentPos = p_dwBeginOfCryptHeader;
	while (p_dwCurrentPos != p_dwEndHeader)
	{
        *p_dwCurrentPos = (*p_dwCurrentPos ^ dwKeys[1]) + dwKeys[0];
		*p_dwCurrentPos++;
        dwKeys[0] += dwKeys[2];
        dwKeys[1] += dwKeys[3];
	}

	// Write File
	WriteFile (hFile , p_dwHeader , p_stBFI -> dwBigHeaderSize , &dwWritten , NULL);	

	free (p_dwHeader);

	return TRUE;
}

//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				22 mars 1999
//
// Prototype		CBigFileToolDlg::WriteFiles
// Parameters		hFile :
//					_p_oFIList :
//					_p_oMUIList :
// Return Type		void
//
// Description      Write all files to Big File
//
//------------------------------------------------------------------------
BOOL CBigFileToolDlg::WriteFiles(char *_szDataPath , HANDLE hFile, CListOfFileInfo *_p_oFIList, tdstMixUpInfo *_a_MUITab, tdstBigFileInfo *p_stBFI)
{
	DWORD dwNumberOfMUI = p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile;
	tdstMixUpInfo *p_stMUI    = _a_MUITab;
	tdstMixUpInfo *p_stMUIEnd = _a_MUITab + dwNumberOfMUI;
	char szFileName[MAX_PATH];
	char *p_cBeginFileName;
	DWORD dwRead , dwWritten;
	char szText[255];
	HANDLE hDebugFile;
	DWORD dwW,dwCount;
    DWORD dwCurrentOffSet;
	unsigned char a_ucKeys[4];
	unsigned char a_ucCode[4];
	unsigned char a_ucProtection[4];
	DWORD *p_dwKey = (DWORD*)a_ucKeys;
	DWORD *p_dwProtection = (DWORD*)a_ucProtection;

	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Write files");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

	m_Ctrl_ProgressBar . SetRange (0 , dwNumberOfMUI);
	m_Ctrl_ProgressBar . SetPos (0);
	m_Ctrl_ProgressBar . SetStep (1);

	strcpy (szFileName , _szDataPath);
	p_cBeginFileName = szFileName + strlen (_szDataPath);

	HGLOBAL hMem = GlobalAlloc (GHND , p_stBFI -> dwMaxFileSize + 4 + 4);
	
	char *p_Buffer = (char*) GlobalLock (hMem);
	char *p_Begin;

	if (m_bGenerateInfoFiles)
	{
		hDebugFile		= CreateFile ("BigFile.log" , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);
		dwCurrentOffSet = p_stBFI -> dwBigHeaderSize;
		dwCount = 0;
	}	

	while (p_stMUI != p_stMUIEnd)
	{
		tdstFileInfo *p_stFI = _p_oFIList -> GetAt (p_stMUI -> xFileInfoPosition);

		// compute crypt int-key
		a_ucCode[0] = (unsigned char) (p_stMUI -> dwMapNumber >> 2);
		a_ucCode[1] = (unsigned char) (p_stMUI -> dwMapNumber % 4);
		a_ucCode[2] = (unsigned char) (p_stMUI -> dwOccur & 0x000000FF);
		a_ucCode[3] = ~a_ucCode[2];

		// compute crypt key
		*p_dwKey		= PTC_fn_lGetCryptKey (*(DWORD*)a_ucCode);

		// compute protection key
		*p_dwProtection = PTC_fn_lGetProtectionKey (*(DWORD*)a_ucCode);

		// fill Debug File
		if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)
		{
			sprintf (szText , "%03d - OffSet : 0x%08x - init-key : 0x%02x%02x%02x%02x => crypt-key : 0x%08x => protect-key : 0x%08x - Map : %s\x0D\x0A"
							, dwCount++ , dwCurrentOffSet , a_ucCode[0] , a_ucCode[1] , a_ucCode[2] , a_ucCode[3]  , *p_dwKey , *p_dwProtection , p_cBeginFileName );

			WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
		}

		// copy Protect key to buffer
		memcpy (p_Buffer , p_dwProtection , 4);
		
		// open Source file
		strcpy (p_cBeginFileName , p_stFI -> szFileName);

		HANDLE hSourceFile = CreateFile ( szFileName, GENERIC_READ , 0 , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL);

		// Copy File
		// Read initial file
		ReadFile (hSourceFile , p_Buffer + 4 , p_stFI -> dwSize + 1 , &dwRead , NULL);
		CloseHandle (hSourceFile);

		dwRead += 4;	// protect key size

		// crypt buffer
		unsigned char *p_ucBeginBuffer = (unsigned char*)p_Buffer;
		unsigned char *p_ucEndBuffer   = (unsigned char*)p_Buffer + dwRead;

		while (p_ucBeginBuffer != p_ucEndBuffer)
		{
			*p_ucBeginBuffer = (*p_ucBeginBuffer ^ a_ucKeys[1]) + a_ucKeys[0];
			a_ucKeys[0] += a_ucKeys[2];
			a_ucKeys[1] += a_ucKeys[3];
			p_ucBeginBuffer++;
		}

		p_Begin = p_Buffer + dwRead;
		
		// Fill to long alignment
		while (dwRead % 4)
		{
			*p_Begin = (unsigned char) PTC_fn_lGetRandomRange (0, 255);
			p_Begin++;
			dwRead++;
		}

		// Fill to align to sector size
		while (dwRead < p_stMUI -> dwSize)
		{
			DWORD dwRandom = PTC_fn_lGetRandom();
			memcpy (p_Begin , &dwRandom , 4);
			p_Begin += 4;
			dwRead += 4;
		}

		// write buffer
		WriteFile(hFile , p_Buffer , p_stMUI -> dwSize , &dwWritten , NULL);

		if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)			dwCurrentOffSet += dwWritten;

		m_Ctrl_ProgressBar . StepIt ();


		// next
		p_stMUI++;

		// Message Pump
		PeekAndPump ();
	}
	GlobalUnlock (hMem);
	GlobalFree (hMem);

	if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)			CloseHandle (hDebugFile);

	m_Ctrl_ProgressBar . SetPos (0);

	return TRUE;
}


//------------------------------------------------------------------------
//
// Author			Marc Trabucato
// Date				23 mars 1999
// 
// Prototype		CBigFileToolDlg::DeleteFiles
// Parameters		_szDataPath : 
//					_p_oList : 
// Return Type		void
// 
// Description		
// 
//------------------------------------------------------------------------
void CBigFileToolDlg::DeleteFiles(char *_szDataPath , CListOfFileInfo * _p_oList)
{
	POSITION xPos;
	char szFileName[MAX_PATH];
	char *p_cBeginFileName;

	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Delete files");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

	m_Ctrl_ProgressBar . SetRange (0 , _p_oList -> GetCount ());
	m_Ctrl_ProgressBar . SetPos (0);
	m_Ctrl_ProgressBar . SetStep (1);

	strcpy (szFileName , _szDataPath);
	p_cBeginFileName = szFileName + strlen (_szDataPath);

	xPos = _p_oList -> GetHeadPosition ();
	while (xPos)
	{
		tdstFileInfo *p_stFI = _p_oList -> GetNext (xPos);

		strcpy (p_cBeginFileName , p_stFI -> szFileName);
		
		if (_access(szFileName , 00) == 0)
		{
			remove (szFileName);
		}
		m_Ctrl_ProgressBar . StepIt ();
	}
}


//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
int fn_iCompareHeaderInfo(const void *elem1, const void *elem2 ) 
{
	tdstHeaderInfo *p_stHI1 = (tdstHeaderInfo*)elem1;
	tdstHeaderInfo *p_stHI2 = (tdstHeaderInfo*)elem2;

	     if (p_stHI1 -> dwOffSet < p_stHI2 -> dwOffSet)		return -1;
	else if (p_stHI1 -> dwOffSet == p_stHI2 -> dwOffSet)	return 0;
	else													return 1;
}

#define M_Arround(x)	(floor(x * 1000000.0) / 1000000.0)
//------------------------------------------------------------------------
//------------------------------------------------------------------------
BOOL CBigFileToolDlg::MixUpFilesWithExplodedHeader(DWORD _dwBigFileSize , CListOfFileInfo *_p_oFIList , tdstMixUpInfo **_a_MUITab, tdstBigFileInfo *p_stBFI, tdstHeaderInfo **_a_HITab)
{
	DWORD dwArraySize , dwNextHeaderPos , dwHeaderNumber;
	POSITION xPos;
	tdstMixUpInfo *p_stMUI;
	DWORD dwOffSet;
	DWORD dwMaxSize = 0;
	DWORD dwCount = 0;
	CString csText;

	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Mix up files");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

	// compute total size
	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute total size of rt? files");
	p_stBFI -> dwTotalSize = 0;
	xPos = _p_oFIList -> GetHeadPosition ();
	while (xPos)
	{
		DWORD dwSize = _p_oFIList -> GetNext (xPos) -> dwSize;

		dwSize = fn_dwAlignToSectorSize(dwSize + 4, M_SECTOR_SIZE);	// add protect-key to each file

		p_stBFI -> dwTotalSize += dwSize;
	}
    p_stBFI -> dwNbFile = _p_oFIList -> GetCount ();
	p_stBFI -> dwNbMap  = (p_stBFI -> dwNbFile >> 2);

	p_stBFI -> dwFirstHeaderSize = fn_dwAlignToSectorSize(16 + 4 + 4 + 4 + 4 + 4 + 4, M_SECTOR_SIZE);	// First Header : Keys (4) + MapNumber (1) + OccurNumber (1) + HeaderStep (1) + FirstHeaderSize (1) + FileStep (1) + SectorSize (1)

	{
		csText . Format ("\t\tTotal Size : %d" , p_stBFI -> dwTotalSize);
		M_LIST(IDC_LIST_WORK) -> AddString (csText);
	}

	/* -------------------------------------------------------------------------------------------------------------- */

	// compute number of occurrences
	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute number of occurrences");
	p_stBFI -> dwNbOccur = 1 + (_dwBigFileSize / p_stBFI -> dwTotalSize);
	
	if (p_stBFI -> dwNbOccur > 30)		p_stBFI -> dwNbOccur = 30;

	{
		csText . Format ("\t\t%d occurrences of %d files" , p_stBFI -> dwNbOccur , p_stBFI -> dwNbFile);
		M_LIST(IDC_LIST_WORK) -> AddString (csText);
	}

	//
	LARGE_INTEGER PerformanceCount;
	QueryPerformanceCounter (&PerformanceCount);
	PTC_g_lCurrentRandom = PerformanceCount . LowPart;

	/* -------------------------------------------------------------------------------------------------------------- */

	// Create Array
	dwArraySize = p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile;
	*_a_MUITab = (tdstMixUpInfo*) malloc (dwArraySize * sizeof(tdstMixUpInfo));

	// Fill Array
	p_stMUI = *_a_MUITab;
	for (DWORD dwOccur = 0 ; dwOccur < p_stBFI -> dwNbOccur ; dwOccur++)
	{
		xPos = _p_oFIList -> GetHeadPosition ();
		while (xPos)
		{
			tdstFileInfo *p_stFI = _p_oFIList -> GetAt (xPos);

			p_stMUI -> xFileInfoPosition = xPos;
			p_stMUI -> dwOccur		= dwOccur;
			p_stMUI -> dwOffSet		= 0;
			p_stMUI -> dwMapNumber	= p_stFI -> dwMapNumber;
			p_stMUI -> dwSize		= fn_dwAlignToSectorSize(p_stFI -> dwSize + 4, M_SECTOR_SIZE);	// add protect-key to each file
			p_stMUI -> p_cFileName  = p_stFI -> szFileName;

			p_stBFI -> dwMaxFileSize = max (p_stBFI -> dwMaxFileSize, p_stMUI -> dwSize);
			_p_oFIList -> GetNext (xPos);
			p_stMUI++;
		}
	}

	/* -------------------------------------------------------------------------------------------------------------- */

	p_stBFI -> dwHeaderSize = fn_dwGetHeaderSizeforAnOccur (p_stBFI -> dwNbOccur * 4, M_SECTOR_SIZE);

	p_stBFI -> dwTotalSector = (p_stBFI -> dwNbOccur * p_stBFI -> dwTotalSize) / M_SECTOR_SIZE;

	p_stBFI -> dwTotalSector = (p_stBFI -> dwNbOccur * p_stBFI -> dwTotalSize) / p_stBFI -> dwHeaderSize;

	p_stBFI -> dwHeaderStep = p_stBFI -> dwTotalSector / (p_stBFI -> dwNbOccur + 1);

	{
		CString csText;

		//csText . Format ("\tHeader Step : 0x%08x" , p_stBFI -> dwHeaderStep * M_SECTOR_SIZE);
		//M_LIST(IDC_LIST_WORK) -> AddString (csText);
		//csText . Format ("\tHeader Size : 0x%08x - %d" , p_stBFI -> dwHeaderSize , p_stBFI -> dwHeaderSize);
		//M_LIST(IDC_LIST_WORK) -> AddString (csText);
		csText . Format ("\tNb Total Sector : 0x%08x - %d" , p_stBFI -> dwTotalSector , p_stBFI -> dwTotalSector);
		M_LIST(IDC_LIST_WORK) -> AddString (csText);
	}

	/* -------------------------------------------------------------------------------------------------------------- */

	M_LIST(IDC_LIST_WORK) -> AddString ("\tCompute Headers positions");
	*_a_HITab = (tdstHeaderInfo*) malloc (p_stBFI -> dwNbOccur * sizeof(tdstHeaderInfo));	
	{
		DWORD dwN;
		double fN , fValue , fA , fB , fC, fInteger;

		//fA = M_Arround(log(2.0));
		//fB = 1.0+fA;
		//fC = M_Arround(log(fB));
		//fN = M_Arround(log(fabs(fA)+fabs(fB)+fabs(fC)));
		fA = 0.69314;
		fB = 1.69314;
		fC = 0.52658;
		fN = 1.06913;
		//csText . Format ("\tfA : %15.8f - fA : %15.8f - fC : %15.8f - f0 : %15.8f" , fA , fB , fC , fN);
		//M_LIST(IDC_LIST_WORK) -> AddString (csText);

		for (dwN = 0 ; dwN < p_stBFI -> dwNbOccur ; dwN++)
		{
			fValue = M_Arround(modf(fN , &fInteger));
			//csText . Format ("\tOccur %03d : Value %15.8f - OffSet : 0x%08x" , dwN , fValue , M_SECTOR_SIZE * (DWORD)floor(fValue * p_stBFI -> dwTotalSector) );
			//M_LIST(IDC_LIST_WORK) -> AddString (csText);
			(*_a_HITab) [dwN] . dwOccur = dwN;
			//(*_a_HITab) [dwN] . dwOffSet = M_SECTOR_SIZE * (DWORD)floor(fValue * p_stBFI -> dwTotalSector) + p_stBFI -> dwFirstHeaderSize;
			(*_a_HITab) [dwN] . dwOffSet = p_stBFI -> dwHeaderSize * (DWORD)floor(fValue * p_stBFI -> dwTotalSector) + p_stBFI -> dwFirstHeaderSize;
			

			fN = fN + fA * fabs(sin(fB * dwN * dwN)) + fC;
			//fN = M_Arround(fN);
		}
		qsort((*_a_HITab) , p_stBFI -> dwNbOccur , sizeof(tdstHeaderInfo) , fn_iCompareHeaderInfo);
	}

	/*
	{
		for (DWORD dwN = 0 ; dwN < *_p_dwTotalOccur ; dwN++)
		{
			CString csText;

			(*_a_HITab) [dwN] . dwOccur = dwN;
			(*_a_HITab) [dwN] . dwOffSet = (dwN+1) * *_p_dwHeaderStep * M_SECTOR_SIZE;
		}
	}
	*/

	M_LIST(IDC_LIST_WORK) -> AddString ("\t\tVerify Headers positions");
	{
		for (DWORD dwN = 0 ; dwN < p_stBFI -> dwNbOccur - 1 ; dwN++)
		{
			//csText . Format ("\t%03d : Occur %03d - OffSet : 0x%08x" , dwN , (*_a_HITab) [dwN] . dwOccur , (*_a_HITab) [dwN] . dwOffSet );
			//M_LIST(IDC_LIST_WORK) -> AddString (csText);
			if( (*_a_HITab) [dwN] . dwOffSet + p_stBFI -> dwHeaderSize >= (*_a_HITab) [dwN+1] . dwOffSet)
			{
				m_csErrorMessage = "Recovering Header";
				return FALSE;
			}
		}
	}
	M_LIST(IDC_LIST_WORK) -> AddString ("\t\tHeaders positions Ok");

	/* -------------------------------------------------------------------------------------------------------------- */

	M_LIST(IDC_LIST_WORK) -> AddString ("\tMixUp Files and Headers");

	dwOffSet = p_stBFI -> dwFirstHeaderSize;
	dwHeaderNumber = 0;
	dwNextHeaderPos = (*_a_HITab) [dwHeaderNumber] . dwOffSet;

    for (DWORD dwIndex = 0 ; dwIndex < dwArraySize-1 ; dwIndex++)
    {
		BOOL bContinue = TRUE;
		while (bContinue)
		{
			DWORD dwRandomPosition	= PTC_fn_lGetRandomRange (dwIndex+1 , dwArraySize);
			DWORD dwNewPosition		= dwRandomPosition;
      
			// swap
			tdstMixUpInfo stMUITmp;
		
			// enough place ???
			while ((dwNewPosition < dwArraySize) && (dwOffSet + (*_a_MUITab)[dwNewPosition] . dwSize > dwNextHeaderPos))
			{
				dwNewPosition++;
			}
			if(dwNewPosition == dwArraySize)
			{
				dwNewPosition = dwRandomPosition;
				while ((dwNewPosition > dwIndex) && (dwOffSet + (*_a_MUITab)[dwNewPosition] . dwSize > dwNextHeaderPos))
				{
					dwNewPosition--;
				}
			}
			if (dwNewPosition != dwArraySize && dwNewPosition != dwIndex)
			{
				// found one

				stMUITmp                    = (*_a_MUITab)[dwIndex];
				(*_a_MUITab)[dwIndex]       = (*_a_MUITab)[dwNewPosition];
				(*_a_MUITab)[dwNewPosition] = stMUITmp;

				// compute OffSet
				(*_a_MUITab)[dwIndex] . dwOffSet = dwOffSet;
				//
				// increase OffSet
				dwOffSet += (*_a_MUITab)[dwIndex] . dwSize;
				//
				bContinue = FALSE;
			}
			else
			{
				// up to next Header;

				dwOffSet = dwNextHeaderPos + p_stBFI -> dwHeaderSize;
				dwHeaderNumber++;
				if (dwHeaderNumber < p_stBFI -> dwNbOccur)
				{
					 dwNextHeaderPos = (*_a_HITab) [dwHeaderNumber] . dwOffSet;
				}
				else
				{
					// no more header
					dwNextHeaderPos = 0xFFFFFFFF;
				}
			}
		}
    }
	// compute OffSet of last one
	(*_a_MUITab)[dwArraySize-1] . dwOffSet = dwOffSet;


	/////////////////////////////////
	/////////////////////////////////
	/////////////////////////////////
	/////////////////////////////////
	/////////////////////////////////
	/*
	if (m_bGenerateInfoFiles)
	{
		HANDLE hDebugFile = CreateFile ("BigFile.map" , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);
		DWORD dwW;

		p_stMUI    = *_a_MUITab;
		tdstMixUpInfo *p_stMUIEnd = *_a_MUITab + dwArraySize;
		dwCount = 0;

		dwOffSet = p_stBFI -> dwFirstHeaderSize;
		dwHeaderNumber = 0;
		dwNextHeaderPos = (*_a_HITab) [dwHeaderNumber] . dwOffSet;
		while (p_stMUI != p_stMUIEnd)
		{
			csText . Format ("%03d - OffSet : 0x%08x - Size : 0x%08x - End : 0x%08x - %s\x0D\x0A"
							, dwCount , p_stMUI -> dwOffSet , p_stMUI -> dwSize , p_stMUI -> dwOffSet + p_stMUI -> dwSize ,  p_stMUI -> p_cFileName);

			WriteFile (hDebugFile , (char*)(LPCTSTR)csText , csText . GetLength () , &dwW , NULL);
			p_stMUI++;
			dwCount++;
			while (p_stMUI -> dwOffSet > dwNextHeaderPos)
			{
				csText . Format ("===== Gap : 0x%08x\x0D\x0A" , dwNextHeaderPos - ((p_stMUI-1) -> dwOffSet + (p_stMUI-1) -> dwSize));
				WriteFile (hDebugFile , (char*)(LPCTSTR)csText , csText . GetLength () , &dwW , NULL);
				csText . Format ("\tOffSet : 0x%08x - Size : 0x%08x - End : 0x%08x - Header : %d\x0D\x0A"
								 , (*_a_HITab) [dwHeaderNumber] . dwOffSet , p_stBFI -> dwHeaderSize , (*_a_HITab) [dwHeaderNumber] . dwOffSet + p_stBFI -> dwHeaderSize , (*_a_HITab) [dwHeaderNumber] .dwOccur);
				WriteFile (hDebugFile , (char*)(LPCTSTR)csText , csText . GetLength () , &dwW , NULL);
				dwHeaderNumber++;
				if (dwHeaderNumber < p_stBFI -> dwNbOccur)
				{
					 dwNextHeaderPos = (*_a_HITab) [dwHeaderNumber] . dwOffSet;
				}
				else
				{
					// no more header
					dwNextHeaderPos = 0xFFFFFFFF;
				}
			}
		}
		CloseHandle (hDebugFile);
	}
	*/	
	/////////////////////////////////
	/////////////////////////////////
	/////////////////////////////////
	/////////////////////////////////
	/////////////////////////////////
	return TRUE;
}

//------------------------------------------------------------------------
//------------------------------------------------------------------------
BOOL CBigFileToolDlg::WriteBigFileWithExplodedHeader(char *_szDataPath , HANDLE hFile, CListOfFileInfo *_p_oFIList, tdstMixUpInfo *_a_MUITab, tdstBigFileInfo *p_stBFI, tdstHeaderInfo *_a_HITab)
{
	DWORD dwNumberOfMUI = p_stBFI -> dwNbOccur * p_stBFI -> dwNbFile;
	tdstMixUpInfo *p_stMUI    = _a_MUITab;
	tdstMixUpInfo *p_stMUIEnd = _a_MUITab + dwNumberOfMUI;
	char szFileName[MAX_PATH];
	char *p_cBeginFileName;
	DWORD dwRead , dwWritten;
	char szText[255];
	HANDLE hDebugFile;
	DWORD dwW,dwCount;
    DWORD dwOffSet;
	unsigned char a_ucKeys[4];
	unsigned char a_ucCode[4];
	unsigned char a_ucProtection[4];
	DWORD *p_dwKey = (DWORD*)a_ucKeys;
	DWORD *p_dwProtection = (DWORD*)a_ucProtection;
	DWORD dwNextHeaderPos , dwHeaderNumber;

	M_LIST(IDC_LIST_WORK) -> AddString ("");
	M_LIST(IDC_LIST_WORK) -> AddString ("Write files");
	M_LIST(IDC_LIST_WORK) -> AddString ("");

	m_Ctrl_ProgressBar . SetRange (0 , dwNumberOfMUI + p_stBFI -> dwNbOccur);
	m_Ctrl_ProgressBar . SetPos (0);
	m_Ctrl_ProgressBar . SetStep (1);

	strcpy (szFileName , _szDataPath);
	p_cBeginFileName = szFileName + strlen (_szDataPath);

	HGLOBAL hMem = GlobalAlloc (GHND , p_stBFI -> dwMaxFileSize + 4 + 4);
	
	char *p_Buffer = (char*) GlobalLock (hMem);
	char *p_Begin;

	////////////////////////////////////////////////
	// compute all headers
	////////////////////////////////////////////////
	DWORD *a_OffSet = (DWORD*)  malloc (dwNumberOfMUI*4);
	DWORD *p_dwEndHeader = a_OffSet + (dwNumberOfMUI);

	while (p_stMUI != p_stMUIEnd)
	{
		//
		DWORD dwIndex = p_stBFI -> dwNbOccur * p_stMUI -> dwMapNumber + p_stMUI -> dwOccur;
        a_OffSet [ dwIndex ] = p_stMUI -> dwOffSet ;
	
		// next
		p_stMUI++;
	}

	if (m_bGenerateInfoFiles)
	{
		char szText[255];
		HANDLE hDebugFile = CreateFile ("BigFile.txt" , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);
		DWORD dwMap , dwOcc, dwW;

		for (dwOcc = 0 ; dwOcc < p_stBFI -> dwNbOccur ; dwOcc++)
		{
			sprintf (szText , "==============================================================================\x0D\x0A");
			WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

			for (dwMap = 0 ; dwMap < p_stBFI -> dwNbFile ; dwMap+=4)
			{
				DWORD dwIndex = p_stBFI -> dwNbOccur * dwMap + dwOcc;

				sprintf (szText , "Map : %02d : Occur %02d : 0x%08x  -  0x%08x  -  0x%08x  -  0x%08x\x0D\x0A" , dwMap >> 2 , dwOcc , a_OffSet [dwIndex] , a_OffSet [dwIndex + p_stBFI -> dwNbOccur] ,a_OffSet [dwIndex + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur] ,a_OffSet [dwIndex + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur]);
				WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
			}
		}
		sprintf (szText , "==============================================================================\x0D\x0A");
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

		CloseHandle (hDebugFile);
	}

	////////////////////////////////////////////////
	// Write First Header : Keys (4) + MapNumber (1) + OccurNumber (1) + HeaderStep (1) + FirstHeaderSize (1) + File Step (1) + SectorSize (1)
	////////////////////////////////////////////////
	if (m_bGenerateInfoFiles)
	{
		hDebugFile		= CreateFile ("BigFile.log" , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL);
		dwOffSet = 0;
		dwCount = 0;
	}	
	
	DWORD dwKeys[4];

	DWORD *p_dwCurrentPos = (DWORD*)p_Buffer;

	dwOffSet = 0;

	// compute keys
	for (int i=0 ; i<4 ; i++ )
	{
		dwKeys[i] = PTC_fn_lGetRandom();
		*p_dwCurrentPos++ = dwKeys[i];
		dwOffSet += 4;
	}
	
	// fill Debug File
	if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)
	{
		sprintf (szText , "First Header : Crypt-key : 0x%08x - 0x%08x - 0x%08x - 0x%08x\x0D\x0A" , dwKeys[0] , dwKeys[1] , dwKeys[2] , dwKeys[3]);
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);
		sprintf (szText , "MapNumber : %d : OccurNumber : %d : Header Step : 0x%08x\x0D\x0A" , p_stBFI -> dwNbFile , p_stBFI -> dwNbOccur , p_stBFI -> dwHeaderStep * M_SECTOR_SIZE);
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);
		sprintf (szText , "First Header Size : 0x%08x - File Step : 0x%08x - Header Size : 0x%08x - Sector Number : 0x%08x\x0D\x0A"
						, p_stBFI -> dwFirstHeaderSize , 0 , p_stBFI -> dwHeaderSize , p_stBFI -> dwTotalSector); 
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

		sprintf (szText , "==============================================================================\x0D\x0A");
		WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
	}

	// Add number of map
	*p_dwCurrentPos++ = (p_stBFI -> dwNbFile ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Add number of Occur
	*p_dwCurrentPos++ = (p_stBFI -> dwNbOccur ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Add Header Step
	*p_dwCurrentPos++ = ((p_stBFI -> dwHeaderStep * M_SECTOR_SIZE) ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Add First Header Size
	*p_dwCurrentPos++ = (p_stBFI -> dwFirstHeaderSize ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Add File Step
	*p_dwCurrentPos++ = (0 ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Add Header size
	*p_dwCurrentPos++ = (p_stBFI -> dwHeaderSize ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Add Sector Number
	*p_dwCurrentPos++ = (p_stBFI -> dwTotalSector ^ dwKeys[1]) + dwKeys[0];
	dwOffSet += 4;
	dwKeys[0] += dwKeys[2];
	dwKeys[1] += dwKeys[3];

	// Fill to align to Sector Size
	while (dwOffSet < p_stBFI -> dwFirstHeaderSize)
	{
		*p_dwCurrentPos++ = PTC_fn_lGetRandom();
		dwOffSet += 4;
	}
	WriteFile (hFile , p_Buffer , p_stBFI -> dwFirstHeaderSize , &dwOffSet , NULL);

	////////////////////////////////////////////////
	// Write Files and Occur Header
	////////////////////////////////////////////////
	dwHeaderNumber = 0;
	dwNextHeaderPos = _a_HITab [dwHeaderNumber] . dwOffSet;

	p_stMUI    = _a_MUITab;
	while (p_stMUI != p_stMUIEnd)
	{
		tdstFileInfo *p_stFI = _p_oFIList -> GetAt (p_stMUI -> xFileInfoPosition);

		if(p_stMUI -> dwOffSet != dwOffSet)
		{
			m_csErrorMessage = p_stMUI -> dwOffSet < dwOffSet ? "Recovering blocs" : "Unwanted gap";
			return FALSE;
		}


		// compute crypt int-key
		a_ucCode[0] = (unsigned char) (p_stMUI -> dwMapNumber >> 2);
		a_ucCode[1] = (unsigned char) (p_stMUI -> dwMapNumber % 4);
		a_ucCode[2] = (unsigned char) (p_stMUI -> dwOccur & 0x000000FF);
		a_ucCode[3] = ~a_ucCode[2];

		// compute crypt key
		*p_dwKey		= PTC_fn_lGetCryptKey (*(DWORD*)a_ucCode);

		// compute protection key
		*p_dwProtection = PTC_fn_lGetProtectionKey (*(DWORD*)a_ucCode);

		// copy Protect key to buffer
		memcpy (p_Buffer , p_dwProtection , 4);
		
		// open Source file
		strcpy (p_cBeginFileName , p_stFI -> szFileName);

		// fill Debug File
		if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)
		{
			sprintf (szText , "%03d - OffSet : 0x%08x - init-key : 0x%02x%02x%02x%02x => crypt-key : 0x%08x => protect-key : 0x%08x - Map : %s\x0D\x0A"
							, dwCount++ , dwOffSet , a_ucCode[0] , a_ucCode[1] , a_ucCode[2] , a_ucCode[3]  , *p_dwKey , *p_dwProtection , p_cBeginFileName );
			WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
		}

		HANDLE hSourceFile = CreateFile ( szFileName, GENERIC_READ , 0 , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL);

		// Copy File
		// Read initial file
		ReadFile (hSourceFile , p_Buffer + 4 , p_stFI -> dwSize + 1 , &dwRead , NULL);
		CloseHandle (hSourceFile);

		dwRead += 4;	// protect key size

		// crypt buffer
		unsigned char *p_ucBeginBuffer = (unsigned char*)p_Buffer;
		unsigned char *p_ucEndBuffer   = (unsigned char*)p_Buffer + dwRead;

		while (p_ucBeginBuffer != p_ucEndBuffer)
		{
			*p_ucBeginBuffer = (*p_ucBeginBuffer ^ a_ucKeys[1]) + a_ucKeys[0];
			a_ucKeys[0] += a_ucKeys[2];
			a_ucKeys[1] += a_ucKeys[3];
			p_ucBeginBuffer++;
		}

		p_Begin = p_Buffer + dwRead;
		
		// Fill to long alignment
		while (dwRead % 4)
		{
			*p_Begin = (unsigned char) PTC_fn_lGetRandomRange (0, 255);
			p_Begin++;
			dwRead++;
		}

		// Fill to align to sector size
		while (dwRead < p_stMUI -> dwSize)
		{
			DWORD dwRandom = PTC_fn_lGetRandom();
			memcpy (p_Begin , &dwRandom , 4);
			p_Begin += 4;
			dwRead += 4;
		}

		// write buffer
		WriteFile(hFile , p_Buffer , p_stMUI -> dwSize , &dwWritten , NULL);

		m_Ctrl_ProgressBar . StepIt ();

		dwOffSet += p_stMUI -> dwSize;

		// next
		p_stMUI++;

		// Message Pump
		PeekAndPump ();

		while (p_stMUI -> dwOffSet > dwNextHeaderPos)
		{
			// fill to next Header Position
			DWORD dwSize = 0;
			while (dwOffSet < dwNextHeaderPos)
			{
				DWORD dwValue = PTC_fn_lGetRandom();
				WriteFile (hFile , &dwValue , 4 , &dwWritten , NULL);
				dwOffSet += 4;
				dwSize += 4;
			}

			// write next Header
			DWORD dwKeys[4];

			p_dwCurrentPos = (DWORD*)p_Buffer;

			// compute keys
			for (int i=0 ; i<4 ; i++ )
			{
				dwKeys[i] = PTC_fn_lGetRandom();
				*p_dwCurrentPos++ = dwKeys[i];
			}

			// fill Debug File
			if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)
			{
				sprintf (szText , "==============================================================================\x0D\x0A");
				WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

				sprintf (szText , "OffSet : 0x%08x - Header %03d - crypt-key : 0x%08x - 0x%08x - 0x%08x - 0x%08x\x0D\x0A" , dwOffSet , _a_HITab [dwHeaderNumber] . dwOccur , dwKeys[0] , dwKeys[1] , dwKeys[2] , dwKeys[3]);
				WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	

				sprintf (szText , "==============================================================================\x0D\x0A");
				WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
			}

			// Write OffSet
			DWORD dwIndex = _a_HITab [dwHeaderNumber] . dwOccur;
			DWORD dwMyCount = 0;
			while (dwIndex < dwNumberOfMUI)
			{
				*p_dwCurrentPos++ = (a_OffSet [dwIndex] ^ dwKeys[1]) + dwKeys[0];
				dwKeys[0] += dwKeys[2];
				dwKeys[1] += dwKeys[3];

				if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE && !(dwMyCount % 4))
				{
					sprintf (szText , "\t%03d - 0x%08x - 0x%08x - 0x%08x - 0x%08x\x0D\x0A" , dwMyCount / 4 , a_OffSet [dwIndex] , a_OffSet [dwIndex + p_stBFI -> dwNbOccur] , a_OffSet [dwIndex + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur] , a_OffSet [dwIndex + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur + p_stBFI -> dwNbOccur]);
					WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);
				}

				dwIndex += p_stBFI -> dwNbOccur;
				dwMyCount += 1;
			}
			if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)
			{
				sprintf (szText , "==============================================================================\x0D\x0A");
				WriteFile (hDebugFile , szText , strlen(szText) , &dwW , NULL);	
			}
			if (dwMyCount != p_stBFI -> dwNbFile)
			{
				m_csErrorMessage = "Bad Header Size";
				return FALSE;
			}
			p_dwEndHeader = (DWORD*)(p_Buffer + p_stBFI -> dwHeaderSize);

			// align to Sector Size
			while (p_dwCurrentPos < p_dwEndHeader)
			{
				*p_dwCurrentPos++ = PTC_fn_lGetRandom();
			}

			// write on file
			WriteFile (hFile , p_Buffer , p_stBFI -> dwHeaderSize , &dwWritten , NULL);

			m_Ctrl_ProgressBar . StepIt ();

			dwOffSet = dwNextHeaderPos + p_stBFI -> dwHeaderSize;

			// compute next Header pos
			dwHeaderNumber++;
			if (dwHeaderNumber < p_stBFI -> dwNbOccur)
			{
				dwNextHeaderPos = _a_HITab [dwHeaderNumber] . dwOffSet;
			}
			else
			{
				// no more header
				dwNextHeaderPos = 0xFFFFFFFF;
			}
		}
	}
	GlobalUnlock (hMem);
	GlobalFree (hMem);

	if (m_bGenerateInfoFiles && hDebugFile != INVALID_HANDLE_VALUE)			CloseHandle (hDebugFile);

	m_Ctrl_ProgressBar . SetPos (0);
	free (a_OffSet);

	return TRUE;
}
