imgtools/sisutils/src/pkgfileparser.cpp
author timothy.murphy@nokia.com
Thu, 25 Mar 2010 13:43:28 +0000
branchfix
changeset 408 a819f9223567
parent 0 044383f39525
child 590 360bd6b35136
permissions -rw-r--r--
fix: stop using "magic" numbers in string operations for the copyannofile2log feature fix: When using the copylogfromannofile workaround, extract the build ID and build duration and add to the log as these are useful for analysis. The log should now be identical to the stdout file. fix: Remove extra blank lines from output in copylogfromannofile mode.

/*
* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/


#include "sisutils.h"
#include "pkgfileparser.h"

// Parse options lookups
#define MAXTOKENLEN	30
struct SParseToken
{
	WCHAR pszOpt[MAXTOKENLEN];
	DWORD dwOpt;
};

const SParseToken KTokens[] =
{
	{L"if",		IF_TOKEN},
	{L"elseif",	ELSEIF_TOKEN},
	{L"else",	ELSE_TOKEN},
	{L"endif",	ENDIF_TOKEN},
	{L"exists",	EXISTS_TOKEN},
	{L"devprop",DEVCAP_TOKEN},
	{L"appcap",	APPCAP_TOKEN},
	{L"package",DEVCAP_TOKEN},
	{L"appprop",APPCAP_TOKEN},
	{L"not",	NOT_TOKEN},
	{L"and",	AND_TOKEN},
	{L"or",		OR_TOKEN},
	{L"type",	TYPE_TOKEN},
	{L"key",	KEY_TOKEN},
};
#define NUMPARSETOKENS (sizeof(KTokens)/sizeof(SParseToken))

/**
Constructor: PkgParser class
Initilize the parameters to data members.

@internalComponent
@released

@param aFile	- Name of the package script file
*/
PkgParser::PkgParser(String aFile) : iPkgFile(aFile), m_nLineNo(0)
{
}

/**
Destructor: PkgParser class
Deallocates the memory for data members

@internalComponent
@released
*/
PkgParser::~PkgParser()
{
	if(iPkgHandle != INVALID_HANDLE_VALUE)
	{
		::CloseHandle(iPkgHandle);
	}

	DeleteAll();
}

/**
OpenFile: Opens the package script file

@internalComponent
@released
*/
int PkgParser::OpenFile()
{
	iPkgHandle = ::CreateFileW(string2wstring(iPkgFile).data(),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	
	return (iPkgHandle != INVALID_HANDLE_VALUE) ? 1 : 0;
}

/**
GetEmbeddedSisList: Returns the embedded sis file list

@internalComponent
@released

@param embedSisList	- reference to sis file list structure
*/
void PkgParser::GetEmbeddedSisList(SISFILE_LIST& embedSisList)
{
	embedSisList = iEmbedSisFiles;
}

/**
GetInstallOptions: Returns the install options read from the package file

@internalComponent
@released

@param aOptions	- reference to the string list structure
*/
void PkgParser::GetInstallOptions(FILE_LIST& aOptions)
{
	aOptions = iInstallOptions;
}

/**
GetLanguageList: Returns the language list read from the package file

@internalComponent
@released

@param langList	- reference to the language list structure
*/
void PkgParser::GetLanguageList(LANGUAGE_LIST& langList)
{
	langList = iLangList;
}

/**
GetHeader: Returns the header details read from the package file

@internalComponent
@released

@param pkgHeader	- reference to the package header structure
*/
void PkgParser::GetHeader(PKG_HEADER& pkgHeader)
{
	pkgHeader = iPkgHeader;
}

/**
GetCommandList: Returns the package body details read from the package file

@internalComponent
@released

@param cmdList	- reference to the command list structure
*/
void PkgParser::GetCommandList(CMDBLOCK_LIST& cmdList)
{
	cmdList = iPkgBlock;
}

/**
ParsePkgFile: Parses the package file

@internalComponent
@released
*/
void PkgParser::ParsePkgFile()
{
	if(!OpenFile())
	{
		throw SisUtilsException((char*)iPkgFile.data(), "Could not open file");
	}

	GetNextChar();

	// skip unicode marker if present
	if(m_pkgChar==0xFEFF) GetNextChar();

	GetNextToken ();
	while(m_token!=EOF_TOKEN)
	{
		ParseEmbeddedBlockL();
		switch (m_token)
		{
		case '&':
			GetNextToken ();
			ParseLanguagesL();
			break;
		case '#':
			GetNextToken ();
			ParseHeaderL();
			break;
		case '%':
			GetNextToken ();
			ParseVendorNameL();
			break;
		case '=':
			GetNextToken ();
			ParseLogoL();
			break;
		case '(':
			GetNextToken ();
			ParseDependencyL();
			break;
		case ':':
			GetNextToken ();
			ParseVendorUniqueNameL();
			break;
		case '[':
			GetNextToken ();
			ParseTargetDeviceL();
			break;
		case EOF_TOKEN:
			break;
		default:
			ParserError("Unexpected token");
			break;
		}
	}
}

/**
ParseLanguagesL: Parses the language section

@internalComponent
@released
*/
void PkgParser::ParseLanguagesL()
{
	unsigned long langCode = 0;
	unsigned long dialect = 0;
	
	while (true)
	{
		if (m_token==ALPHA_TOKEN)
		{
			langCode = PkgLanguage::GetLanguageCode(m_tokenValue.pszString);
		}
		else if (m_token==NUMERIC_TOKEN && m_tokenValue.dwNumber>=0 && m_tokenValue.dwNumber<=1000)
		{
			langCode = (m_tokenValue.dwNumber);
		}

		GetNextToken ();

		// Check if a dialect is defined
		if (m_token == '(')
		{
			GetNumericToken();
			// Modify the last added language code, combining it with dialect code
			dialect = (m_tokenValue.dwNumber);
			GetNextToken ();
			GetNextToken ();
		}
		AddLanguage(wstring2string(PkgLanguage::GetLanguageName(langCode)), langCode, dialect);

		if (m_token!=',')
			return;
		GetNextToken ();
	}
}


/**
ParseHeaderL: Parses the package header section

@internalComponent
@released
*/
void PkgParser::ParseHeaderL()
{
	if (!iLangList.size())
	{
		//No languages defined, assuming English."
		AddLanguage("EN", PkgLanguage::ELangEnglish, 0);
	}
	
	// process application names
	ExpectToken('{');
	for (WORD wNumLangs = 0; wNumLangs < iLangList.size(); wNumLangs++)
	{
		GetNextToken ();
		ExpectToken(QUOTED_STRING_TOKEN);
		iPkgHeader.pkgNameList.push_back(wstring2string(m_tokenValue.pszString));
		GetNextToken ();
		if (wNumLangs < (iLangList.size()-1) )
		{
			ExpectToken(',');
		}
	}
	ExpectToken('}');
	GetNextToken (); 
	
	ExpectToken(',');
	GetNextToken ();
	ExpectToken('(');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.pkgUid = m_tokenValue.dwNumber;
	GetNextToken ();
	
	ExpectToken(')');
	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.vMajor = m_tokenValue.dwNumber;
	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.vMinor = m_tokenValue.dwNumber;
	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.vBuild = m_tokenValue.dwNumber;
	GetNextToken ();
	
	// Parse any options
	while (m_token==',')
	{
		GetNextToken ();
		if (m_token==TYPE_TOKEN)
		{
			GetNextToken ();
			ExpectToken('=');
			GetNextToken ();
			iPkgHeader.pkgType = wstring2string(m_tokenValue.pszString);
			GetNextToken ();
		}
		else
			GetNextToken ();
	}
}

/**
ParseEmbeddedBlockL: Parses the package body block

@internalComponent
@released
*/
void PkgParser::ParseEmbeddedBlockL ()
{
	while(m_token!=EOF_TOKEN)
	{
		switch (m_token)
		{
		case QUOTED_STRING_TOKEN:
			ParseFileL ();
			break;
		case '@':
			GetNextToken ();
			ParsePackageL ();
			break;
		case '!':
			GetNextToken ();
			ParseOptionsBlockL();
			break;
		case '+':
			GetNextToken ();
			ParsePropertyL ();
			break;
		case IF_TOKEN:
			GetNextToken ();
			ParseIfBlockL ();
			break;
		case ';' :
			ParseCommentL ();
			break;
		default :
			return;
		}
	}
}

/**
ParseFileL: Parses the file list section

@internalComponent
@released
*/
void PkgParser::ParseFileL()
{
	PCMD_BLOCK pCmdBlock = 0;
	PINSTALLFILE_LIST pFileList = 0;
	
	std::wstring sourceFile (m_tokenValue.pszString);
	
	// Linux and windows both support forward slashes so if source path is given '\' need to convert
	// in forward slash for compatibility.
	wchar_t *pBuffer = (wchar_t*)sourceFile.c_str();
	wchar_t *pCurrent = pBuffer;
	while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'\\')) != NULL)
	{
		*pCurrent = L'/';
		pBuffer = pCurrent + 1;
	}
	
	GetNextToken ();
	
	ExpectToken('-');
	GetNextToken ();
	
	ExpectToken(QUOTED_STRING_TOKEN);
	
	std::wstring destinationFile (m_tokenValue.pszString);
	
	// SWI only supports backward slashesh so need to convert destination path in backward slash if
	// user gives '/' in Linux.
	pBuffer = (wchar_t*)destinationFile.c_str();
	pCurrent = pBuffer;
	while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'/')) != NULL)
	{
		*pCurrent = L'\\';
		pBuffer = pCurrent + 1;
	}
	
	GetNextToken ();
	
	// Test for options
	if (m_token!=',')
	{
		pCmdBlock = new CMD_BLOCK;
		pFileList = new INSTALLFILE_LIST;

		pCmdBlock->cmdType = INSTALLFILE;
		pCmdBlock->iInstallFileList = pFileList;

		pFileList->langDepFlg = 0;
		pFileList->srcFiles.push_back(wstring2string(sourceFile));
		pFileList->destFile = wstring2string(destinationFile);

		iPkgBlock.push_back(pCmdBlock);
	}
	else
	{	
		bool needAdd = false;
		while(m_token==',')
		{
			GetNextToken ();
			std::wstring installOption = m_tokenValue.pszString;
			if((installOption == L"FF") || (installOption == L"FILE"))
			{
				needAdd = true;
			}
			GetNextToken ();
		}
		if (needAdd)
		{
			pCmdBlock = new CMD_BLOCK;
			pFileList = new INSTALLFILE_LIST;

			pCmdBlock->cmdType = INSTALLFILE;
			pCmdBlock->iInstallFileList = pFileList;

			pFileList->langDepFlg = 0;
			pFileList->srcFiles.push_back(wstring2string(sourceFile));
			pFileList->destFile = wstring2string(destinationFile);
		
			iPkgBlock.push_back(pCmdBlock);
		}
	}
}

/**
ParseIfBlockL: Parses the conditional installation body

@internalComponent
@released
*/
void PkgParser::ParseIfBlockL()
{
	PCMD_BLOCK pCmdBlock = 0; 

	//IF
	pCmdBlock = new CMD_BLOCK;
	pCmdBlock->cmdType = IF;
	ParseLogicalOp(pCmdBlock->cmdExpression);
	iPkgBlock.push_back(pCmdBlock);

	ParseEmbeddedBlockL ();
	
	while (m_token==ELSEIF_TOKEN)
	{
		GetNextToken ();
		//ELSEIF
		pCmdBlock = new CMD_BLOCK;
		pCmdBlock->cmdType = ELSEIF;
		ParseLogicalOp(pCmdBlock->cmdExpression);
		iPkgBlock.push_back(pCmdBlock);

		ParseEmbeddedBlockL ();
	}
	
	if (m_token==ELSE_TOKEN)
	{
		GetNextToken ();
		//ELSEIF
		pCmdBlock = new CMD_BLOCK;
		pCmdBlock->cmdType = ELSE;
		iPkgBlock.push_back(pCmdBlock);

		ParseEmbeddedBlockL ();
	}
	
	ExpectToken(ENDIF_TOKEN);
	//ENDIF
	pCmdBlock = new CMD_BLOCK;
	pCmdBlock->cmdType = ENDIF;
	iPkgBlock.push_back(pCmdBlock);

	GetNextToken ();
}

/**
ParseLogicalOp: Parses the logical expression

@internalComponent
@released
*/
void PkgParser::ParseLogicalOp (String& aExpression)
{
    ParseRelation (aExpression);
	switch (m_token)
	{
	case AND_TOKEN:
	case OR_TOKEN:
		{
			if (m_token==AND_TOKEN)
				aExpression.append(" && ");
			else
				aExpression.append(" || ");
			GetNextToken ();
			ParseLogicalOp (aExpression);
		}
		break;
	}
}

/**
ParseRelation: Parses the relational expression

@internalComponent
@released
*/
void PkgParser::ParseRelation(String& aExpression)
{
    ParseUnary (aExpression);
	switch (m_token)
	{
	case '=':
	case '>':
	case '<':
	case GE_TOKEN:
	case LE_TOKEN:
	case NE_TOKEN:
	case APPCAP_TOKEN:
		{
			switch (m_token)
			{
			case '=':
				aExpression.append(" == ");
				break;
			case '>':
				aExpression.append(" > ");
				break;
			case '<':
				aExpression.append(" < ");
				break;
			case GE_TOKEN:
				aExpression.append(" >= ");
				break;
			case LE_TOKEN:
				aExpression.append(" <= ");
				break;
			case NE_TOKEN:
				aExpression.append(" != ");
				break;
			case APPCAP_TOKEN:
				aExpression.append(" APPPROP ");
				break;
			}
			GetNextToken ();
			ParseUnary (aExpression);
			break;
		}
	}
}

/**
ParseUnary: Parses the unary expression

@internalComponent
@released
*/
void PkgParser::ParseUnary(String& aExpression)
{
    switch (m_token)
	{
	case NOT_TOKEN:
		aExpression.append(" !");
		GetNextToken ();
		ParseUnary (aExpression);
		break;
	case EXISTS_TOKEN:
	case DEVCAP_TOKEN:
		{	// 1 arg function
			int token=m_token;
			GetNextToken ();
			ExpectToken('(');
			GetNextToken ();
			if (token==EXISTS_TOKEN)
			{
				aExpression.append("EXISTS(\"");
				ExpectToken(QUOTED_STRING_TOKEN);
				GetNextToken ();
				aExpression.append(wstring2string(m_tokenValue.pszString));
				aExpression.append("\")");
			}
			else
			{
				aExpression.append("DEVCAP(");
				ParseUnary (aExpression);
				aExpression.append(")");
			}
			ExpectToken(')');
			GetNextToken ();
			break;
		}
	default:
		ParseFactor (aExpression);
		break;
	}
}

/**
ParseFactor: Parses the expression factor

@internalComponent
@released
*/
void PkgParser::ParseFactor(String& aExpression)
{
    switch (m_token) {
	case '(':
		{
			aExpression.append("(");
			GetNextToken ();
			ParseLogicalOp (aExpression);
			ExpectToken(')');
			aExpression.append(")");
		}
		break;
	case QUOTED_STRING_TOKEN:
	case ALPHA_TOKEN:
	case NUMERIC_TOKEN:
		{
			switch (m_token)
			{
			case QUOTED_STRING_TOKEN:
				aExpression.append("\"");
				aExpression.append(wstring2string(m_tokenValue.pszString));
				aExpression.append("\"");
				break;
			case ALPHA_TOKEN:
				if(!CompareNString(m_tokenValue.pszString,L"option",6))
				{
					aExpression.append(" defined(");
					aExpression.append(wstring2string(m_tokenValue.pszString));
					aExpression.append(") ");
				}
				else
				{
					aExpression.append(wstring2string(m_tokenValue.pszString));
				}
				break;
			case NUMERIC_TOKEN:
				{
					std::ostringstream str;

					str << "(0x" << std::setbase(16) << m_tokenValue.dwNumber << ")";
					aExpression.append(str.str());
				}
				break;
			}
		}
		break;
	default:
		ParserError("ErrBadCondFormat");
	}
	GetNextToken ();
}


/**
ParsePackageL: Parses the embedded package section

@internalComponent
@released
*/
void PkgParser::ParsePackageL()
{
	PCMD_BLOCK pCmdBlock = 0;
	int found = 0;

	ExpectToken(QUOTED_STRING_TOKEN);

	//if the sis file already exists then skip it
	SISFILE_LIST::iterator begin = iEmbedSisFiles.begin();
	SISFILE_LIST::iterator end = iEmbedSisFiles.end();

	while(begin != end)
	{
		if((*begin).compare(wstring2string(m_tokenValue.pszString)) == 0)
		{
			found = 1;
			break;
		}
		++begin;
	}

	if(!found)
	{
		iEmbedSisFiles.push_back(wstring2string(m_tokenValue.pszString));
	}
	
	//add as a command block as well
	{
		pCmdBlock = new CMD_BLOCK;

		pCmdBlock->cmdType = PACKAGE;
		pCmdBlock->iInstallFileList = 0;
		pCmdBlock->cmdExpression = wstring2string(m_tokenValue.pszString);

		iPkgBlock.push_back(pCmdBlock);
	}


	GetNextToken ();

	ExpectToken(',');
	GetNextToken ();
	ExpectToken('(');
	GetNextToken ();
	ExpectToken(NUMERIC_TOKEN);
	GetNextToken ();
	ExpectToken(')');
	GetNextToken ();
}

/**
ParseCommentL: Parses the comment section
  Parses a comment line (Does nothing, just throws the line away)

@internalComponent
@released
*/
void PkgParser::ParseCommentL()
{
	// parse to end of line
	while (m_pkgChar && (m_pkgChar!='\n')) GetNextChar();
	GetNextToken ();
}

/**
ParseOptionsBlockL: Parses the install options section

@internalComponent
@released
*/
void PkgParser::ParseOptionsBlockL()
{
	WORD wNumLangs;
	
	ExpectToken('(');
	GetNextToken ();
	
	for (;;)
	{
		ExpectToken('{');
		GetNextToken ();
		
		wNumLangs = 0;
		while (wNumLangs < iLangList.size())
		{
			ExpectToken(QUOTED_STRING_TOKEN);
			iInstallOptions.push_back(wstring2string(m_tokenValue.pszString));
			GetNextToken ();
			if (wNumLangs < iLangList.size() - 1)
			{
				ExpectToken(',');
				GetNextToken ();
			}
			wNumLangs++;
		}
		
		ExpectToken('}');
		GetNextToken ();
		if (m_token!=',') break;
		GetNextToken ();
	}
	
	ExpectToken(')');
	GetNextToken ();	
}

/**
ParsePropertyL: Parses the capability options section

@internalComponent
@released
*/
void PkgParser::ParsePropertyL()
{
	ExpectToken('(');
	do
	{
		GetNextToken ();
		
		ExpectToken(NUMERIC_TOKEN);
		GetNextToken ();
		ExpectToken('=');
		GetNextToken ();
		ExpectToken(NUMERIC_TOKEN);
		GetNextToken ();
	} while (m_token==',');
	ExpectToken(')');
	GetNextToken ();
}

/**
ParseVendorNameL: Parses the vendor options section

@internalComponent
@released
*/
void PkgParser::ParseVendorNameL()
{
	ExpectToken('{');
	for (WORD wNumLangs = 0; wNumLangs < iLangList.size(); wNumLangs++)
	{
		GetNextToken ();
		ExpectToken(QUOTED_STRING_TOKEN);
		GetNextToken ();
		if (wNumLangs < iLangList.size() -1 )
		{
			ExpectToken(',');
		}
	}
	ExpectToken('}');
	GetNextToken ();
}

/**
ParseLogoL: Parses the logo options section

@internalComponent
@released
*/
void PkgParser::ParseLogoL()
{
	ExpectToken (QUOTED_STRING_TOKEN);
	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	ExpectToken (QUOTED_STRING_TOKEN);
	GetNextToken ();
	if (m_token==',')
	{
		GetNextToken ();
		ExpectToken (QUOTED_STRING_TOKEN);
		GetNextToken ();
	}
}

/**
ParseVersion: Parses the version details

@internalComponent
@released
*/
void PkgParser::ParseVersion()
{
	GetNextToken();
	ExpectToken(NUMERIC_TOKEN);

	GetNextToken();
	ExpectToken(',');
	GetNextToken();
	ExpectToken(NUMERIC_TOKEN);

	GetNextToken();
	ExpectToken(',');
	GetNextToken();
	ExpectToken(NUMERIC_TOKEN);

	GetNextToken();
}

/**
ParseDependencyL: Parses the dependency package section

@internalComponent
@released
*/
void PkgParser::ParseDependencyL()
{
	ExpectToken(NUMERIC_TOKEN);
	GetNextToken ();
	ExpectToken(')');
	GetNextToken ();
	ExpectToken(',');

	ParseVersion();
	if (m_token == '~')
	{
		ParseVersion();
		ExpectToken(',');
	}
	
	GetNextToken ();
	ExpectToken('{');
	for (TUint numLangs = 0; numLangs < iLangList.size(); ++numLangs)
	{
		GetNextToken ();
		ExpectToken(QUOTED_STRING_TOKEN);
		GetNextToken ();
		if (numLangs < (iLangList.size() - 1))
			ExpectToken(',');
	}
	ExpectToken('}');
	GetNextToken ();
}

/**
ParseVendorUniqueNameL: Parses the vendor unique name section

@internalComponent
@released
*/
void PkgParser::ParseVendorUniqueNameL()
{
	ExpectToken(QUOTED_STRING_TOKEN);
	GetNextToken ();
}

/**
ParseTargetDeviceL: Parses the target device name section

@internalComponent
@released
*/
void PkgParser::ParseTargetDeviceL()
{
	ExpectToken(NUMERIC_TOKEN);
	GetNextToken ();
	ExpectToken(']');
	GetNextToken ();
	ExpectToken(',');
	
	ParseVersion();
	if (m_token == '~')
	{
		ParseVersion();
		ExpectToken(',');
	}
	GetNextToken ();
	ExpectToken('{');
	
	// must do this before adding language strings	
	for (TUint numLangs = 0; numLangs < iLangList.size(); ++numLangs)
	{
		GetNextToken ();
		ExpectToken(QUOTED_STRING_TOKEN);
		GetNextToken ();
		if (numLangs < (iLangList.size() - 1))
			ExpectToken(',');
	}
	ExpectToken('}');
	GetNextToken ();
}


/**
GetNextChar: Reads the next character from the package file

@internalComponent
@released
*/
void PkgParser::GetNextChar()
{
#ifdef WIN32
	DWORD dwBytesRead;
	if (!::ReadFile(iPkgHandle, (LPVOID)&m_pkgChar, sizeof(WCHAR), &dwBytesRead, NULL) ||
		dwBytesRead!=sizeof(wchar_t))
		m_pkgChar='\0';
#else
#error "TODO: Implement this function under other OS than Windows"
#endif
}

/**
ExpectToken: Tests the current token value

@internalComponent
@released

@param aToken - expected token value
*/
void PkgParser::ExpectToken(int aToken)
{
	if (m_token!=aToken)
	{
		ParserError("Unexpected Token");
	}
}

/**
GetNextToken: Reads the next valid token from the package file

@internalComponent
@released
*/
void PkgParser::GetNextToken ()
{
	// skip any white space & newLine's
	while (m_pkgChar == '\n' || isspace(m_pkgChar) || m_pkgChar == 0xA0)
	{
		if (m_pkgChar == '\n') ++m_nLineNo;
		GetNextChar();
	}
	
	if (m_pkgChar == '\0')
		m_token=EOF_TOKEN;
	else if (IsNumericToken())
	{
		GetNumericToken();
		m_token=NUMERIC_TOKEN;
	}
	else if (isalpha(m_pkgChar))
	{ // have some alphanumeric text
		GetAlphaNumericToken();
		m_token=ALPHA_TOKEN;
		// check if it is a keyword
		for(unsigned short wLoop = 0; wLoop < NUMPARSETOKENS; wLoop++)
		{
			if(CompareTwoString(m_tokenValue.pszString,(wchar_t*)KTokens[wLoop].pszOpt) == 0)
			{
				m_token=KTokens[wLoop].dwOpt;
				break;
			}
		}
	}
	else if (m_pkgChar == '\"')
	{ // have a quoted string
		GetStringToken();
		m_token=QUOTED_STRING_TOKEN;
	}
	else if (m_pkgChar == '>')
	{
		GetNextChar();
		if (m_pkgChar == '=')
		{
			m_token=GE_TOKEN;
			GetNextChar();
		}
		else
			m_token='>';
	}
	else if (m_pkgChar == '<')
	{
		// check if start of an escaped string, e.g. <123>"abc"
		if (GetStringToken())
			m_token=QUOTED_STRING_TOKEN;
		else
		{
			GetNextChar();
			if (m_pkgChar == '=')
			{
				m_token=LE_TOKEN;
				GetNextChar();
			}
			else if (m_pkgChar == '>')
			{
				m_token=NE_TOKEN;
				GetNextChar();
			}
			else
				m_token='<';
		}
	}
	else
	{
		m_token=m_pkgChar;
		GetNextChar();
	}
}

/**
GetStringToken: Reads the string token from the package file

@internalComponent
@released
*/
bool PkgParser::GetStringToken()
{
	DWORD wCount = 0;
	bool done=false;
	bool finished=false;
	DWORD escapeChars = 0;
	
	while (!finished)
	{
		if (m_pkgChar == '\"')
		{
			GetNextChar();
			while(m_pkgChar && m_pkgChar != '\"')
			{
				if(wCount < (MAX_STRING - 1))
					m_tokenValue.pszString[wCount++] = m_pkgChar;
				else //We dont want the string with length greater than MAX_STRING to be cut off silently
					ParserError("Bad String");
				GetNextChar();
			}
			if(m_pkgChar == '\0')
				ParserError("Bad String");
			GetNextChar();
			done=true;
		}
		if (m_pkgChar == '<')
		{
			m_tokenValue.pszString[wCount] = L'\0';
			escapeChars=ParseEscapeChars();
			if (escapeChars>0)
			{
				done=true;
				wCount+=escapeChars;
				if (wCount>=MAX_STRING) wCount=MAX_STRING-1;
			}
		}
		if (escapeChars==0 || m_pkgChar != '\"')
			finished=true;
	}
	
	m_tokenValue.pszString[wCount] = L'\0';
	return done;
}

/**
ParseEscapeChars: Parses the escape sequence characters

@internalComponent
@released
*/
WORD PkgParser::ParseEscapeChars()
{
	WORD found=0;
	WCHAR temp[MAX_STRING];
#ifdef WIN32
	while (m_pkgChar == '<')
	{
		wcscpy(temp,m_tokenValue.pszString);
		DWORD fileOffset=::SetFilePointer(iPkgHandle, 0L, NULL, FILE_CURRENT);
		try
		{
			GetNextChar();
			GetNumericToken();
			if (m_pkgChar=='>')
				found++;
			else
			{
				::SetFilePointer(iPkgHandle, fileOffset, NULL, FILE_BEGIN);
				break;
			}
		}
		catch (...)
		{
			wcscpy(m_tokenValue.pszString,temp);
			::SetFilePointer(iPkgHandle, fileOffset, NULL, FILE_BEGIN);
			break;
		}
		DWORD num=m_tokenValue.dwNumber;
		// watch for CP1252 escapes which aren't appropriate for UNICODE
		if (num>=0x80 && num<=0x9F) ParserError("Invalid Escape");
		DWORD len=wcslen(temp);
		wcscpy(m_tokenValue.pszString,temp);
		if (len+2<=MAX_STRING)
		{
			m_tokenValue.pszString[len]=(WCHAR)num;
			len++;
			m_tokenValue.pszString[len]='\0';
		}
		GetNextChar();
	}
#else
#error "TODO: Implement this function under other OS than Windows"
#endif 
	return found;
}

/**
GetAlphaNumericToken: Parse an alphanumeric string from the input line

@internalComponent
@released
*/
void PkgParser::GetAlphaNumericToken()
{
	WORD wCount = 0;
	while(m_pkgChar && (isalnum(m_pkgChar) || ((m_pkgChar) == '_')))
	{
		if(wCount < (MAX_STRING - 1))
			m_tokenValue.pszString[wCount++] = m_pkgChar;
		GetNextChar();
	}
	m_tokenValue.pszString[wCount] = L'\0';
}

/**
IsNumericToken: Determines if the next lexeme is a numeric token

@internalComponent
@released
*/
bool PkgParser::IsNumericToken()
{
	bool lexemeIsNumber = false;
	if (iswdigit(m_pkgChar))
		lexemeIsNumber = true;
	else if (m_pkgChar == '+' || m_pkgChar == '-')
	{
		// we may have a number but we must look ahead one char to be certain
		
		WCHAR oldChar = m_pkgChar;
		DWORD fileOffset=::SetFilePointer(iPkgHandle, 0L, NULL, FILE_CURRENT);
		GetNextChar();
		lexemeIsNumber = iswdigit(m_pkgChar) != FALSE;
		m_pkgChar = oldChar;
		::SetFilePointer(iPkgHandle,fileOffset,NULL,FILE_BEGIN);
	}
	
	return lexemeIsNumber;
}

/**
GetNumericToken: Parse a number from the input line

@internalComponent
@released
*/
void PkgParser::GetNumericToken()
{
	WCHAR temp[MAX_STRING];
	LPWSTR end;
	bool hexString = false;
	DWORD dwBytesRead;
	DWORD fileOffset=::SetFilePointer(iPkgHandle, 0L, NULL, FILE_CURRENT);
	
	temp[0]=m_pkgChar;
	if (!::ReadFile(iPkgHandle, &temp[1], (MAX_STRING-2)*sizeof(WCHAR), &dwBytesRead, NULL) ||
		dwBytesRead==0)
		ParserError("Read failed");
	temp[1+dwBytesRead/sizeof(WCHAR)]='\0';
	hexString = (!CompareNString(temp, L"0x", 2) || !CompareNString(&temp[1], L"0x", 2));
	
	m_tokenValue.dwNumber = wcstoul(temp, &end, (hexString) ? 16 : 10);
	
	if (end==temp) ParserError("Read failed"); 
	::SetFilePointer(iPkgHandle, fileOffset+(end-temp-1)*sizeof(WCHAR), NULL, FILE_BEGIN);
	GetNextChar();
}

/**
AddLanguage: Updates the language list structure

@internalComponent
@released

@param aLang - Name of the language
@param aCode - Language code
@param aDialect - Language dialect code
*/
void PkgParser::AddLanguage(String aLang, unsigned long aCode, unsigned long aDialect)
{
	PLANG_LIST lc = new LANG_LIST;
	
	lc->langName = aLang;
	lc->langCode = aCode;
	lc->dialectCode = aDialect;

	iLangList.push_back(lc);
}

/**
DeleteAll: Deallocates memory for the data members

@internalComponent
@released
*/
void PkgParser::DeleteAll()
{
	while(iPkgBlock.size() > 0)
	{
		PCMD_BLOCK ptemp = 0;

		ptemp = iPkgBlock.front();
		iPkgBlock.pop_front();

		if(ptemp->cmdType == INSTALLFILE)
		{
			delete ptemp->iInstallFileList;
		}
		delete ptemp;
	}

	{
		LANGUAGE_LIST::iterator begin = iLangList.begin();
		LANGUAGE_LIST::iterator end = iLangList.end();
		while(begin != end)
		{
			PLANG_LIST ptemp = 0;
			ptemp = (*begin);

			if(ptemp)
				delete ptemp;
			++begin;
		}
		iLangList.clear();
	}
}

/**
ParserError: Throws exception with the given error message

@internalComponent
@released

@param msg - error message to be thrown
*/
void PkgParser::ParserError(char* msg)
{
	std::ostringstream str;

	str << (char*)iPkgFile.data() << "(" << m_nLineNo << "): " << msg;

	throw SisUtilsException("PakageFile-Parser Error", (char*)(str.str()).data());
}

/**
wstring2string: Converts wide string to string

@internalComponent
@released

@param aWide - input wide string
*/
String wstring2string (const std::wstring& aWide)
{
	int max = ::WideCharToMultiByte(CP_OEMCP,0,aWide.c_str(),aWide.length(),0,0,0,0);
	String reply;
	if (max > 0 )
	{
		char* buffer = new char [max];
		try
		{
			::WideCharToMultiByte(CP_OEMCP,0,aWide.c_str(),aWide.length(),buffer,max,0,0);
			reply = String (buffer, max);
		}
		catch (...)
		{
			throw SisUtilsException("ParserError", "wstring to string conversion failed");
		}
		delete [] buffer;
	}
	return reply;
}

/**
string2wstring: Converts string to wide string

@internalComponent
@released

@param aNarrow - input string
*/
std::wstring string2wstring (const String& aNarrow)
{
	int max = ::MultiByteToWideChar(CP_OEMCP,0,aNarrow.c_str(),aNarrow.length(),0,0);
	std::wstring reply;
	if (max > 0 )
	{
		wchar_t* buffer = new wchar_t [max];
		try
		{
			::MultiByteToWideChar(CP_OEMCP,0,aNarrow.c_str(),aNarrow.length(),buffer,max);
			reply = std::wstring (buffer, max);
		}
		catch (...)
		{
			throw SisUtilsException("ParserError", "string to wstring conversion failed");
		}
		delete [] buffer;
	}
	return reply;
}

/**
CompareTwoString: Compares two wide string

@internalComponent
@released

@param string - first string
@param option - second string
*/
int CompareTwoString(wchar_t* string ,wchar_t* option)
{
	return wcsicmp(string,option);
}

/**
CompareNString: Compares two wide string for n characters

@internalComponent
@released

@param string - first string
@param option - second string
@param len - no of wide characters to be compared
*/
int CompareNString(wchar_t* string ,wchar_t* option, int len)
{
	return wcsnicmp(string,option,len);
}