/*
* 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.htm ".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/


#include "sisutils.h"
#include "pkgfileparser.h"
#ifdef __LINUX__ 
#include <strings.h>
#define stricmp strcasecmp
#define strnicmp strncasecmp
#endif
#include "utf16string.h"

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

const SParseToken KTokens[] =
{
	{ "if",		IF_TOKEN},
	{ "elseif",	ELSEIF_TOKEN},
	{ "else",	ELSE_TOKEN},
	{ "endif",	ENDIF_TOKEN},
	{ "exists",	EXISTS_TOKEN},
	{ "devprop",DEVCAP_TOKEN},
	{ "appcap",	APPCAP_TOKEN},
	{ "package",DEVCAP_TOKEN},
	{ "appprop",APPCAP_TOKEN},
	{ "not",	NOT_TOKEN},
	{ "and",	AND_TOKEN},
	{ "or",		OR_TOKEN},
	{ "type",	TYPE_TOKEN},
	{ "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(const string& aFile) : iPkgFileContent(""),iContentPos(0),iContentStr("") ,iPkgFileName(aFile),iToken(EOF_TOKEN) , iLineNumber(0){
}

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

@internalComponent
@released
*/
PkgParser::~PkgParser() {
	 
	DeleteAll();
	
}

/**
OpenFile: Opens the package script file

@internalComponent
@released
*/
bool PkgParser::OpenFile() {
	
	UTF16String str ;
	if(!str.FromFile(iPkgFileName.c_str()))
		return false ;
	
	if(!str.ToUTF8(iContentStr)) 		 
		return false ; 
	 
	iPkgFileContent = iContentStr.c_str();
	iContentPos = 0 ;	
	return true ;
}
/** 
 * GetNextChar : iContentStr is a UTF-8 String, of which char is as follows:
 * 
 *0000-007F | 0xxxxxxx
 *0080-07FF | 110xxxxx 10xxxxxx
 *0800-FFFF | 1110xxxx 10xxxxxx 10xxxxxx
 * 10000-10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 */
void PkgParser::GetNextChar() {		
	if(iContentPos < iContentStr.length()){
		if(0 == (iPkgFileContent[iContentPos] & 0x80))
			iContentPos++;
		else if(0xC0 == (iPkgFileContent[iContentPos]  & 0xE0))
			iContentPos += 2 ;
		else if(0xE0 == (iPkgFileContent[iContentPos]  & 0xF0))
			iContentPos += 3 ;
		else
			iContentPos += 4 ;
		if(iContentPos >= iContentStr.length())
			iContentPos = iContentStr.length() ;
	} 
}
/**
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(iPkgFileName.c_str(), "Could not open file"); 
	GetNextToken ();
	while(iToken!=EOF_TOKEN) {
		ParseEmbeddedBlockL();
		switch (iToken)
		{
		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(){
	TUint32 iLangCode = 0;
	TUint32 dialect = 0;
	
	while (true){
		if (iToken==ALPHA_TOKEN){
			iLangCode = GetLanguageCode(iTokenVal.iString);
		}
		else if (iToken==NUMERIC_TOKEN && iTokenVal.iNumber>=0 && iTokenVal.iNumber<=1000)	{
			iLangCode = (iTokenVal.iNumber);
		}

		GetNextToken ();

		// Check if a dialect is defined
		if (iToken == '(')
		{
			GetNumericToken();
			// Modify the last added language code, combining it with dialect code
			dialect = (iTokenVal.iNumber);
			GetNextToken ();
			GetNextToken ();
		}
		const char* temp = GetLanguageName(iLangCode);
		if(NULL != temp){		 
			AddLanguage(string(temp), iLangCode, dialect);
		}

		if (iToken!=',')
			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 (TUint16 wNumLangs = 0; wNumLangs < iLangList.size(); wNumLangs++) 	{
		GetNextToken ();
		ExpectToken(QUOTED_STRING_TOKEN);
		iPkgHeader.iPkgNames.push_back(string(iTokenVal.iString));
		GetNextToken ();
		if (wNumLangs < (iLangList.size()-1) ) {
			ExpectToken(',');
		}
	}
	ExpectToken('}');
	GetNextToken (); 
	
	ExpectToken(',');
	GetNextToken ();
	ExpectToken('(');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.iPkgUID = iTokenVal.iNumber;
	GetNextToken (); 
	ExpectToken(')'); 

	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.iMajorVersion = iTokenVal.iNumber;
	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.iMinorVersion = iTokenVal.iNumber;
	GetNextToken ();
	ExpectToken(',');
	GetNextToken ();
	
	ExpectToken(NUMERIC_TOKEN);
	iPkgHeader.iBuildVersion = iTokenVal.iNumber;
	GetNextToken ();
	
	// Parse any options
	while (iToken==',') {
		GetNextToken ();
		if (iToken==TYPE_TOKEN) {
			GetNextToken ();
			ExpectToken('=');
			GetNextToken ();
			iPkgHeader.iPkgType = iTokenVal.iString;
			GetNextToken ();
		}
		else
			GetNextToken ();
	}
}

/**
ParseEmbeddedBlockL: Parses the package body block

@internalComponent
@released
*/
void PkgParser::ParseEmbeddedBlockL () {
	while(iToken!=EOF_TOKEN) {
		switch (iToken) {
		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;
	
	string sourceFile (iTokenVal.iString);
	
	// Linux and windows both support forward slashes so if source path is given '\' need to convert
	// in forward slash for compatibility.
	char* pBuffer = const_cast<char*>(sourceFile.data());
	char* pCurrent = pBuffer;
	while (pBuffer && *pBuffer && (pCurrent = strchr(pBuffer,'\\')) != NULL) {
		*pCurrent = '/';
		pBuffer = pCurrent + 1;
	}
	
	GetNextToken ();
	
	ExpectToken('-');
	GetNextToken ();
	
	ExpectToken(QUOTED_STRING_TOKEN);
	
	string destinationFile (iTokenVal.iString);
	
	// SWI only supports backward slashesh so need to convert destination path in backward slash if
	// user gives '/' in Linux.
	pBuffer = const_cast<char*>(destinationFile.data());
	pCurrent = pBuffer;
	while (pBuffer && *pBuffer && (pCurrent = strchr(pBuffer,'/')) != NULL) {
		*pCurrent = '\\';
		pBuffer = pCurrent + 1;
	}
	
	GetNextToken ();
	
	// Test for options
	if (iToken!=',') {
		pCmdBlock = new CMD_BLOCK;
		pFileList = new INSTALLFILE_LIST;

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

		pFileList->iLangDepFlag = 0;
		pFileList->iSourceFiles.push_back(sourceFile);
		pFileList->iDestFile = destinationFile;

		iPkgBlock.push_back(pCmdBlock);
	}
	else {	
		bool needAdd = false;
		while(iToken==',') {
			GetNextToken ();
			string installOption = iTokenVal.iString;
			if((installOption == "FF") || (installOption == "FILE")) {
				needAdd = true;
			}
			GetNextToken ();
		}
		if (needAdd) {
			pCmdBlock = new CMD_BLOCK;
			pFileList = new INSTALLFILE_LIST;

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

			pFileList->iLangDepFlag = 0;
			pFileList->iSourceFiles.push_back(sourceFile);
			pFileList->iDestFile = 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->iCmdType = IF;
	ParseLogicalOp(pCmdBlock->iCmdExpr);
	iPkgBlock.push_back(pCmdBlock);

	ParseEmbeddedBlockL ();
	
	while (iToken==ELSEIF_TOKEN){
		GetNextToken ();
		//ELSEIF
		pCmdBlock = new CMD_BLOCK;
		pCmdBlock->iCmdType = ELSEIF;
		ParseLogicalOp(pCmdBlock->iCmdExpr);
		iPkgBlock.push_back(pCmdBlock);

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

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

	GetNextToken ();
}

/**
ParseLogicalOp: Parses the logical expression

@internalComponent
@released
*/
void PkgParser::ParseLogicalOp (string& aExpression) {
    ParseRelation (aExpression);
	switch (iToken) {
	case AND_TOKEN:
	case OR_TOKEN:
		{
			if (iToken==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 (iToken)
	{
	case '=':
	case '>':
	case '<':
	case GE_TOKEN:
	case LE_TOKEN:
	case NE_TOKEN:
	case APPCAP_TOKEN:
		{
			switch (iToken)
			{
			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 (iToken) 	{
	case NOT_TOKEN:
		aExpression.append(" !");
		GetNextToken ();
		ParseUnary (aExpression);
		break;
	case EXISTS_TOKEN:
	case DEVCAP_TOKEN:
		{	// 1 arg function
			TInt token=iToken;
			GetNextToken ();
			ExpectToken('(');
			GetNextToken ();
			if (token==EXISTS_TOKEN)
			{
				aExpression.append("EXISTS(\"");
				ExpectToken(QUOTED_STRING_TOKEN);
				GetNextToken ();
				aExpression.append(string(iTokenVal.iString));
				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 (iToken) {
	case '(':
		{
			aExpression.append("(");
			GetNextToken ();
			ParseLogicalOp (aExpression); 
			ExpectToken(')'); 
			aExpression.append(")");
		}
		break;
	case QUOTED_STRING_TOKEN:
	case ALPHA_TOKEN:
	case NUMERIC_TOKEN:
		{
			switch (iToken)
			{
			case QUOTED_STRING_TOKEN:
				aExpression.append("\"");
				aExpression.append(iTokenVal.iString);
				aExpression.append("\"");
				break;
			case ALPHA_TOKEN:
				if(!strnicmp(iTokenVal.iString,"option",6)) {
					aExpression.append(" defined(");
					aExpression.append(iTokenVal.iString); 
					ExpectToken(')'); 
				}
				else {
					aExpression.append(iTokenVal.iString);
				}
				break;
			case NUMERIC_TOKEN:
				{
					ostringstream str;

					str << "(0x" << setbase(16) << iTokenVal.iNumber << ")";
					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;
	TInt 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) == iTokenVal.iString) {
			found = 1;
			break;
		}
		++begin;
	}

	if(!found)
		iEmbedSisFiles.push_back(string(iTokenVal.iString));
		
	//add as a command block as well
	 
	pCmdBlock = new CMD_BLOCK;

	pCmdBlock->iCmdType = PACKAGE;
	pCmdBlock->iInstallFileList = 0;
	pCmdBlock->iCmdExpr = iTokenVal.iString;

	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 (GetCurChar() && (GetCurChar()!='\n')) GetNextChar();
	GetNextToken ();
}

/**
ParseOptionsBlockL: Parses the install options section

@internalComponent
@released
*/
void PkgParser::ParseOptionsBlockL() {
	TUint16 wNumLangs;
	
	ExpectToken('(');
	GetNextToken ();
	
	for (;;){
		ExpectToken('{');
		GetNextToken ();
		
		wNumLangs = 0;
		while (wNumLangs < iLangList.size()){
			ExpectToken(QUOTED_STRING_TOKEN);
			iInstallOptions.push_back(string(iTokenVal.iString));
			GetNextToken ();
			if (wNumLangs < iLangList.size() - 1){
				ExpectToken(',');
				GetNextToken ();
			}
			wNumLangs++;
		}
		
		ExpectToken('}');
		GetNextToken ();
		if (iToken!=',') 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 (iToken==','); 
	ExpectToken(')'); 
	GetNextToken ();
}

/**
ParseVendorNameL: Parses the vendor options section

@internalComponent
@released
*/
void PkgParser::ParseVendorNameL() {
	ExpectToken('{');
	for (TUint16 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 (iToken==',')
	{
		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 (iToken == '~') {
		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 (iToken == '~') {
		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 ();
}
 

 

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

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

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

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

/**
ParseEscapeChars: Parses the escape sequence characters

@internalComponent
@released
*/
TUint16 PkgParser::ParseEscapeChars() {
	TUint16 found=0;
	char temp[MAX_STRING];
 
	while (GetCurChar() == '<'){
		strcpy(temp,iTokenVal.iString);
		TUint savedPos = iContentPos ;	
		try	{
			GetNextChar();
			GetNumericToken();
			if (GetCurChar()=='>')
				found++;
			else {
				iContentPos = savedPos ;
				break;
			}
		}
		catch (...)	{
			strcpy(iTokenVal.iString,temp);
			iContentPos = savedPos ;
			break;
		}
		TUint32 num=iTokenVal.iNumber;
		// watch for CP1252 escapes which aren't appropriate for UNICODE
		if (num>=0x80 && num<=0x9F) ParserError("Invalid Escape");
		TUint32 len=strlen(temp);
		memcpy(iTokenVal.iString,temp, len + 1);
		if ((len + 2) <= MAX_STRING){
			iTokenVal.iString[len]= static_cast<char>(num);
			len++;
			iTokenVal.iString[len]='\0';
		}
		GetNextChar();
	}
 
	return found;
}

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

@internalComponent
@released
*/
void PkgParser::GetAlphaNumericToken()
{
	size_t length = 0;
	TUint savedPos = iContentPos ;	
	TUint bound = iContentStr.length();
	while((iContentPos < bound) && 
		(isalnum(iPkgFileContent[iContentPos]) || (iPkgFileContent[iContentPos] == '_'))) {
		iContentPos ++ ;
		if(length < (MAX_STRING - 1)) length ++ ; 
	}
	memcpy(iTokenVal.iString,&iPkgFileContent[savedPos],length);	
	iTokenVal.iString[length] = 0;
}

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

@internalComponent
@released
*/
bool PkgParser::IsNumericToken() { 
	char ch = iPkgFileContent[iContentPos];
	if (isdigit(ch))
		return true ;
	else if (ch == '+' || ch == '-'){
		// we may have a number but we must look ahead one char to be certain	
		return isdigit(iPkgFileContent[iContentPos + 1]) != 0; 
	}	
	return false ;
}

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

@internalComponent
@released
*/
void PkgParser::GetNumericToken() {
	 
	int base = 10; 
	const char* temp = &iPkgFileContent[iContentPos] ;
	if(*temp == '0' &&( temp[1] == 'x' || temp[1] == 'X')){
		base = 16 ;
		temp += 2;
	}
	char *end = const_cast<char*>(temp) ;
	iTokenVal.iNumber = strtoul(temp, &end, base);
	iContentPos = end - iPkgFileContent ;
}

/**
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(const string& aLang, TUint32 aCode, TUint32 aDialect) {
	PLANG_LIST lc = new LANG_LIST;
	
	lc->iLangName = aLang;
	lc->iLangCode = aCode;
	lc->iDialectCode = 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->iCmdType == 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(); 
	iPkgFileContent = "" ;
	iContentPos = 0 ;
	iContentStr.clear(); 
	
}

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

@internalComponent
@released

@param msg - error message to be thrown
*/
void PkgParser::ParserError(const char* aMsg) {
	ostringstream str;
	str << iPkgFileName.c_str() << "(" << iLineNumber << "): " << aMsg;
	throw SisUtilsException("PakageFile-Parser Error", str.str().c_str());
}
