// HalSIS.cpp: CHalSIS クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "afxpriv.h"
// directory handling
#include <shlwapi.h>   //PathIsDirectoryA
#include <imagehlp.h>  //MakeSureDirectoryPathExists

#include "HalSIS.h"
#include "zlib.h"

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

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CHalSIS::CHalSIS()
{
	InitParameters();
}

// copy constructor. NOTE: could be removed
CHalSIS::CHalSIS(CHalSIS* pParams)
{
	InitParameters();

	*this = *pParams;
	
	pParams->m_sisFilePtr = NULL;
	pParams->m_pPackage = NULL;
}


CHalSIS::CHalSIS(const char* strSISFileName, const char* strDstDirectory)
{
	InitParameters();
	
	strcpy(m_sisFileName, strSISFileName);
	strcpy(m_dstDirectoryName, strDstDirectory);
}

CHalSIS::~CHalSIS()
{
	if(m_sisFilePtr)
	{
		fclose(m_sisFilePtr);
	}
	if(m_pPackage)
	{
		delete [] m_pPackage;
	}
}

void CHalSIS::InitParameters()
{
	m_installDriveSetting = HALSIS_DEFAULT_INSTALL_DRIVE;
	m_sisFilePtr = NULL;
	m_pPackage = NULL;
	m_totalExtractedDataAmount = 0;
	m_PreferredLanguage = HALSIS_PREFERRED_LANGUAGE;
}

void CHalSIS::ReadHeaderTableFixedPart() // equivalent to fixHeaderTable
{
	if ((m_sisFilePtr = fopen(m_sisFileName, "rb")) == NULL)
	{
		throw "ReadHeaderTable: Could not open SIS file";
	}
	
	fseek(m_sisFilePtr, 0, SEEK_SET); // ensure pointing the file head
	fread(m_headerBuffer, 1, SIS_HEADER_SIZE, m_sisFilePtr);
	
	// version validation
	if(m_headerBuffer[CONFIRM_INSTALLER_OFFSET] != CONFIRM_INSTALLER_VER){
		throw "ReadHeaderTable: This is not a Symbian SIS File !!";
	}
	
	m_UID0 = getNumberFromArray(m_headerBuffer, 0x00, 4);
	m_UID1 = getNumberFromArray(m_headerBuffer, 0x04, 4);
	m_UID2 = getNumberFromArray(m_headerBuffer, 0x08, 4);
	m_UIDCheckSum = getNumberFromArray(m_headerBuffer, 0x0C, 4);
	m_SISCheckSum = getNumberFromArray(m_headerBuffer, 0x10, 2);
	m_LanguageCount = getNumberFromArray(m_headerBuffer, 0x12, 2);
	m_FileCount = getNumberFromArray(m_headerBuffer, 0x14, 2);
	m_Dependency = getNumberFromArray(m_headerBuffer, 0x16, 2);
	m_LanguageUsed = getNumberFromArray(m_headerBuffer, 0x18, 2);
	m_NumberOfFilesAlreadyInstalled = getNumberFromArray(m_headerBuffer, 0x1A, 2);
	m_InstallDrive = getNumberFromArray(m_headerBuffer, 0x1C, 2);
	m_Capabilities = getNumberFromArray(m_headerBuffer, 0x1E, 2);
	m_InstallerVersion = getNumberFromArray(m_headerBuffer, 0x20, 4);
	m_Flags = getNumberFromArray(m_headerBuffer, 0x24, 2);
	m_Type = getNumberFromArray(m_headerBuffer, 0x26, 2);
	
	m_Version0 = getNumberFromArray(m_headerBuffer, 0x28, 2);
	m_Version1 = getNumberFromArray(m_headerBuffer, 0x2A, 2);
	m_Version2 = getNumberFromArray(m_headerBuffer, 0x2C, 4);
	
	m_LanguageOffset = getNumberFromArray(m_headerBuffer, 0x30, 4);
	m_PackageFilesOffset = getNumberFromArray(m_headerBuffer, 0x34, 4);
	m_DependenciesOffset = getNumberFromArray(m_headerBuffer, 0x38, 4);
	m_CertificatesOffset = getNumberFromArray(m_headerBuffer, 0x3C, 4);
	m_AppNamesOffset = getNumberFromArray(m_headerBuffer, 0x40, 4);
	m_SignatureOffset = getNumberFromArray(m_headerBuffer, 0x44, 4);
	m_CapabilityOffset = getNumberFromArray(m_headerBuffer, 0x48, 4);
	m_SpaceUsed = getNumberFromArray(m_headerBuffer, 0x4C, 4);
	m_MaxInstallSize = getNumberFromArray(m_headerBuffer, 0x50, 4);
	
	// get m_SelectedLanguageIndex
	unsigned char workBuffer[4];
	
	fseek(m_sisFilePtr, m_LanguageOffset, SEEK_SET);
	for(int i = 0; i < m_LanguageCount; i++){
		fread(workBuffer, 1, 2, m_sisFilePtr);
		m_Languages[i] = getNumberFromArray(workBuffer, 0, 2);
	}
	setLanguageIndex(m_PreferredLanguage); // set m_SelectedLanguageIndex but it can be changed later
}

void CHalSIS::ReadHeaderTableDependencyPart()
{
	unsigned char workBuffer[4];

	// get m_AppName
	fseek(m_sisFilePtr, m_AppNamesOffset, SEEK_SET);
	for(int i = 0;i < m_LanguageCount;i++){
		fread(workBuffer, 1, 4, m_sisFilePtr);
		if (i == m_LanguageCount - 1){
			m_SisLength = getNumberFromArray(workBuffer, 0, 4);
		}
		if (i == m_SelectedLanguageIndex){
			m_AppNameLength = getNumberFromArray(workBuffer, 0, 4);
			// "break" statement should not be put here.
		}
	}
	
	for(i = 0;i < m_LanguageCount;i++){
		fread(workBuffer, 1, 4, m_sisFilePtr);
		if (i == m_LanguageCount - 1){
			m_SisOffset = getNumberFromArray(workBuffer, 0, 4);
		}
		if (i == m_SelectedLanguageIndex){
			m_AppNameOffset = getNumberFromArray(workBuffer, 0, 4);
			// "break" statement should not be put here.
		}
	}
	
	// read application name
	unsigned char byteBfr[MAX_PATH*2];
	memset(byteBfr, 0, MAX_PATH * 2);
	fseek(m_sisFilePtr, m_AppNameOffset, SEEK_SET);
	fread(byteBfr, 1, m_AppNameLength, m_sisFilePtr);
	convByte2Wchar(m_AppName, byteBfr, m_AppNameLength);
}

void CHalSIS::ReadPackageInfo()
{
	unsigned char workBuffer[4];
	int i,j;
	
	m_pPackage = new HalSISPackage[m_FileCount];
	memset(m_pPackage, 0, sizeof(HalSISPackage) * m_FileCount);
	
	fseek(m_sisFilePtr, m_PackageFilesOffset, SEEK_SET);
	
	for(i = 0;i < m_FileCount; i++){
		
		fread(workBuffer, 1, 4, m_sisFilePtr);
		m_pPackage[i].m_packageType = getNumberFromArray(workBuffer, 0, 4);
		
		switch (m_pPackage[i].m_packageType){
		case 0:
		case 1:
			
			// File Type
			fread(workBuffer, 1, 4, m_sisFilePtr);
			m_pPackage[i].m_FileInfo_type = getNumberFromArray(workBuffer, 0, 4);
			
			// File Options
			fread(workBuffer, 1, 4, m_sisFilePtr);
			m_pPackage[i].m_FileInfo_option = getNumberFromArray(workBuffer, 0, 4);
			
			//
			// Make source file name
			//
			fread(workBuffer, 1, 4, m_sisFilePtr);
			m_pPackage[i].m_FileInfo_srcFileNameLength = getNumberFromArray(workBuffer, 0, 4);
			
			fread(workBuffer, 1, 4, m_sisFilePtr);
			m_pPackage[i].m_FileInfo_srcFileNamePointer = getNumberFromArray(workBuffer, 0, 4);
			
			//
			// Make desitination file name 
			//
			fread(workBuffer, 1, 4, m_sisFilePtr);
			m_pPackage[i].m_FileInfo_dstFileNameLength = getNumberFromArray(workBuffer, 0, 4);
			
			fread(workBuffer, 1, 4, m_sisFilePtr);
			m_pPackage[i].m_FileInfo_dstFileNamePointer = getNumberFromArray(workBuffer, 0, 4);
			
			// Attn: Should put on handling of "Multiple Language version "
			
			if (m_pPackage[i].m_packageType){
				m_pPackage[i].m_languageCount = m_LanguageCount;
				m_pPackage[i].m_selectedLanguageIndex = m_SelectedLanguageIndex;
			}
			else{
				m_pPackage[i].m_languageCount = 1;
				m_pPackage[i].m_selectedLanguageIndex = 0;
			}
			
			for(j = 0; j < m_pPackage[i].m_languageCount;j++){
				fread(workBuffer, 1, 4, m_sisFilePtr);
				m_pPackage[i].m_FileInfo_compressedSize[j] = getNumberFromArray(workBuffer, 0, 4);
			}
			
			for(j = 0; j < m_pPackage[i].m_languageCount;j++){
				fread(workBuffer, 1, 4, m_sisFilePtr);
				m_pPackage[i].m_FileInfo_offset[j] = getNumberFromArray(workBuffer, 0, 4);
			}
			
			for(j = 0; j < m_pPackage[i].m_languageCount;j++){
				fread(workBuffer, 1, 4, m_sisFilePtr);
				m_pPackage[i].m_FileInfo_originalSize[j] = getNumberFromArray(workBuffer, 0, 4);
			}
			
			// Unknown
			fread(workBuffer, 1, 4, m_sisFilePtr);
			
			// End of names pointer
			fread(workBuffer, 1, 4, m_sisFilePtr);
			
			break;
			
		case 2:
			{
			int pkgType2_numOfOptions = 0;
			fread(workBuffer, 1, 4, m_sisFilePtr);
			pkgType2_numOfOptions = getNumberFromArray(workBuffer, 0, 4);

			// skip option strings
			fseek(m_sisFilePtr, pkgType2_numOfOptions * m_LanguageCount * 4 * 2, SEEK_CUR);
			// skip selected options
			fseek(m_sisFilePtr, 4 * 4, SEEK_CUR);
			}
			break;
			
		case 3:
		case 4:
			{
			int pkgType3_4_size = 0;
			fread(workBuffer, 1, 4, m_sisFilePtr);
			pkgType3_4_size = getNumberFromArray(workBuffer, 0, 4);

			fseek(m_sisFilePtr, pkgType3_4_size, SEEK_CUR);
			}
			break;
			
		case 5:
		case 6:
			// Do nothing
			break;
			
		default:
			throw "ReadPackageInfo: Unknown package type";
			break;
		}
	}
	

	// Dependencies
	//fseek(m_sisFilePtr, m_DependenciesOffset, SEEK_SET);


	// Read src/dstFileName
	unsigned char fnameBfr[MAX_PATH*2];
	wchar_t wcBfr[MAX_PATH];
	int pos = 0;
	for(i = 0;i < m_FileCount; i++){
		memset(wcBfr, 0, sizeof(wchar_t) * MAX_PATH);
		fseek(m_sisFilePtr, m_pPackage[i].m_FileInfo_srcFileNamePointer, SEEK_SET);
		fread(fnameBfr, 1, m_pPackage[i].m_FileInfo_srcFileNameLength, m_sisFilePtr);
		convByte2Wchar(wcBfr, fnameBfr, m_pPackage[i].m_FileInfo_srcFileNameLength);
		// cut redundant path
		pos = scanWcharFromEnd(wcBfr, 0x5C);
		if(wcBfr[pos] == 0x5C){
			pos++; // backslash should be stripped.
		}
		wcscpy(m_pPackage[i].m_FileInfo_srcFileName, wcBfr + pos);
		
		fseek(m_sisFilePtr, m_pPackage[i].m_FileInfo_dstFileNamePointer, SEEK_SET);
		fread(fnameBfr, 1, m_pPackage[i].m_FileInfo_dstFileNameLength, m_sisFilePtr);
		convByte2Wchar(m_pPackage[i].m_FileInfo_dstFileName, fnameBfr, m_pPackage[i].m_FileInfo_dstFileNameLength);

	}
	
	return;
}

int CHalSIS::ExtractPackage(HalSISPackage* pPkg)
{
	int targetFileDataAmount = 0; // Return value of this function.
	FILE *createdFilePtr = NULL;
	char targetAbsolutePath[MAX_PATH];
	char targetRelativePath[MAX_PATH];
	int embededSISFlag = 0; // initialised to FALSE
	
	// init buffers
	memset(targetAbsolutePath, 0, MAX_PATH);
	memset(targetRelativePath, 0, MAX_PATH);
	
	/*-----------------------------------------
	* create file name and make directory
	*-----------------------------------------*/
	if(pPkg->m_FileInfo_type == 2 || pPkg->m_FileInfo_type == 6 || pPkg->m_FileInfo_type == 7){
		// embeded SIS file
		// set desctination root directory to put generated SIS file
		strcpy(targetAbsolutePath, m_dstDirectoryName);
		
		if(targetAbsolutePath[strlen(targetAbsolutePath) - 1] != 0x5C /*backslash*/){
			strcat(targetAbsolutePath, "\\");
		}

		// get embeded SIS file name
		if(wcstombs(targetRelativePath, pPkg->m_FileInfo_srcFileName, MAX_PATH) < 0)
		{
			throw "ExtractPackage: Could not convert m_FileInfo_srcFileName from wchar_t to char!!";
		}
		// set absolute path
		strcat(targetAbsolutePath, targetRelativePath);
		
		embededSISFlag = 1; // set it to TRUE
	}else {
		if(pPkg->m_FileInfo_dstFileNameLength             > 0 &&
			pPkg->m_FileInfo_compressedSize[pPkg->m_selectedLanguageIndex] > 0 &&
			pPkg->m_FileInfo_originalSize[pPkg->m_selectedLanguageIndex]   > 0 ){
			// File Creation		
			
			// install drive information handling
			char installDriveStr[2];
			char strBfr[16];

			if(wcstombs(strBfr, pPkg->m_FileInfo_dstFileName, 16) < 0)
			{
				throw "ExtractPackage: Could not convert m_FileInfo_dstFileName from wchar_t to char for install drive checking!!";
			}

			if((!strncmp(strBfr, "c:\\",3)) || (!strncmp(strBfr, "C:\\", 3)))
			{
				// If install drive is forced to C drive
				sprintf(installDriveStr, "C");
			}else if((!strncmp(strBfr, "e:\\",3)) || (!strncmp(strBfr, "E:\\",3)))
			{
				// If install drive is forced to E drive
				sprintf(installDriveStr, "E");
			}else /* if(!strncmp(strBfr, "!:\\",3)) */
			{
				// If install drive is set to "selectable" or unknown drive
				sprintf(installDriveStr, "%c", m_installDriveSetting); // set user defined drive
			}
			
			// get relative path
			// convert wchar_t to multibyte-charactor string
			if (wcstombs(targetRelativePath, pPkg->m_FileInfo_dstFileName + 2 /* skip first two charactors (i.e. drive info)*/, MAX_PATH) < 0)
			{
				throw "ExtractPackage: Could not convert m_FileInfo_dstFileName from wchar_t to char!!";
			}

			// Destination directory creation
			char targetRelativeDirPath[MAX_PATH];
			targetRelativeDirPath[0] = '\0'; // init string

			getDirectory(targetRelativeDirPath, targetRelativePath);
			
			strcpy(targetAbsolutePath, m_dstDirectoryName); // set base destination directory
			strcat(targetAbsolutePath, installDriveStr);
			strcat(targetAbsolutePath, targetRelativeDirPath);
			
			if (makeDirectory(targetAbsolutePath) < 0)
			{
				throw "ExtractPackage: Could not create dstAbsolutePath directory!!";
			}
			
			// File Name Creation
			targetAbsolutePath[0] = '\0'; // init string
			strcpy(targetAbsolutePath, m_dstDirectoryName); // set base destination directory
			strcat(targetAbsolutePath, installDriveStr);
			strcat(targetAbsolutePath, targetRelativePath);
		}
	}
	
	/*-----------------------------------------
	* open the target file and extract the file
	*-----------------------------------------*/
	if(strlen(targetAbsolutePath) > 0){
		if((createdFilePtr = fopen(targetAbsolutePath, "w+b")) == NULL){
			throw "ExtractPackage: Could not open m_FileInfo_dstFileName!!";
		}
		
		fseek(m_sisFilePtr, pPkg->m_FileInfo_offset[pPkg->m_selectedLanguageIndex], SEEK_SET);	
		// Extract data 
		if (pPkg->m_FileInfo_originalSize[pPkg->m_selectedLanguageIndex] != decompress(createdFilePtr, m_sisFilePtr, pPkg->m_FileInfo_compressedSize[pPkg->m_selectedLanguageIndex])){
			throw "ExtractPackage: Decompression failure !!";
		}
		targetFileDataAmount = pPkg->m_FileInfo_originalSize[pPkg->m_selectedLanguageIndex];
		fclose(createdFilePtr);
		
		/*-----------------------------------------
		* extract embeded SIS recursively
		*-----------------------------------------*/
		if(embededSISFlag){
			CHalSIS sis(targetAbsolutePath, m_dstDirectoryName);
			sis.m_installDriveSetting = m_installDriveSetting;
			sis.m_PreferredLanguage = m_Languages[m_SelectedLanguageIndex];
			sis.ExtractSIS();
			fclose(sis.m_sisFilePtr); sis.m_sisFilePtr = NULL;
			remove(targetAbsolutePath);
		}else{
			m_totalExtractedDataAmount += targetFileDataAmount; // embeded SIS data amount should not be counted.
		}
	}
	
	return targetFileDataAmount;
}

void CHalSIS::CreateInstallSIS()
{
	int i;
	unsigned char workBuffer[4];
	char installFileName[MAX_PATH];
	FILE *installFilePtr = NULL;
	
	// Install part creation
	// Install part file name creation

	// The name of current processing SIS file needs to be copied as install file name.
	int pos = scanCharFromEnd(m_sisFileName, 0x5C);
	if(m_sisFileName[pos] == 0x5C){
		pos++; // skip backslash
	}
	memset(installFileName, 0, MAX_PATH);
	strcpy(installFileName, m_sisFileName + pos);
	
	// Fixing Header Data array
	
	// Used Language
	m_headerBuffer[0x18] = m_Languages[m_SelectedLanguageIndex] & 0xFF;       // m_headerBuffer[0x12];
	m_headerBuffer[0x19] = (m_Languages[m_SelectedLanguageIndex] >> 8) & 0xFF;//m_headerBuffer[0x13];
	
	// File Count
	// Destination file counting routine will skip, if encountered non-Symbian file(s).
	// Make sure this action for further implementation !!
	m_headerBuffer[0x1A] = m_headerBuffer[0x14];
	m_headerBuffer[0x1B] = m_headerBuffer[0x15];
	
	// Drive letter Setting
	m_headerBuffer[0x1C] = m_installDriveSetting;
	
	// Install size
	for(i = 0;i < 4;i++){
		m_headerBuffer[0x4C + i] = (m_totalExtractedDataAmount >> (8 * i)) & 0xFF;
	}
	
	// Make destnation directory
	char dstPath[MAX_PATH];
	
	memset(dstPath, 0, MAX_PATH);
	strcpy(dstPath, m_dstDirectoryName); // destination root directory
#if defined(WIN32)
	char instDrive[3];
	sprintf(instDrive, "\\%c", m_installDriveSetting);
	strcat(dstPath, instDrive);
#endif
	strcat(dstPath, "\\system\\install\\");
	
	if(makeDirectory(dstPath) < 0)
	{
		throw "CreateInstallSIS: Could not create \\System\\install\\ directory!!";
	}
	
	// Make install file
	strcat(dstPath, installFileName);
	
	if((installFilePtr = fopen(dstPath, "w+b")) == NULL){
		throw "CreateInstallSIS: Could not open(i.e. create) install SIS file!!";
	}
	
	fwrite(m_headerBuffer, 1, m_PackageFilesOffset, installFilePtr);
	fseek(m_sisFilePtr, m_PackageFilesOffset, SEEK_SET);
	
//	for(i = m_PackageFilesOffset;i < (m_AppNameOffset + m_AppNameLength);i++){
	for(i = m_PackageFilesOffset;i < (m_SisOffset + m_SisLength);i++){
		fread(workBuffer, 1, 1, m_sisFilePtr);
		fwrite(workBuffer, 1, 1, installFilePtr);
	}
	
	fclose(installFilePtr);
}

int CHalSIS::ExtractSIS()
{
	ReadHeaderTableFixedPart();
	ReadHeaderTableDependencyPart();
	ReadPackageInfo();
	for(int i = 0; i < m_FileCount; i++)
	{
		ExtractPackage(&m_pPackage[i]);
	}
	CreateInstallSIS();
	
	return 0;
}

int CHalSIS::decompress(FILE *dstFilePtr, FILE *sisFilePtr, size_t dataLength)
{
	// Preparation of de-compression
	z_stream z;
	int zStatus   = Z_OK;
	size_t remainingDataAmount = 0;
	unsigned int srcBufSize = 0;
	unsigned char srcBuf[MCS_UNZIP_BUF_SIZE];
	unsigned int dstBufSize = 0;
	unsigned char dstBuf[MCS_UNZIP_BUF_SIZE];
	int dstDataAmount = 0;
	
	//char errStr[128];
	
	/* use zlib's memory management */
	z.zalloc = Z_NULL;
	z.zfree = Z_NULL;
	z.opaque = Z_NULL;
	
	/* z_stream initialization */
	z.next_in = Z_NULL;
	z.avail_in = 0;
	if (inflateInit(&z) != Z_OK) {
		//sprintf(errStr, "inflateInit: %s\n", (z.msg) ? z.msg : "???");
		throw("Decompress: inflateInit failed !!");
	}
	
	zStatus = Z_OK;
	remainingDataAmount = dataLength;
	while(remainingDataAmount > 0){
		srcBufSize = fread(srcBuf, 1, remainingDataAmount > MCS_UNZIP_BUF_SIZE ? MCS_UNZIP_BUF_SIZE : remainingDataAmount, sisFilePtr);
		
		// setup z_stream to inflate
		z.next_in   = srcBuf;
		z.avail_in  = srcBufSize;
		z.next_out  = dstBuf;
		z.avail_out = MCS_UNZIP_BUF_SIZE;
		
		while ((zStatus != Z_STREAM_END) && (z.avail_in != 0)) {
			zStatus = inflate(&z, Z_NO_FLUSH); /* de-compress */
			if (zStatus != Z_OK && zStatus != Z_STREAM_END) {	/* error */
				//sprintf(errStr, "inflate: %s\n", (z.msg) ? z.msg : "???");
				throw "Decompress: inflate error !!";
			}
			
			dstBufSize = MCS_UNZIP_BUF_SIZE - z.avail_out;
			if (fwrite(dstBuf, 1, dstBufSize, dstFilePtr) != dstBufSize) {
				//sprintf(errStr, "fwrite fails");
				throw "Decompress: fwrite error !!";
			}
			dstDataAmount += dstBufSize;
			
			z.next_out  = dstBuf;
			z.avail_out = MCS_UNZIP_BUF_SIZE;
		}
		
		remainingDataAmount -= srcBufSize;
		
		if (zStatus == Z_STREAM_END && remainingDataAmount != 0)
		{
			// skip padding data
			fseek(sisFilePtr, remainingDataAmount, SEEK_CUR);
			remainingDataAmount = 0;
		}
	}
	
	/* tidy up z_stream */
	if (inflateEnd(&z) != Z_OK) {
		//sprintf(errStr, "inflateEnd: %s", (z.msg) ? z.msg : "???");
		throw "Decompress: inflateEnd error!!";
	}
	
	return(dstDataAmount); // successful procedure end
}

int CHalSIS::getNumberFromArray(unsigned char *aTable, int aPositionOfArray, int aLength)
{
	switch (aLength){
	case 0:
		break;
	case 1:
		return aTable[aPositionOfArray];
		break;
	case 2:
		return (aTable[aPositionOfArray + 1] << 8) + aTable[aPositionOfArray];
		break;
	case 3:
		return (aTable[aPositionOfArray + 2] << 16) + (aTable[aPositionOfArray + 1] << 8) + aTable[aPositionOfArray];
		break;
	case 4:
		return (aTable[aPositionOfArray + 3] << 24) + (aTable[aPositionOfArray + 2] << 16) + (aTable[aPositionOfArray + 1] << 8) + aTable[aPositionOfArray];
		break;
	default:
		break;
	}
	return 0;
}

int CHalSIS::scanCharFromEnd(char *aTargetStrings, unsigned char aTargetChar)
{
	int i, strTargetLength, lastTargetPosition;
	
	strTargetLength = strlen(aTargetStrings);
	lastTargetPosition = 0;
	for(i = strTargetLength;i > 0;i--){
		if(aTargetStrings[i] == aTargetChar){
			lastTargetPosition = i;
			i = 0;	// Exit loop
		}
	}
	return lastTargetPosition;
}

int CHalSIS::scanWcharFromEnd(wchar_t *aTargetStrings, wchar_t aTargetChar)
{
	int i, strTargetLength, lastTargetPosition;
	
	strTargetLength = wcslen(aTargetStrings);
	lastTargetPosition = 0;
	for(i = strTargetLength;i > 0;i--){
		if(aTargetStrings[i] == aTargetChar){
			lastTargetPosition = i;
			i = 0;	// Exit loop
		}
	}
	return lastTargetPosition;
}


int CHalSIS::getDirectory(char *aCompletedDirectory, char *aSourceDirectory)
{
	int i, lastSeperatorPosition;
	
	lastSeperatorPosition = scanCharFromEnd(aSourceDirectory, 0x5C);
	
	for(i = 0;i <= lastSeperatorPosition;i++){
		aCompletedDirectory[i] = aSourceDirectory[i];
	}
	
	aCompletedDirectory[i] = 0x00;
	
	return i;
}

/*
* Function picks up wide charactor data from byte array in little endian order.
* mbstowcs cannot be used for this purpose.
*/
void CHalSIS::convByte2Wchar(wchar_t *pDst, unsigned char* pSrc, size_t srcLength)
{
	int offset = 0;
	
	while(srcLength > 0)
	{
		*(pDst++) = getNumberFromArray(pSrc, offset, 2);
		offset += 2;
		srcLength -= 2;
	}
	
	*pDst = 0x0000;
}


int CHalSIS::makeDirectory(const char *absolutePath)
{
#if defined(WIN32)
	int retValue = 1;
	char path[MAX_PATH];
	strcpy(path, absolutePath);
	
	if(PathIsDirectory(path) == FALSE){
		if(path[strlen(path)-1] != '\\'){
			strcat(path, "\\");
		}
		if(MakeSureDirectoryPathExists(path) == FALSE){
			retValue = -1;
		}
	}
	return retValue;
	
#else
#error The target is not WIN32. makeDirectory function needs to be implemented for the target.
#endif
	
}

int CHalSIS::setLanguageIndex(int preferredLanguage)
{
	int preferredIndex = -1;
	int britishIndex = -1;
	int americanIndex = -1;
	
	for(int i = 0; i < m_LanguageCount; i++){
		if(m_Languages[i] == preferredLanguage){
			preferredIndex = i;
		}else if(m_Languages[i] == 1 /* UK english */){
			britishIndex = i;
		}else if(m_Languages[i] == 10 /* American english */){
			americanIndex = i;
		}
	}

	m_SelectedLanguageIndex = 0; // set to default: 0.
	if(preferredIndex > 0){
		m_SelectedLanguageIndex = preferredIndex;
	}else if(britishIndex > 0){
		m_SelectedLanguageIndex = britishIndex;
	}else if(americanIndex > 0){
		m_SelectedLanguageIndex = americanIndex;
	}

	return m_SelectedLanguageIndex;
}
