diff -r 000000000000 -r ba25891c3a9e secureswitools/swisistools/source/makesislib/packageparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/secureswitools/swisistools/source/makesislib/packageparser.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,2207 @@ +/* +* Copyright (c) 1997-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: +* handles parsing of PKG file +* Note: This file may contain code to generate corrupt files for test purposes. +* Such code is excluded from production builds by use of compiler defines; +* it is recommended that such code should be removed if this code is ever published publicly. +* INCLUDES +* +*/ + + +/** + @file + @internalComponent + @released +*/ + +#ifdef _MSC_VER +#pragma warning (disable: 4786) +#endif + +#include +#include +#include +#include + +#include "packageparser.h" +#include "utility_interface.h" +#include "version.h" +#include "utils.h" + + +#define EOF_TOKEN 0 +#define NUMERIC_TOKEN 1 +#define ALPHA_TOKEN 2 +#define QUOTED_STRING_TOKEN 3 +#define AND_TOKEN 4 +#define OR_TOKEN 5 +#define NOT_TOKEN 6 +#define EXISTS_TOKEN 7 +#define DEVCAP_TOKEN 8 +#define APPCAP_TOKEN 9 +#define GE_TOKEN 10 +#define LE_TOKEN 11 +#define NE_TOKEN 12 +#define IF_TOKEN 13 +#define ELSEIF_TOKEN 14 +#define ELSE_TOKEN 15 +#define ENDIF_TOKEN 16 +#define TYPE_TOKEN 17 +#define KEY_TOKEN 18 +#define VERSION_TOKEN 19 +#define SUPPORTED_LANG_TOKEN 20 +#define LAST_TOKEN 20 + + + +TDuplicates CPackageParser::iSrcFiles; + +// =========================================================================== +// CONSTANTS +// =========================================================================== + +// Set up the cout stream so that we can use it with either narrow or wide +// chars at build time + +#ifndef _UNICODE +#error _UNICODE expected +#endif // _UNICODE + + +// Parse options lookups +const SParseOpt KHeaderOptions[] = + { + {L"IU", EInstIsUnicode}, + {L"SH", EInstShutdownApps}, + {L"NC", EInstNoCompress}, + {L"IUNICODE", EInstIsUnicode}, + {L"SHUTDOWNAPPS", EInstShutdownApps}, + {L"NOCOMPRESS", EInstNoCompress}, + {L"NR", EInstNonRemovable}, + {L"NONREMOVABLE", EInstNonRemovable}, + {L"RU", EInstROMUpgrade}, + {L"ROMUPGRADE", EInstROMUpgrade}, + {L"H", EInstHide}, + {L"HIDE", EInstHide} + + }; +#define NUMHEADEROPTIONS (sizeof(KHeaderOptions)/sizeof(SParseOpt)) + +// 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"devcap", 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}, + {L"version", VERSION_TOKEN}, + {L"supported_language",SUPPORTED_LANG_TOKEN}, + + }; +#define NUMPARSETOKENS (sizeof(KTokens)/sizeof(SParseToken)) + +// =========================================================================== +// CPackageParser +// =========================================================================== + +CPackageParser::CPackageParser(MParserObserver& aObserver) : + iValidSISFile(true), + iMakeStub(false), + iReportInterpretSisError(false), + iEnoughForStub(false), + iIsHeaderDefined(false), + iUniqueVendorName (false), + iLocalisedVendorNames (false), + iPkgChar(0), + iLineNo(0), // The line we are currently on + iCurrentLang(0), // If we are in a lang/lang file block - which lang are we processing + iToken(0), + iFileHandle(0), + iObserver(aObserver) + { + memset((void *)iSearchDir, 0x0000, PATHMAX * sizeof(wchar_t)); + } + +void CPackageParser::SetSearchDirectory(LPCWSTR pszPath) +// Purpose : Sets the search directory +// Inputs : pszPath - The directory path (including trailing backslash!) + { + wcsncpy(iSearchDir, pszPath, PATHMAX - 1); + DWORD len=wcslen(iSearchDir); + wchar_t *pBuffer = iSearchDir; + wchar_t *pCurrent = pBuffer; + + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'\\')) != NULL) + { + *pCurrent = L'/'; + pBuffer = pCurrent + 1; + } + + if(len>0 && iSearchDir[len - 1] != '/') + { + iSearchDir[len] = '/'; + iSearchDir[len+1] = '\0'; + } + + } + +void CPackageParser::MakeSis(const wchar_t* aPkgFileName, const wchar_t* aSisFileName, bool aMakeStub, bool aReportInterpretSisError) + { + iMakeStub = aMakeStub; + iReportInterpretSisError = aReportInterpretSisError; + ParseL(aPkgFileName); + // Turn off line number output + iObserver.SetLineNumber(0); + + if (iMakeStub) + iObserver.DoVerbage(L"Generating SIS stub file..."); + else + iObserver.DoVerbage(L"Generating SIS installation file..."); + + if (iValidSISFile) + { + iSISXWriter.WriteSIS (aSisFileName); + } + } + +HANDLE CPackageParser::OpenPackageFile(const wchar_t* aPkgFileName) + { + bool fResult = true; + wchar_t pszTempSource [PATHMAX]; + bool converted = true; + HANDLE hFile = 0; + + TEncodingScheme encScheme; + if (!FileIsUnicode(aPkgFileName,encScheme)) + { + if ( EUtf8 != encScheme ) + iObserver.DoVerbage(L"Byte order marker not detected. Assuming UTF-8 encoding"); + iObserver.DoVerbage(L"Encoding scheme: UTF8"); + wcscpy(pszTempSource,ConvertFileToUnicode(aPkgFileName,encScheme)); + } + else if (encScheme == EUcs2BE && sizeof(WCHAR) == 2) + { + iObserver.DoVerbage(L"Encoding scheme: UCS2 (BE)"); + wcscpy(pszTempSource,ConvertUCS2FileToLittleEndianUnicode(aPkgFileName)); + } + /* + Linux first needs conversion to little endian and then into ucs-4 + Linux has wchar in 4 bytes and processing of .pkg file happens based on wchar + so need conversion here from ucs2 to ucs4 + */ + else if (encScheme == EUcs2BE && sizeof(WCHAR) == 4) + { + iObserver.DoVerbage(L"Encoding scheme: UCS2 (BE)"); + wcscpy(pszTempSource,ConvertUCS2FileToLittleEndianUnicode(aPkgFileName)); + wcscpy(pszTempSource,ConvertUCS2FileToUCS4(pszTempSource)); + } + else if (encScheme == EUcs2LE && sizeof(WCHAR) == 2) + { + iObserver.DoVerbage(L"Encoding scheme: UCS2 (LE)"); + wcscpy(pszTempSource, aPkgFileName); + converted = false; + } + // Convert UCS2 file to UCS4 for Linux + else if (encScheme == EUcs2LE && sizeof(WCHAR) == 4) + { + iObserver.DoVerbage(L"Encoding scheme: UCS2 (LE)"); + wcscpy(pszTempSource,ConvertUCS2FileToUCS4(aPkgFileName)); + } + else + { + iObserver.DoVerbage(L"Encoding scheme not supported"); + throw ErrCannotOpenFile; + } + + hFile = ::MakeSISOpenFile(pszTempSource,GENERIC_READ,OPEN_EXISTING); + + if (hFile==INVALID_HANDLE_VALUE) + { + throw ErrCannotOpenFile; + } + + if(encScheme == EUtf8) + { + UnicodeMarker(hFile); + } + + if(converted) + { + _wunlink(pszTempSource); + } + + return hFile; + } + +void CPackageParser::ParseL (const wchar_t* aPkgFileName) +// Purpose : Check the contents of an input line and defers parsing to the appropriate ParseXXXL() +// method +// Inputs : m_pkgPtr - The line to process + { + iValidSISFile = true; + iFileHandle = OpenPackageFile(aPkgFileName); + assert(iFileHandle != INVALID_HANDLE_VALUE); + + iEnoughForStub = false; + iSISXWriter.SetDefaultContent (); + + iObserver.SetLineNumber(++iLineNo); + + // Make sure we're at the beginning of the file + ::SetFilePointer(iFileHandle, 0L, NULL, FILE_BEGIN); + + GetNextChar(); + + // skip unicode marker if present + if(iPkgChar==0xFEFF) GetNextChar(); + + GetNextToken (); + while(iToken!=EOF_TOKEN && !(iMakeStub && iEnoughForStub)) + { + ParseEmbeddedBlockL (iSISXWriter.InstallBlock ()); + switch (iToken) + { + case '&': + // Pkg file keyword check is disabled here + // to avoid conflicts with the language code + // (e.g. "IF - International French"). + GetNextToken (1); + ParseLanguagesL(); + break; + case '#': + GetNextToken (); + ParseHeaderL(); + break; + case '%': + GetNextToken (); + ParseVendorNameL(); + break; + case '=': + GetNextToken (); + ParseLogoL(); + break; + case '(': + GetNextToken (); + ParseDependencyL(); + break; + case '*': + GetNextToken (); + ParseSignatureL(); + break; + case ':': + GetNextToken (); + ParseVendorUniqueNameL(); + break; + case '[': + GetNextToken (); + ParseTargetDeviceL(); + break; + case EOF_TOKEN: + break; + default : + { + throw ErrUnknownLine; + } + } + } + if (! iUniqueVendorName && ! iLocalisedVendorNames) + { + iObserver.DoMsg(L"No vendor names found.\n"); + } + else if (! iLocalisedVendorNames) + { + iObserver.DoMsg(L"Localised vendor names not found.\n"); + } + else if (! iUniqueVendorName) + { + iObserver.DoMsg(L"Unique vendor name not found.\n"); + } + + if (iFileHandle) + { + ::CloseHandle(iFileHandle); + } + } + +void CPackageParser::ParseEmbeddedBlockL (CSISInstallBlock& aInstall) + { + while(iToken!=EOF_TOKEN) + { + switch (iToken) + { + case QUOTED_STRING_TOKEN: + ParseFileL (aInstall); + break; + case '@': + GetNextToken (); + ParsePackageL (aInstall); + break; + case '!': + GetNextToken (); + ParseOptionsBlockL(); + break; + case '{': + GetNextToken (); + ParseLanguageBlockL (aInstall); + break; + case '+': + GetNextToken (); + ParsePropertyL (); + break; + case IF_TOKEN: + GetNextToken (); + ParseIfBlockL (aInstall); + break; + case ';' : + ParseCommentL (); + break; + default : + return; + } + } + } + +void CPackageParser::ParseLanguagesL() +// Parses the language definition line +// Updated to support "dialects" +// Dialect definition syntax is: ["("")"] + + { + iObserver.DoVerbage(L"processing languages"); + + if (iSISXWriter.AreLanguagesSpecified ()) + throw ErrLanguagesAlreadyDefined; + + CSISLanguage::TDialect dialect (0); + + while (true) + { + if (iToken==ALPHA_TOKEN) + { + dialect = CSISLanguage::IdentifyLanguage (iTokenValue.pszString); + if (dialect == CSISLanguage::ELangNone) throw ErrUnknownLanguagesId; + } + else if (iToken==NUMERIC_TOKEN && iTokenValue.dwNumber>=0 && iTokenValue.dwNumber<=1000) + { + dialect = static_cast (iTokenValue.dwNumber); + } + else + throw ErrUnknownLanguagesId; + GetNextToken (); + // Check if a dialect is defined + if (iToken == '(') + { + GetNumericToken(); + // Modify the last added language code, combining it with dialect code + if (dialect) dialect = dialect + static_cast (iTokenValue.dwNumber); + GetNextToken (); + if (iToken != ')') + throw ErrUnexpectedToken; + GetNextToken (); + } + iSISXWriter.AddLanguage (dialect); + dialect=0; + if (iToken!=',') + return; + GetNextToken (1); + } + } + + +void CPackageParser::ParseHeaderL() +// Parses the pkg header line + { + iObserver.DoVerbage(L"processing header"); + + // Default type + std::wstring interpretType = L"SA"; + bool isNonRemovable = false; + + // By default the ROM Upgradeable flag (RU) is FALSE. + bool isROMUpgrade = false; + + if (iIsHeaderDefined) + throw ErrHeaderAlreadyDefined; + + if (! iSISXWriter.AreLanguagesSpecified ()) + { + iObserver.DoVerbage (L"No languages defined, assuming English."); + } + + // process application names + ExpectToken('{'); + for (WORD wNumLangs = 0; wNumLangs < iSISXWriter.GetNoLanguages(); wNumLangs++) + { + GetNextToken (); + ExpectToken(QUOTED_STRING_TOKEN); + iSISXWriter.AddName (iTokenValue.pszString); + GetNextToken (); + if (wNumLangs < iSISXWriter.GetNoLanguages() -1 ) + { + ExpectToken(','); + } + } + ExpectToken('}'); + GetNextToken (); + + DWORD dwFlags = 0; + DWORD dwType = 0; + + ExpectToken(','); + GetNextToken (); + ExpectToken('('); + GetNextToken (); + + ExpectToken(NUMERIC_TOKEN); + CSISUid::TUid uid = iTokenValue.dwNumber; + GetNextToken (); + + ExpectToken(')'); + GetNextToken (); + ExpectToken(','); + GetNextToken (); + + ExpectToken(NUMERIC_TOKEN); + CSISVersion::TMajor major = iTokenValue.dwNumber; + GetNextToken (); + ExpectToken(','); + GetNextToken (); + + ExpectToken(NUMERIC_TOKEN); + CSISVersion::TMinor minor = iTokenValue.dwNumber; + GetNextToken (); + ExpectToken(','); + GetNextToken (); + + ExpectToken(NUMERIC_TOKEN); + CSISVersion::TBuild build = iTokenValue.dwNumber; + GetNextToken (); + + ValidateVersion(major,minor,build); + + // Parse any options + bool narrow=false; + while (iToken==',') + { + GetNextToken (); + if (iToken==TYPE_TOKEN) + { + GetNextToken (); + ExpectToken('='); + GetNextToken (); + interpretType = iTokenValue.pszString; + iSISXWriter.InterpretType (iTokenValue.pszString); + GetNextToken (); + } + else + { + DWORD option=ParseOption(KHeaderOptions,NUMHEADEROPTIONS,&dwFlags); + narrow=(option==0); + + switch (option) + { + + case EInstShutdownApps: + iSISXWriter.AddInstallFlag(CSISInfo::EInstFlagShutdownApps); + break; + + case EInstNonRemovable: + isNonRemovable = true; + iSISXWriter.AddInstallFlag(CSISInfo::EInstFlagNonRemovable); + break; + + case EInstROMUpgrade: + isROMUpgrade = true; + iSISXWriter.AddInstallFlag(CSISInfo::EInstFlagROMUpgrade); + break; + + case EInstHide: + #ifdef SYMBIAN_UNIVERSAL_INSTALL_FRAMEWORK + iSISXWriter.AddInstallFlag(CSISInfo::EInstFlagHide); + #endif + break; + } + } + } + + //ROM Upgrade is applicable only for SA, PU & SP, reject package file if RU is coupled + //with anything other than these three install types. + if(isROMUpgrade && ((interpretType != L"SA") && (interpretType != L"PU") && (interpretType != L"SP"))) + { + throw ErrInvalidInstallFlagOption; + } + + // Reject package types PA-PP if marked non-removable + if (isNonRemovable && (interpretType == L"PA" || interpretType == L"PP")) + { + throw ErrHeaderRejectPreInstalledNonRemovable; + } + + if (InterpretSis() && (interpretType == L"PP")) + { + ReportInterpretSisError(ErrInvalidAppType); + } + + // if narrow not explicitly set default to unicode + if (!narrow) dwFlags|=EInstIsUnicode; + + iSISXWriter.SetVersionInfo (uid, TVersion (major, minor, build), dwType, dwFlags); + iIsHeaderDefined = true; + } + +void CPackageParser::ParseVendorNameL () + { + iObserver.DoVerbage(L"processing vendor name"); + + ExpectToken('{'); + for (WORD wNumLangs = 0; wNumLangs < iSISXWriter.GetNoLanguages(); wNumLangs++) + { + GetNextToken (); + ExpectToken(QUOTED_STRING_TOKEN); + iSISXWriter.AddVendorName (iTokenValue.pszString); + GetNextToken (); + if (wNumLangs < iSISXWriter.GetNoLanguages() -1 ) + { + ExpectToken(','); + } + } + ExpectToken('}'); + GetNextToken (); + iLocalisedVendorNames = true; + } + +void CPackageParser::ParseLogoL () + { + iObserver.DoVerbage(L"processing logo"); + + ExpectToken (QUOTED_STRING_TOKEN); + std::wstring file (iTokenValue.pszString); + + const wchar_t *pBuffer = file.c_str(); + wchar_t *pCurrent = const_cast(pBuffer); + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'\\')) != NULL) + { + *pCurrent = L'/'; + pBuffer = pCurrent + 1; + } + + GetNextToken (); + ExpectToken(','); + GetNextToken (); + ExpectToken (QUOTED_STRING_TOKEN); + std::wstring mime (iTokenValue.pszString); + + pBuffer = mime.c_str(); + pCurrent = const_cast(pBuffer); + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'\\')) != NULL) + { + *pCurrent = L'/'; + pBuffer = pCurrent + 1; + } + + GetNextToken (); + std::wstring target; + + if (iToken==',') + { + GetNextToken (); + ExpectToken (QUOTED_STRING_TOKEN); + target = iTokenValue.pszString; + } + iSISXWriter.SetLogo (file, mime, target); + const CSISLogo& logo = iSISXWriter.SISContent().Controller().Logo(); + CSISFileDescription& fd = const_cast(logo.FileDesc()); + ComputeAndSetHash(fd); + GetNextToken (); + } + +void CPackageParser::ParseFileL (CSISInstallBlock& aInstall) +// Parses a file definition line + { + iObserver.DoVerbage(L"processing file"); + bool fileProblem = false; + + if (! iIsHeaderDefined) + throw ErrHeaderNotDefined; + + std::wstring sourceFile (iTokenValue.pszString); + + // Linux and windows both support forward slashes so if source path is given '\' need to convert + // in forward slash for compatibility. + const wchar_t *pBuffer = sourceFile.c_str(); + wchar_t *pCurrent = const_cast(pBuffer); + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'\\')) != NULL) + { + *pCurrent = L'/'; + pBuffer = pCurrent + 1; + } + + TUint64 size; + TUint64 compressedSize = 0; + + bool isFileNameEmpty = sourceFile.empty (); + if(CSISContents::IsPreInstalledApp() && isFileNameEmpty) + { + fileProblem = true; + iObserver.DoMsg(L" Error : Source file is missing for PreInstalled APP : "); + CSISException::ThrowIf (fileProblem , + CSISException::EFileProblem, + std::wstring (L"Source file is missing for PreInstalled APP ")); + } + + if(! isFileNameEmpty && ! DoesFileExist (sourceFile, size)) + { + wchar_t msg[255]; + wcscpy(msg, L"Cannot find file : "); + wcscat(msg, sourceFile.c_str()); + wcsncat(msg, L"\n", 1); + iObserver.DoErrMsg(msg); + fileProblem = true; + } + + CSISException::ThrowIf (fileProblem , + CSISException::EFileProblem, + std::wstring (L"cannot find ") + sourceFile); + + GetNextToken (); + + ExpectToken('-'); + GetNextToken (); + + ExpectToken(QUOTED_STRING_TOKEN); + + // BAW-5CQEA5 Check for invalid destination (i.e starts with ':') + if ((sourceFile.size () > 0) && (sourceFile [0] == ':')) + throw ErrBadDestinationPath; + + std::wstring destinationFile (iTokenValue.pszString); + + // SWI only supports backward slashesh so need to convert destination path in backward slash if + // user gives '/' in Linux. + pBuffer = destinationFile.c_str(); + pCurrent = const_cast(pBuffer); + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'/')) != NULL) + { + *pCurrent = L'\\'; + pBuffer = pCurrent + 1; + } + + // SWI only supports backward slashesh so need to convert destination path in backward slash if + // user gives '/' in Linux. + pBuffer = destinationFile.c_str(); + pCurrent = const_cast(pBuffer); + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'/')) != NULL) + { + *pCurrent = L'\\'; + pBuffer = pCurrent + 1; + } + + bool bNewFile = true; + // CSisFileDescription is allocated on the heap, since the compiler does not support well + // its allocation on the stack combined with exceptions (DEF108815) + std::auto_ptr fd(new CSISFileDescription); + TUint32 fileIndex = Find((wchar_t*)sourceFile.c_str(),*fd); + if ( fileIndex == -1 ) + { + aInstall.AddFileDescription (); + } + else + { + aInstall.AddFileDescription (*fd); + bNewFile = false; + } + + if (! isFileNameEmpty) + { + if ( bNewFile ) + { + TUint64 size = 0; + fileIndex = iSISXWriter.LoadFile (sourceFile, &size); + aInstall.SetFileIndex (fileIndex); + aInstall.ExtractCapabilities(sourceFile); + aInstall.SetLengths (size, iSISXWriter.CompressedSize ()); + ComputeAndSetHash(aInstall.FileDescription()); + + Set(sourceFile,aInstall.FileDescription()); + } + } + + aInstall.SetTarget (destinationFile); + + GetNextToken (); + + if ( !bNewFile ) + { + CSISFileDescription& fdLast = aInstall.FileDescription(); + fdLast.SetOperation(0); + fdLast.SetOptions(0); + } + + // Test for options + if (iToken!=',') + { + aInstall.SetOperation (CSISFileDescription::EOpInstall); + } + else + { + GetNextToken (); + + CSISFileDescription::TSISInstOption type = aInstall.InterpretOption (iTokenValue.pszString); + GetNextToken (); + if (type == CSISFileDescription::EInstFileRunOptionByMimeType) + { + ExpectToken (','); + GetNextToken (); + ExpectToken (QUOTED_STRING_TOKEN); + aInstall.SetMimeType (iTokenValue.pszString); + GetNextToken (); + } + if (iToken==',') + { + do + { + + GetNextToken (); + aInstall.InterpretOption (iTokenValue.pszString); + + //if the next token is a comma , then continue. + GetNextToken (); + + } while (iToken == ','); + + } + } + + } + +void CPackageParser::ParsePackageL (CSISInstallBlock& aInstall) +// Parses a package (component SIS file) line + { + iObserver.DoVerbage(L"processing embedded package file"); + + if (InterpretSis()) + { + ReportInterpretSisError(ErrEmbeddedSisNotSupported); + } + + if (! iIsHeaderDefined) + throw ErrHeaderNotDefined; + + ExpectToken(QUOTED_STRING_TOKEN); + WCHAR pszFile[MAX_STRING]; + wcscpy(pszFile,iTokenValue.pszString); + std::wstring fileName; + std::wstring name; + //check whether search directory is specified. + if(iSearchDir[0] != '\0') + { + if ((wcslen (iSearchDir) + wcslen (pszFile)) < PATHMAX - 1) + { + WCHAR pszNewPath[PATHMAX]; + wcscpy(pszNewPath, iSearchDir); + wcscat(pszNewPath, pszFile); + fileName.append(pszNewPath); + } + } + else + { + name = iTokenValue.pszString; + } + + + // Test that the file exists + GetNextToken (); + + ExpectToken(','); + GetNextToken (); + ExpectToken('('); + GetNextToken (); + ExpectToken(NUMERIC_TOKEN); + CSISUid::TUid uid = iTokenValue.dwNumber; + GetNextToken (); + ExpectToken(')'); + GetNextToken (); + + if(iSearchDir[0] != '\0') + { + iSISXWriter.EmbedFile (fileName, uid, aInstall ); + } + else + { + iSISXWriter.EmbedFile (name, uid, aInstall ); + } + } + +TVersion CPackageParser::ParseVersion() +// Parse version information for dependency lines + { + + CSISVersion::TMajor major; + GetNextToken(); + if (iToken == '*') + { + major = -1; + } + else + { + ExpectToken(NUMERIC_TOKEN); + major = iTokenValue.dwNumber; + } + + GetNextToken(); + ExpectToken(','); + + CSISVersion::TMinor minor; + GetNextToken(); + if (iToken == '*') + { + minor = -1; + } + else + { + ExpectToken(NUMERIC_TOKEN); + minor = iTokenValue.dwNumber; + } + + GetNextToken(); + ExpectToken(','); + + CSISVersion::TBuild build; + GetNextToken(); + if (iToken == '*') + { + build = -1; + } + else + { + ExpectToken(NUMERIC_TOKEN); + build = iTokenValue.dwNumber; + } + + GetNextToken(); + + ValidateVersion(major, minor, build); + + return TVersion(major, minor, build); + + } + +void CPackageParser::ParseDependencyL() +// Parses a dependency line + { + iObserver.DoVerbage(L"processing dependency"); + + if (! iIsHeaderDefined) + throw ErrHeaderNotDefined; + + ExpectToken(NUMERIC_TOKEN); + CSISUid::TUid uid = iTokenValue.dwNumber; + GetNextToken (); + + ExpectToken(')'); + GetNextToken (); + ExpectToken(','); + + TVersion from = ParseVersion(); + TVersion to(-1,-1,-1); + + if (iToken == '~') + { + to = ParseVersion(); + ExpectToken(','); + } + else if (iToken == ',') + { + to = TVersion(KIrrelevant, KIrrelevant, KIrrelevant); + } + else + { + iObserver.DoErrMsg(L"Expected '-' or ',' in dependency line"); + throw ErrUnexpectedToken; + } + + + GetNextToken (); + ExpectToken('{'); + + iSISXWriter.AddDependency (uid, from, to); + // must do this before adding language strings + + for (TUint16 numLangs = 0; numLangs < iSISXWriter.GetNoLanguages (); ++numLangs) + { + GetNextToken (); + ExpectToken(QUOTED_STRING_TOKEN); + iSISXWriter.AddDependencyName (iTokenValue.pszString); + GetNextToken (); + if (numLangs < (iSISXWriter.GetNoLanguages() - 1)) + ExpectToken(','); + } + ExpectToken('}'); + GetNextToken (); + } + +void CPackageParser::ParseTargetDeviceL() +// Parses a target device line + { + iObserver.DoVerbage(L"processing target device"); + + if (! iIsHeaderDefined) + throw ErrHeaderNotDefined; + + ExpectToken(NUMERIC_TOKEN); + CSISUid::TUid uid = iTokenValue.dwNumber; + GetNextToken (); + + ExpectToken(']'); + GetNextToken (); + ExpectToken(','); + + TVersion from = ParseVersion(); + TVersion to(-1,-1,-1); + + if (iToken == '~') + { + to = ParseVersion(); + ExpectToken(','); + } + else if (iToken == ',') + { + to = TVersion(KIrrelevant, KIrrelevant, KIrrelevant); + } + else + { + iObserver.DoErrMsg(L"Expected '-' or ',' in dependency line"); + throw ErrUnexpectedToken; + } + + GetNextToken (); + ExpectToken('{'); + + iSISXWriter.AddTarget (uid, from, to); + // must do this before adding language strings + + for (TUint16 numLangs = 0; numLangs < iSISXWriter.GetNoLanguages (); ++numLangs) + { + GetNextToken (); + ExpectToken(QUOTED_STRING_TOKEN); + iSISXWriter.AddTargetName (iTokenValue.pszString); + GetNextToken (); + if (numLangs < (iSISXWriter.GetNoLanguages() - 1)) + ExpectToken(','); + } + ExpectToken('}'); + GetNextToken (); + } + +void CPackageParser::ParseSignatureL() +{ + // Parses the package-signature + iObserver.DoVerbage(L"processing signature"); + + // MAKESIS ignore the Signature,this option is deprecated. + iObserver.DoMsg(L"Signature ignored,this option is deprecated...\n"); + + if (! iIsHeaderDefined) + throw ErrHeaderNotDefined; + + // If generating a stub file then once have signature line don't need to + // process rest of PKG file + iEnoughForStub=true; + + ExpectToken(QUOTED_STRING_TOKEN); + + GetNextToken (); + ExpectToken(','); + GetNextToken (); + + ExpectToken(QUOTED_STRING_TOKEN); + GetNextToken (); + + //check for optional items (password) + if (iToken==',') + { + GetNextToken (); + if (iToken==KEY_TOKEN) + { + GetNextToken (); + ExpectToken('='); + GetNextToken (); + ExpectToken(QUOTED_STRING_TOKEN); + GetNextToken (); + } + } + +} + + +void CPackageParser::ParseVendorUniqueNameL() +{ + // Parses the package-signature + iObserver.DoVerbage(L"processing unique vendor name"); + + ExpectToken(QUOTED_STRING_TOKEN); + iSISXWriter.SetVendorUniqueName (iTokenValue.pszString); + iUniqueVendorName = true; + GetNextToken (); +} + +void CPackageParser::ParsePropertyL () +// Parses a capability line + { + iObserver.DoVerbage(L"processing property"); + + CSISProperty::TKey key; + CSISProperty::TValue value; + + ExpectToken('('); + do + { + GetNextToken (); + + ExpectToken(NUMERIC_TOKEN); + key = iTokenValue.dwNumber; + GetNextToken (); + ExpectToken('='); + GetNextToken (); + ExpectToken(NUMERIC_TOKEN); + value = iTokenValue.dwNumber; + iSISXWriter.AddProperty (key, value); + + GetNextToken (); + } while (iToken==','); + ExpectToken(')'); + GetNextToken (); + } + +void CPackageParser::ParseOptionsBlockL () +// To parse an options block + { + WORD wNumLangs; + + iObserver.DoVerbage(L"processing options block"); + + ExpectToken('('); + GetNextToken (); + + if (InterpretSis()) + { + ReportInterpretSisError(ErrUserOptionsNotSupported); + } + + for (;;) + { + ExpectToken('{'); + GetNextToken (); + + iSISXWriter.AddOption (); + + wNumLangs = 0; + while (wNumLangs < iSISXWriter.GetNoLanguages()) + { + ExpectToken(QUOTED_STRING_TOKEN); + iSISXWriter.AddOptionName (iTokenValue.pszString); + GetNextToken (); + if (wNumLangs < iSISXWriter.GetNoLanguages() - 1) + { + ExpectToken(','); + GetNextToken (); + } + wNumLangs++; + } + + ExpectToken('}'); + GetNextToken (); + if (iToken!=',') break; + GetNextToken (); + } + + ExpectToken(')'); + GetNextToken (); + + } + +void CPackageParser::ParseLanguageBlockL (CSISInstallBlock& aInstall) +// To parse the start of a language block + { + iObserver.DoVerbage(L"processing language block"); + + if (! iIsHeaderDefined) + throw ErrHeaderNotDefined; + + bool packages=(iToken=='@'); + unsigned languageCount = iSISXWriter.GetNoLanguages (); + std::vector fileIndex (languageCount); + std::vector fileSize (languageCount); + std::vector compressedSize (languageCount); + std::vector hashes (languageCount); + + for (DWORD iCurrentLang = 0; iCurrentLang < languageCount; iCurrentLang++) + { + if (iCurrentLang == 0) + { + aInstall.AddIf (); + aInstall.If ().Expression ().SetLanguageComparision (iSISXWriter.Language (iCurrentLang)); + } + else + { + aInstall.If ().AddElseIf (); + aInstall.If ().ElseIf ().Expression ().SetLanguageComparision (iSISXWriter.Language (iCurrentLang)); + } + if (packages) + { + ExpectToken ('@'); + GetNextToken (); + if (iCurrentLang == 0) + { + iSISXWriter.EmbedPackage (aInstall.If ().InstallBlock (), iTokenValue.pszString, 0); + } + else + { + iSISXWriter.EmbedPackage (aInstall.If ().ElseIf ().InstallBlock (), iTokenValue.pszString, 0); + } + } + else + { + CSISFileDescription fd; + wchar_t *pBuffer = iTokenValue.pszString; + wchar_t *pCurrent = pBuffer; + while (pBuffer && *pBuffer && (pCurrent = wcschr(pBuffer,L'\\')) != NULL) + { + *pCurrent = L'/'; + pBuffer = pCurrent + 1; + } + + TUint32 index = Find(iTokenValue.pszString,fd); + if ( index == -1 ) + { + HANDLE hFile = ::MakeSISOpenFile (iTokenValue.pszString, GENERIC_READ, OPEN_EXISTING); + if (hFile == INVALID_HANDLE_VALUE) + { + // If we are using a search directory + if(iSearchDir[0] != '\0') + { + if (wcslen (iSearchDir) + wcslen (iTokenValue.pszString) < PATHMAX - 1) + { + WCHAR pszNewPath[PATHMAX]; + wcscpy(pszNewPath, iSearchDir); + wcscat(pszNewPath, iTokenValue.pszString); + HANDLE hFile = ::MakeSISOpenFile(pszNewPath, GENERIC_READ, OPEN_EXISTING); + if (hFile != INVALID_HANDLE_VALUE) wcscpy(iTokenValue.pszString, pszNewPath); + ::CloseHandle(hFile); + } + } + } + ::CloseHandle(hFile); + + fileIndex [iCurrentLang] = iSISXWriter.LoadFile (iTokenValue.pszString, &fileSize [iCurrentLang]); + compressedSize [iCurrentLang] = iSISXWriter.CompressedSize (); + + fd.SetFileIndex(fileIndex[iCurrentLang]); + fd.SetLengths (fileSize [iCurrentLang], compressedSize [iCurrentLang]); + ComputeAndSetHash(fd); + + hashes [iCurrentLang] = fd.Hash(); + + // Add new file to the map + std::wstring newfile(iTokenValue.pszString); + Set(newfile,fd); + } + else + { + fileIndex [iCurrentLang] = fd.FileIndex(); + fileSize [iCurrentLang] = fd.UncompressedLength(); + compressedSize [iCurrentLang] = fd.Length(); + hashes [iCurrentLang] = fd.Hash(); + } + } + GetNextToken (); + } + + ExpectToken('}'); + GetNextToken (); + + if(!packages) + { + ExpectToken('-'); + GetNextToken (); + + // Get the destination & options + ExpectToken(QUOTED_STRING_TOKEN); + CSISFileDescription file; + file.SetTarget (iTokenValue.pszString); + + GetNextToken (); + + if (iToken==',') + { + GetNextToken (); + CSISFileDescription::TSISInstOption type = file.InterpretOption (iTokenValue.pszString); + GetNextToken(); + if (type == CSISFileDescription::EInstFileRunOptionByMimeType) + { + ExpectToken(','); + GetNextToken (); + ExpectToken(QUOTED_STRING_TOKEN); + file.SetMimeType (iTokenValue.pszString); + GetNextToken (); + } + else + if (iToken==',') + { + do + { + + GetNextToken (); + file.InterpretOption (iTokenValue.pszString); + GetNextToken (); + + } while (iToken == ','); + + } + } + + for (unsigned index = 0; index < languageCount; index++) + { + if (index == 0) + { + aInstall.If ().InstallBlock ().AddFileDescription (file); + aInstall.If ().InstallBlock ().SetFileIndex (fileIndex [index]); + aInstall.If ().InstallBlock ().SetLengths (fileSize [index], compressedSize [index]); + aInstall.If ().InstallBlock ().SetHash (hashes[index]); + } + else + { + aInstall.If ().ElseIf (index - 1).InstallBlock ().AddFileDescription (file); + aInstall.If ().ElseIf (index - 1).InstallBlock ().SetFileIndex (fileIndex [index]); + aInstall.If ().ElseIf (index - 1).InstallBlock ().SetLengths (fileSize [index], compressedSize [index]); + aInstall.If ().ElseIf (index - 1).InstallBlock ().SetHash (hashes[index]); + } + } + } + else + { + ExpectToken(','); + GetNextToken (); + ExpectToken('('); + GetNextToken (); + + ExpectToken(NUMERIC_TOKEN); + GetNextToken (); + + ExpectToken(')'); + GetNextToken (); + + } + } + +void CPackageParser::ParseIfBlockL (CSISInstallBlock& aInstall) + { + iObserver.DoVerbage(L"processing IF block"); + + aInstall.AddIf (); + + ParseLogicalOp (aInstall.If ().Expression ()); + ParseEmbeddedBlockL (aInstall.If ().InstallBlock ()); + + while (iToken==ELSEIF_TOKEN) + { + GetNextToken (); + aInstall.If ().AddElseIf (); + ParseLogicalOp (aInstall.If ().ElseIfExpression ()); + ParseEmbeddedBlockL (aInstall.If ().ElseIf ().InstallBlock ()); + } + + if (iToken==ELSE_TOKEN) + { + GetNextToken (); + aInstall.If ().AddElse (); + // elseif true + ParseEmbeddedBlockL(aInstall.If ().ElseIf ().InstallBlock ()); + } + + ExpectToken(ENDIF_TOKEN); + GetNextToken (); + } + +void CPackageParser::ParseCommentL() +// Purpose : Parses a comment line (Does nothing, just throws the line away) +// Inputs : m_pkgPtr - The string to parse +// Returns : Success or failure + { + iObserver.DoVerbage(L"processing comment"); + + // parse to end of line + while (iPkgChar && (iPkgChar!='\n')) GetNextChar(); + GetNextToken (); + } + +void CPackageParser::ParseLogicalOp (CSISExpression& aExpression) + { + CSISExpression left; + + if (InterpretSis()) + { + std::wstring aOption = iTokenValue.pszString; + for(size_t i = 0; i < aOption.length(); ++i) + aOption.at(i) = towupper(aOption.at(i)); + + if (aOption.find(L"OPTION",0) != std::string::npos) + { + ReportInterpretSisError(ErrUserOptionsNotSupported); + } + } + + ParseRelation (left); + switch (iToken) + { + case AND_TOKEN: + case OR_TOKEN: + { + if (iToken==AND_TOKEN) + aExpression.SetOperator (CSISExpression::ELogOpAnd, left); + else + aExpression.SetOperator (CSISExpression::ELogOpOr, left); + GetNextToken (); + ParseLogicalOp (aExpression.RHS ()); + } + break; + default: + aExpression = left; + break; + } + } + + +void CPackageParser::ParseRelation(CSISExpression& aExpression) + { + CSISExpression left; + ParseUnary (left); + switch (iToken) + { + case '=': + case '>': + case '<': + case GE_TOKEN: + case LE_TOKEN: + case NE_TOKEN: + { + switch (iToken) + { + case '=': + aExpression.SetOperator (CSISExpression::EBinOpEqual, left); + break; + case '>': + aExpression.SetOperator (CSISExpression::EBinOpGreaterThan, left); + break; + case '<': + aExpression.SetOperator (CSISExpression::EBinOpLessThan, left); + break; + case GE_TOKEN: + aExpression.SetOperator (CSISExpression::EBinOpGreaterThanOrEqual, left); + break; + case LE_TOKEN: + aExpression.SetOperator (CSISExpression::EBinOpLessThanOrEqual, left); + break; + case NE_TOKEN: + aExpression.SetOperator (CSISExpression::EBinOpNotEqual, left); + break; + } + GetNextToken (); + ParseUnary (aExpression.RHS ()); + break; + } + default: + aExpression = left; + break; + } + } + +void CPackageParser::ParseUnary(CSISExpression& aExpression) + { + switch (iToken) + { + case NOT_TOKEN: + aExpression.SetOperator (CSISExpression::EUnaryOpNot); + GetNextToken (); + ParseUnary (aExpression.RHS ()); + break; + case APPCAP_TOKEN: + { // 2 arg function + GetNextToken (); + ExpectToken('('); + + aExpression.SetOperator (CSISExpression::EFuncAppProperties); + GetNextToken (); + ParseUnary (aExpression.LHS ()); + ExpectToken(','); + GetNextToken (); + ParseUnary (aExpression.RHS ()); +// GetNextToken (); + + ExpectToken(')'); + GetNextToken (); + break; + } + case EXISTS_TOKEN: + case DEVCAP_TOKEN: + { // 1 arg function + TOKEN token=iToken; + GetNextToken (); + ExpectToken('('); + GetNextToken (); + if (token==EXISTS_TOKEN) + { + aExpression.SetOperator (CSISExpression::EFuncExists); + ExpectToken(QUOTED_STRING_TOKEN); + GetNextToken (); + aExpression.SetValue (std::wstring (iTokenValue.pszString)); + } + else + { + aExpression.SetOperator (CSISExpression::EFuncDevProperties); + ParseUnary (aExpression.RHS ()); + } + ExpectToken(')'); + GetNextToken (); + break; + } + case VERSION_TOKEN: + { + /** + CR1125 - VERSION() function to allow for the evaluation of installed package versions + + The functions arguments are parsed and formatted into an argument string within + CPackageParser::ParseVersionArgs(). The SISString is then stored within the SISExpression + using the CSISExpression::EFuncExists TOperator enumeration for compatibility with old + versions of the SWI Server. + **/ + GetNextToken (); + ExpectToken('('); + + aExpression.SetOperator (CSISExpression::EFuncExists); + GetNextToken (); + aExpression.SetValue (ParseVersionArgs()); + + ExpectToken(')'); + GetNextToken (); + break; + } + + // Block to handle Supported_Language token used in package file + // This block sets the SISExpression with the corresponding fields + // like Operator = EFuncExists, Value = "/sys/install/supported_language/?10" + // (language ID for the example given below), + // Eg:supported_language = 10 + case SUPPORTED_LANG_TOKEN: + { + GetNextToken(); + ExpectToken('='); + + aExpression.SetOperator (CSISExpression::EFuncExists); + GetNextToken (); + aExpression.SetValue (ParseSupportedLangArgs()); + break; + } + + + default: + ParseFactor (aExpression); + break; + } + } + +void CPackageParser::ParseFactor(CSISExpression& aExpression) + { + switch (iToken) { + case '(': + { + GetNextToken (); + ParseLogicalOp (aExpression); + ExpectToken(')'); + } + break; + case QUOTED_STRING_TOKEN: + case ALPHA_TOKEN: + case NUMERIC_TOKEN: + { + switch (iToken) + { + case QUOTED_STRING_TOKEN: + aExpression.SetOperator (CSISExpression::EPrimTypeString); + aExpression.SetValue (std::wstring (iTokenValue.pszString)); + break; + case ALPHA_TOKEN: + { + if(!CompareNString(iTokenValue.pszString,L"option",6)) + { + WCHAR *temp,*end; + temp=&iTokenValue.pszString[6]; + DWORD optionNum = wcstol(temp, &end, 10); + if (end==temp || errno==ERANGE) + throw ErrUnknownVariable; + aExpression.SetOperator (CSISExpression::EPrimTypeOption); + aExpression.SetValue (optionNum); + } + else + { + aExpression.SetVariable (std::wstring (iTokenValue.pszString)); + } + } + break; + case NUMERIC_TOKEN: + aExpression.SetOperator (CSISExpression::EPrimTypeNumber); + aExpression.SetValue (iTokenValue.dwNumber); + break; + } + } + break; + default: + throw ErrBadCondFormat; + } + GetNextToken (); + } + +// Additional Functionality Provided By CR1125 +std::wstring CPackageParser::ParseVersionArgs() + { + std::wstring agrsString; + TInt32 vMaj = 0; + TInt32 vMin = 0; + TInt32 vBld = 0; + wchar_t* relation; + TVersion version; + + ExpectToken(NUMERIC_TOKEN); + CSISUid::TUid pUid = iTokenValue.dwNumber; + GetNextToken (); + + ExpectToken(','); + GetNextToken (); + + switch (iToken) + { + case '=': + relation = L"ET"; + break; + case '>': + relation = L"GT"; + break; + case '<': + relation = L"LT"; + break; + case GE_TOKEN: + relation = L"GE"; + break; + case LE_TOKEN: + relation = L"LE"; + break; + case NE_TOKEN: + relation = L"NE"; + break; + default: + throw ErrVersionInvalidRelationalOperator; + } + + GetNextToken (); + ExpectToken(','); + + version = ParseVersion(); + + vMaj = version.Major(); + vMin = version.Minor(); + vBld = version.Build(); + + + if(vMaj == -1 || vMin == -1 || vBld == -1) + { + // If a wildcard has been specified, throw a bad condition + throw ErrVersionWildcardsNotSupported; + } + else if(vMaj < 0 || vMin < 0 || vBld < 0) + { + // If a negative version component has been specified, throw a bad condition + throw ErrVersionNegativesNotSupported; + } + + // Integer to String Conversions + std::wstring pUidStr; + pUidStr = ConvertToString(pUid,std::hex); + + std::wstring vMajStr; + vMajStr = ConvertToString(vMaj,std::dec); + + std::wstring vMinStr; + vMinStr = ConvertToString(vMin,std::dec); + + std::wstring vBldStr; + vBldStr = ConvertToString(vBld,std::dec); + + // Construct the formatted argument string + agrsString = L"\\sys\\install\\pkgversion\\?"; + agrsString += L"0x"; + agrsString += pUidStr; + agrsString += L","; + agrsString += relation; + agrsString += L","; + agrsString += vMajStr; + agrsString += L","; + agrsString += vMinStr; + agrsString += L","; + agrsString += vBldStr; + + return agrsString; + } + +// Function added to parse the supported language token(suppoted_language) and +// provide the appropriate value string, which is set onto SISExpression. +// It returns a string like "\sys\install\supported_langauge\?01" if the parsed +// token is like "(((01)))" +std::wstring CPackageParser::ParseSupportedLangArgs() + { + std::wstring argsString; + TInt32 langId = 0; + TInt32 parenthesisCount = 0; + while ( iToken == '(' ) + { + GetNextToken(); + parenthesisCount++; + } + + ExpectToken(NUMERIC_TOKEN); + + langId = iTokenValue.dwNumber; + GetNextToken (); + while ( iToken == ')' && parenthesisCount) + { + GetNextToken(); + parenthesisCount--; + } + if (!(0 == parenthesisCount)) + { + throw ErrUnBalancedParenthesis; + } + std::wstring vLangIdStr; + vLangIdStr = ConvertToString(langId,std::dec); + + // Construct the formatted argument string + argsString = L"\\sys\\install\\supportedlanguage\\?"; + argsString += vLangIdStr; + + return argsString; + } + + +std::wstring CPackageParser::ConvertToString(const TInt32 aValue, std::ios_base& (*aBase)(std::ios_base&)) + { + std::wostringstream wOutStream; + + if((wOutStream << aBase << aValue).fail()) + { + throw ErrBadIntegerToStringConversion; + }; + + return wOutStream.str(); + } + +DWORD CPackageParser::ParseOption(const SParseOpt* options, DWORD dwNumOptions, DWORD* pdwOptions) +// Parse the options part of an input line + { + DWORD option=0; + ExpectToken(ALPHA_TOKEN); + // Look for the option + for(WORD wLoop = 0; wLoop < dwNumOptions; wLoop++) + { + if(CompareTwoString(iTokenValue.pszString,(wchar_t*) options[wLoop].pszOpt) == 0) + { + option=options[wLoop].dwOpt; + break; + } + } + if(wLoop == dwNumOptions) + throw ErrBadOption; + *pdwOptions |= option; + GetNextToken (); + return option; + } + +void CPackageParser::ExpectToken(TOKEN aToken) + { + if (iToken!=aToken) + { + wchar_t msg[255]=L"Expected "; + if (aToken<=LAST_TOKEN) + wcsncat(msg,GetTokenText(aToken),wcslen(GetTokenText(aToken))); + else + { + wchar_t tmp[2]={(wchar_t)aToken,0}; + wcsncat(msg,tmp,wcslen(tmp)); + } + wcsncat(msg,L" read ",wcslen(L" read ")); + if (iToken<=LAST_TOKEN) + wcsncat(msg,GetTokenText(iToken), wcslen(GetTokenText(iToken))); + else + { + wchar_t tmp[2]={(wchar_t)iToken,0}; + wcsncat(msg,tmp,wcslen(tmp)); + } + iObserver.DoErrMsg(msg); + throw ErrUnexpectedToken; + } + } + +const _TCHAR* CPackageParser::GetTokenText(TOKEN aToken) + { + switch(aToken) + { + case NUMERIC_TOKEN: + return L"numeric value"; + case ALPHA_TOKEN: + return L"alphanumeric value"; + case QUOTED_STRING_TOKEN: + return L"quoted string"; + case AND_TOKEN: + return L"AND"; + case OR_TOKEN: + return L"OR"; + case NOT_TOKEN: + return L"NOT"; + case EXISTS_TOKEN: + return L"EXISTS"; + case GE_TOKEN: + return L">="; + case LE_TOKEN: + return L"<="; + case NE_TOKEN: + return L"<>"; + case IF_TOKEN: + return L"IF"; + case ELSEIF_TOKEN: + return L"ELSEIF"; + case ELSE_TOKEN: + return L"ELSE"; + case ENDIF_TOKEN: + return L"ENDIF"; + default: + return L"?"; + } + } + +void CPackageParser::GetNextToken (const TBool aDisablePkgKeywordCheck) +// lexical analyzer + { + // skip any white space & newLine's + while (iPkgChar == '\n' || isspace(iPkgChar) || iPkgChar == 0xA0) + { + if (iPkgChar == '\n') + { + iObserver.SetLineNumber(++iLineNo); + } + GetNextChar(); + } + + if (iPkgChar == '\0') + iToken=EOF_TOKEN; + else if (IsNumericToken()) + { + GetNumericToken(); + iToken=NUMERIC_TOKEN; + } + else if (isalpha(iPkgChar)) + { // have some alphanumeric text + GetAlphaNumericToken(); + iToken=ALPHA_TOKEN; + // check if it is a PKG keyword only when the keyword check is not + // disabled by setting the paramter "aDisablePkgKeywordCheck" + if (!aDisablePkgKeywordCheck) + { + for(WORD wLoop = 0; wLoop < NUMPARSETOKENS; wLoop++) + { + if(CompareTwoString(iTokenValue.pszString, (wchar_t*)KTokens[wLoop].pszOpt) == 0) + { + iToken=KTokens[wLoop].dwOpt; + break; + } + } + } + } + else if (iPkgChar == '\"') + { // have a quoted string + GetStringToken(); + iToken=QUOTED_STRING_TOKEN; + } + else if (iPkgChar == '>') + { + GetNextChar(); + if (iPkgChar == '=') + { + iToken=GE_TOKEN; + GetNextChar(); + } + else + iToken='>'; + } + else if (iPkgChar == '<') + { + // check if start of an escaped string, e.g. <123>"abc" + if (GetStringToken()) + iToken=QUOTED_STRING_TOKEN; + else + { + GetNextChar(); + if (iPkgChar == '=') + { + iToken=LE_TOKEN; + GetNextChar(); + } + else if (iPkgChar == '>') + { + iToken=NE_TOKEN; + GetNextChar(); + } + else + iToken='<'; + } + } + else + { + iToken = iPkgChar; + GetNextChar(); + } + } + +bool CPackageParser::GetStringToken() +// Purpose : Parse a quoted string from the input line +// Inputs : m_pkgPtr - The string to parse +// pszString - The output string +// wMaxLength - The max length of pszString + { + DWORD wCount = 0; + bool done=false; + bool finished=false; + DWORD escapeChars = 0; + + while (!finished) + { + if (iPkgChar == '\"') + { + GetNextChar(); + while(iPkgChar && iPkgChar != '\"') + { + if(wCount < (MAX_STRING - 1)) + iTokenValue.pszString[wCount++] = iPkgChar; + else //We dont want the string with length greater than MAX_STRING to be cut off silently + throw ErrBadString; + GetNextChar(); + } + if(iPkgChar == '\0') + throw ErrBadString; + GetNextChar(); + done=true; + } + if (iPkgChar == '<') + { + iTokenValue.pszString[wCount] = L'\0'; + escapeChars=ParseEscapeChars(); + if (escapeChars>0) + { + done=true; + wCount+=escapeChars; + if (wCount>=MAX_STRING) wCount=MAX_STRING-1; + } + } + if (escapeChars==0 || iPkgChar != '\"') + finished=true; + } + + iTokenValue.pszString[wCount] = L'\0'; + return done; + } + +WORD CPackageParser::ParseEscapeChars() + { + WORD found=0; + WCHAR temp[MAX_STRING]; + while (iPkgChar == '<') + { + wcscpy(temp,iTokenValue.pszString); + DWORD fileOffset=::SetFilePointer(iFileHandle, 0L, NULL, FILE_CURRENT); + try + { + GetNextChar(); + GetNumericToken(); + if (iPkgChar=='>') + found++; + else + { + ::SetFilePointer(iFileHandle, fileOffset, NULL, FILE_BEGIN); + break; + } + } + catch (TParseException) + { + wcscpy(iTokenValue.pszString,temp); + ::SetFilePointer(iFileHandle, fileOffset, NULL, FILE_BEGIN); + break; + } + DWORD num=iTokenValue.dwNumber; + // watch for CP1252 escapes which aren't appropriate for UNICODE + if (num>=0x80 && num<=0x9F) throw ErrInvalidEscape; + DWORD len=wcslen(temp); + wcscpy(iTokenValue.pszString,temp); + if (len+2<=MAX_STRING) + { + iTokenValue.pszString[len]=(WCHAR)num; + len++; + iTokenValue.pszString[len]='\0'; + } + GetNextChar(); + } + return found; + } + +void CPackageParser::GetAlphaNumericToken() +// Purpose : Parse an alphanumeric string from the input line +// Inputs : m_pkgPtr - The string to parse +// pszString - The output string +// wMaxLength - The max length of pszString + { + WORD wCount = 0; + while(iPkgChar && (isalnum(iPkgChar) || ((iPkgChar) == '_'))) + { + if(wCount < (MAX_STRING - 1)) + iTokenValue.pszString[wCount++] = iPkgChar; + GetNextChar(); + } + iTokenValue.pszString[wCount] = L'\0'; + } + +bool CPackageParser::IsNumericToken() +// Purpose : Determines if the next lexeme is a numeric token + { + bool lexemeIsNumber = false; + if (iswdigit(iPkgChar)) + lexemeIsNumber = true; + else if (iPkgChar == '+' || iPkgChar == '-') + { + // we may have a number but we must look ahead one char to be certain + + WCHAR oldChar = iPkgChar; + DWORD fileOffset=::SetFilePointer(iFileHandle, 0L, NULL, FILE_CURRENT); + GetNextChar(); + lexemeIsNumber = iswdigit(iPkgChar) != FALSE; + iPkgChar = oldChar; + ::SetFilePointer(iFileHandle,fileOffset,NULL,FILE_BEGIN); + } + + return lexemeIsNumber; + } + + +void CPackageParser::GetNumericToken() +// Purpose : Parse a number from the input line +// Inputs : m_pkgPtr - The string to parse +// pdwNumber - The output number + { + WCHAR temp[MAX_STRING]; + LPWSTR end; + bool hexString = false; + DWORD dwBytesRead; + DWORD fileOffset=::SetFilePointer(iFileHandle, 0L, NULL, FILE_CURRENT); + + temp[0]=iPkgChar; + if (!::ReadFile(iFileHandle, &temp[1], (MAX_STRING-2)*sizeof(WCHAR), &dwBytesRead, NULL) || + dwBytesRead==0) + throw ErrReadFailed; + temp[1+dwBytesRead/sizeof(WCHAR)]='\0'; + hexString = (!CompareNString(temp, L"0x", 2) || !CompareNString(&temp[1], L"0x", 2)); + + iTokenValue.dwNumber = wcstoul(temp, &end, (hexString) ? 16 : 10); + + if (end==temp) throw ErrReadFailed; + if (errno==ERANGE) + throw ErrNumberOutOfRange; + ::SetFilePointer(iFileHandle, fileOffset+(end-temp-1)*sizeof(WCHAR), NULL, FILE_BEGIN); + GetNextChar(); + } + +void CPackageParser::GetNextChar() + { + DWORD dwBytesRead; + if (!::ReadFile(iFileHandle, (LPVOID)&iPkgChar, sizeof(WCHAR), &dwBytesRead, NULL) || + dwBytesRead!=sizeof(WCHAR)) + iPkgChar='\0'; + } + +void CPackageParser::ValidateVersion(TInt32& major, TInt32 &minor, TInt32 &build) + { + if((major > 127) || (minor > 99) || (build > 32767)) + { + iObserver.DoMsg(L"Warning : The valid version number ranges are : (Major: 0..127) (Minor: 0..99 ) (Build: 0..32,767)."); + } + } + +bool CPackageParser::DoesExist(LPWSTR pszFile, DWORD *pdwSize) +// Purpose : Attempt to determine whether the file exists (w. or W.out the search path), and gets +// it's file size. +// Inputs : pszFile - The file to find (as a UNICODE string) +// pdwSize - store its size here (set to zero if not found) +// Returns : Yes or No + + { + bool fFound = false; + *pdwSize = 0; + + try + { + HANDLE hFile = ::MakeSISOpenFile(pszFile, GENERIC_READ, OPEN_EXISTING); + if (hFile != INVALID_HANDLE_VALUE) + { + *pdwSize = ::GetFileSize(hFile, NULL); + ::CloseHandle(hFile); + fFound = true; + } + else + { + // If we are using a search directory + if(iSearchDir[0] != '\0') + { + + if (wcslen (iSearchDir) + wcslen (pszFile) < PATHMAX - 1) + { + wchar_t pszNewPath[PATHMAX]; + wcscpy(pszNewPath, iSearchDir); + wcscat(pszNewPath, pszFile); + HANDLE hFile = MakeSISOpenFile(pszNewPath, GENERIC_READ, OPEN_EXISTING); + if (hFile != INVALID_HANDLE_VALUE) + { + *pdwSize = ::GetFileSize(hFile, NULL); + CloseHandle(hFile); + wcscpy(pszFile, pszNewPath); + fFound = true; + } + } + } + } + } + catch (TUtilsException excp) + { + // ignore error if writing a stub file + if (!iMakeStub) throw excp; + iObserver.DoVerbage(L"warning :file does not exist"); + fFound=true; + } + return fFound; + } + +bool CPackageParser::DoesFileExist (std::wstring& aFileName, TUint64& aSize) + + { + if (aFileName.empty ()) return false; + bool found = false; + aSize = 0; + + try + { + HANDLE hFile = ::MakeSISOpenFile (aFileName.c_str (), GENERIC_READ, OPEN_EXISTING); + if (hFile == INVALID_HANDLE_VALUE) + { + // If we are using a search directory + if(iSearchDir[0] != '\0') + { + std::wstring newPath (std::wstring (iSearchDir) + aFileName); + hFile = ::MakeSISOpenFile (newPath.c_str (), GENERIC_READ, OPEN_EXISTING); + if (hFile != INVALID_HANDLE_VALUE) aFileName = newPath; + } + } + if (hFile != INVALID_HANDLE_VALUE) + { + aSize = GetSizeOfFile(hFile); + found = true; + } + } + catch (TUtilsException excp) + { + // ignore error if writing a stub file + if (!iMakeStub) throw excp; + iObserver.DoVerbage(L"warning :file does not exist"); + found=true; + } + return found; + } + +TUint32 CPackageParser::Find(wchar_t* aWhat, CSISFileDescription& aFileDesciption) + { + TUint32 ret = -1; + if ( iSrcFiles.find(aWhat) != iSrcFiles.end() ) + { + aFileDesciption = iSrcFiles[aWhat]; + ret = aFileDesciption.FileIndex(); + } + return ret; + } + +void CPackageParser::Set(std::wstring& aWhat, CSISFileDescription& aData) + { + iSrcFiles[aWhat] = aData; + } + +void CPackageParser::ReportInterpretSisError(TInterpretSisException aException) + { + iValidSISFile = false; + iObserver.AddInterpretSisError(aException); + } + +void CPackageParser::ComputeAndSetHash(CSISFileDescription& aFileDesc) + { + const CSISDataUnit& dataUnit = iSISXWriter.DataUnit(); + const CSISFileData& fileData = dataUnit.FileData(aFileDesc.FileIndex()); + // Compute the hash data for the file. + CSISHash tempSisHash; + TUint8 digest [SHA_DIGEST_LENGTH]; + memset (&digest, 0, SHA_DIGEST_LENGTH); +#ifdef GENERATE_ERRORS + if (CSISFieldRoot::IsBugToBeCreated (CSISFieldRoot::EBugHashError)) + { + for (unsigned index = 0; index < SHA_DIGEST_LENGTH; index++) + { + digest [index] = static_cast (rand () & 0xFF); + } + } + else +#endif // GENERATE_ERRORS + { + SHA1 (fileData.Data (), fileData.UncompressedSize (), digest); + } + aFileDesc.SetHash(digest, SHA_DIGEST_LENGTH); + } +