diff -r 000000000000 -r 044383f39525 imgtools/sisutils/src/pkgfileparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imgtools/sisutils/src/pkgfileparser.cpp Tue Oct 27 16:36:35 2009 +0000 @@ -0,0 +1,1435 @@ +/* +* 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); +}