DPDEF142718 Incremental rebuild fails if dependent files deleted (resurrection through merge).
/*
* Copyright (c) 1995-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:
* @internalComponent * @released
* Rofsbuild Obey file class and its reader class.
*
*/
#include <string.h>
#ifdef __VC32__
#ifdef __MSVCDOTNET__
#include <strstream>
#include <iomanip>
#else //__MSVCDOTNET__
#include <strstrea.h>
#include <iomanip.h>
#endif //__MSVCDOTNET__
#else // !__VC32__
#ifdef __TOOLS2__
#include <sstream>
#include <iomanip>
#include <sys/stat.h>
using namespace std;
#else
#include <strstrea.h>
#include <iomanip.h>
#endif
#endif //__VC32__
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <e32std.h>
#include <e32std_private.h>
#include <e32rom.h>
#include <u32std.h>
#include <f32file.h>
#include "h_utl.h"
#include "r_obey.h"
#include "r_coreimage.h"
#include "patchdataprocessor.h"
#include "filesysteminterface.h"
#include "r_driveimage.h"
extern TInt gCodePagingOverride;
extern TInt gDataPagingOverride;
extern ECompression gCompress;
extern TBool gEnableStdPathWarning; // Default to not warn if destination path provided for a file is not in standard path.
#define _P(word) word, sizeof(word)-1 // match prefix, optionally followed by [HWVD]
#define _K(word) word, 0 // match whole word
const ObeyFileKeyword ObeyFileReader::iKeywords[] =
{
{_K("file"), 2,-2, EKeywordFile, "File to be copied into ROFS"},
{_K("data"), 2,-2, EKeywordData, "same as file"},
{_K("rofsname"), 1, 1, EKeywordRofsName, "output file for ROFS image"},
{_K("romsize"), 1, 1, EKeywordRomSize, "size of ROM image"},
{_P("hide"), 2, -1, EKeywordHide, "Exclude named file from ROM directory structure"},
{_P("alias"), 2, -2, EKeywordAlias, "Create alias for existing file in ROM directory structure"},
{_P("rename"), 2, -2, EKeywordRename, "Change the name of a file in the ROM directory structure"},
{_K("rofssize"), 1, 1, EKeywordRofsSize, "maximum size of ROFS image"},
{_K("romchecksum"), 1, 1, EKeywordRofsChecksum, "desired 32-bit checksum value for the whole image"},
{_K("version"), 1, 1, EKeywordVersion, "ROFS image version number"},
{_K("time"), 1,-1, EKeywordTime, "ROFS image timestamp"},
{_K("extensionrofs"),1+2, 1, EKeywordExtensionRofs, "Start of definition of optional Extension ROFS"},
{_K("extensionrofsname"),1, 1, EKeywordCoreRofsName, "ROFS image on which extension ROFS is based"},
{_K("rem"), 0, 0, EKeywordNone, "comment"},
{_K("stop"), 0, 0, EKeywordNone, "Terminates OBEY file prematurely"},
{_K("romchecksum"), 1, 1, EKeywordRomChecksum, "desired 32-bit checksum value for the whole ROFS image"},
{_K("coreimage"), 1, 1, EKeywordCoreImage, "Core image to be used for extension directory structure"},
{_K("autosize"), 1, 1, EKeywordRofsAutoSize, "Automatically adjust maximum image size to actual used"},
{_K("pagingoverride"), 1, 1, EKeywordPagingOverride, "Overide the demand paging attributes for every file in ROM, NOPAGING|DEFAULTUNPAGED|DEFAULTPAGED"},
{_K("codepagingoverride"), 1, 1, EKeywordCodePagingOverride, "Overide the code paging attributes for every file in ROM, NOPAGING|DEFAULTUNPAGED|DEFAULTPAGED"},
{_K("datapagingoverride"), 1, 1, EKeywordDataPagingOverride, "Overide the data paging attributes for every file in ROM, NOPAGING|DEFAULTUNPAGED|DEFAULTPAGED"},
{_K("dataimagename"),1, 1,EKeywordDataImageName, "Data Drive image file name"},
{_K("dataimagefilesystem"),1, 1,EKeywordDataImageFileSystem, "Drive image file system format"},
{_K("dataimagesize"),1, 1,EKeywordDataImageSize, "Maximum size of Data Drive image"},
{_K("volume"),1, -1,EKeywordDataImageVolume, "Volume Label of Data Drive image"},
{_K("sectorsize"),1, 1,EKeywordDataImageSectorSize, "Sector size(in bytes) of Data Drive image"},
{_K("fattable"),1, 1,EKeywordDataImageNoOfFats, "Number of FATs in the Data Drive image"},
// things we don't normally report in the help information
{_K("trace"), 1, 1, EKeywordTrace, "(ROMBUILD activity trace flags)"},
{_K("filecompress"),2, -2,EKeywordFileCompress,"Non-XIP Executable to be loaded into the ROM compressed" },
{_K("fileuncompress"),2, -2,EKeywordFileUncompress,"Non-XIP Executable to be loaded into the ROM uncompressed" },
{_K("patchdata"),2, 5,EKeywordPatchDllData, "Patch exported data"},
{_K("imagename"), 1, 1, EKeywordSmrImageName, "output file for SMR image"},
{_K("hcrdata"), 1, 1, EKeywordSmrFileData, "file data for HCR SMR image"},
{_K("formatversion"), 1, 1, EKeywordSmrFormatVersion, "format version for HCR SMR image"},
{_K("payloadflags"), 1, 1, EKeywordSmrFlags, "payload flags for the HCR SMR image"},
{_K("payloaduid"), 1, 1, EKeywordSmrUID, "payload UID for the HCR SMR image"},
{0,0,0,0,EKeywordNone,""}
};
extern TInt isNumber(TText *aString);
extern TInt getNumber(TText *aStr);
void ObeyFileReader::KeywordHelp() // static
{
cout << "Obey file keywords:\n";
const ObeyFileKeyword* k=0;
for (k=iKeywords; k->iKeyword!=0; k++)
{
if (k->iHelpText==0)
continue;
if (k->iHelpText[0]=='(' && !H.iVerbose)
continue; // don't normally report things in (parentheses)
char buf[32];
sprintf(buf, "%-20s", k->iKeyword);
if (k->iKeywordLength)
memcpy(buf+k->iKeywordLength,"[HWVD]",6);
if (H.iVerbose)
sprintf(buf+20,"%2d",k->iNumArgs);
cout << " " << buf << " " << k->iHelpText << endl;
}
cout << endl;
cout << "File attributes:\n";
const FileAttributeKeyword* f=0;
for (f=iAttributeKeywords; f->iKeyword!=0; f++)
{
if (f->iHelpText==0)
continue;
if (f->iHelpText[0]=='(' && !H.iVerbose)
continue; // don't normally report things in (parentheses)
char buf[32];
sprintf(buf, "%-20s", f->iKeyword);
if (H.iVerbose)
sprintf(buf+20,"%2d",k->iNumArgs);
cout << " " << buf << " " << f->iHelpText << endl;
}
cout << endl;
}
ObeyFileReader::ObeyFileReader(TText* aFileName):
iObeyFile(0),iMark(0), iMarkLine(0), iCurrentMark(0), iCurrentLine(0), imaxLength(0)
{
iFileName = new TText[strlen((const char *)aFileName)+1];
strcpy((char *)iFileName,(const char *)aFileName);
iNumWords = 0 ;
for(unsigned int i = 0 ; i < KNumWords ; i++)
iWord[i] = 0 ;
iSuffix = new TText();
iLine = 0 ;
iCurrentObeyStatement = 0 ;
}
ObeyFileReader::~ObeyFileReader()
{
if (iObeyFile)
fclose(iObeyFile);
iObeyFile=0;
delete [] iFileName;
delete [] iLine;
delete [] iCurrentObeyStatement;
}
TBool ObeyFileReader::Open()
//
// Open the file & return a status
//
{
if (!iFileName)
{
return EFalse;
}
iObeyFile = fopen((const char *)iFileName,"r");
if (!iObeyFile)
{
Print(EError,"Cannot open obey file %s\n",iFileName);
return EFalse;
}
if (SetLineLengthBuffer() != KErrNone)
{
Print(EError,"Insufficent Memory to Continue.");
return EFalse;
}
return ETrue;
}
TInt ObeyFileReader::SetLineLengthBuffer()
// Get the Max Line length for the given obey file and allocate the buffer.
{
char ch = '\0';
TInt length = 0;
Rewind();
while ((ch = (char)fgetc(iObeyFile)) != EOF)
{
length++;
if (ch == '\n')
{
if (length > imaxLength)
imaxLength = length;
length = 0;
}
}
if (length > imaxLength)
imaxLength = length;
if (0 == imaxLength)
{
Print(EError,"Empty obey file passed as input.");
exit(-1);
}
else if (imaxLength < 2)
{
Print(EError,"Invalid obey file passed as input.");
exit(-1);
}
Rewind();
iLine = new TText[imaxLength+1];
if(!iLine)
return KErrNoMemory;
return KErrNone;
}
void ObeyFileReader::Mark()
{
iMark = iCurrentMark;
iMarkLine = iCurrentLine-1;
}
void ObeyFileReader::MarkNext()
{
iMark = ftell(iObeyFile);
iMarkLine = iCurrentLine;
}
void ObeyFileReader::Rewind()
{
fseek(iObeyFile,iMark,SEEK_SET);
iCurrentMark = iMark;
iCurrentLine = iMarkLine;
}
void ObeyFileReader::CopyWord(TInt aIndex, TText*& aString)
{
aString = new TText[strlen((const char *)iWord[aIndex])+1];
strcpy((char *)aString, (const char *)iWord[aIndex]);
}
TInt ObeyFileReader::ReadAndParseLine()
{
if (feof(iObeyFile))
return KErrEof;
iCurrentLine++;
iCurrentMark = ftell(iObeyFile);
iLine[0]='\0';
fgets((char*)iLine,imaxLength+1,iObeyFile);
iCurrentObeyStatement = new TText[imaxLength+1];
strcpy((char*)iCurrentObeyStatement,(char*)iLine);
iNumWords = Parse();
return KErrNone;
}
TInt ObeyFileReader::NextLine(TInt aPass, enum EKeyword& aKeyword)
{
NextLine:
TInt err = ReadAndParseLine();
if (err == KErrEof)
return KErrEof;
if (iNumWords == 0 || stricmp((const char*)iWord[0], "rem")==0)
goto NextLine;
if (stricmp((const char*)iWord[0], "stop")==0)
return KErrEof;
const ObeyFileKeyword* k=0;
for (k=iKeywords; k->iKeyword!=0; k++)
{
if (k->iKeywordLength == 0)
{
// Exact case-insensitive match on keyword
if (stricmp((const char*)iWord[0], k->iKeyword) != 0)
continue;
iSuffix = 0;
}
else
{
// Prefix match
if (strnicmp((const char*)iWord[0], k->iKeyword, k->iKeywordLength) != 0)
continue;
// Suffix must be empty, or a variant number in []
iSuffix = iWord[0]+k->iKeywordLength;
if (*iSuffix != '\0' && *iSuffix != '[')
continue;
}
// found a match
if ((k->iPass & aPass) == 0)
goto NextLine;
if (k->iNumArgs>=0 && (1+k->iNumArgs != iNumWords))
{
Print(EError, "Incorrect number of arguments for keyword %s on line %d.\n",
iWord[0], iCurrentLine);
goto NextLine;
}
if (k->iNumArgs<0 && (1-k->iNumArgs > iNumWords))
{
Print(EError, "Too few arguments for keyword %s on line %d.\n",
iWord[0], iCurrentLine);
goto NextLine;
}
aKeyword = k->iKeywordEnum;
return KErrNone;
}
if (aPass == 1)
Print(EWarning, "Unknown keyword '%s'. Line %d ignored\n", iWord[0], iCurrentLine);
goto NextLine;
}
inline TBool ObeyFileReader::IsGap(char ch)
{
return (ch==' ' || ch=='=' || ch=='\t');
}
TInt ObeyFileReader::Parse()
//
// splits a line into words, and returns the number of words found
//
{
TInt i;
TText *letter=iLine;
TText *end=iLine+strlen((char *)iLine);
for (i=0; (TUint)i<KNumWords; i++)
iWord[i]=end;
enum TState {EInWord, EInQuotedWord, EInGap};
TState state=EInGap;
i=0;
while ((TUint)i<KNumWords && letter<end)
{
char ch=*letter;
if (ch==0)
break;
if (ch=='\n')
{
*letter='\0'; // remove trailing newline left by fgets
break;
}
switch (state)
{
case EInGap:
if (ch=='\"')
{
if (letter[1]!=0 && letter[1]!='\"')
iWord[i++]=letter+1;
state=EInQuotedWord;
}
else if (!IsGap(ch))
{
iWord[i++]=letter;
state=EInWord;
}
else
*letter=0;
break;
case EInWord:
if (ch=='\"')
{
*letter=0;
if (letter[1]!=0 && letter[1]!='\"')
iWord[i++]=letter+1;
state=EInQuotedWord;
}
else if (IsGap(ch))
{
*letter=0;
state=EInGap;
}
break;
case EInQuotedWord:
if (ch=='\"')
{
*letter=0;
state=EInGap;
}
break;
}
letter++;
}
return i;
}
void ObeyFileReader::ProcessTime(TInt64& aTime)
//
// Process the timestamp
//
{
char timebuf[256];
if (iNumWords>2)
sprintf(timebuf, "%s_%s", iWord[1], iWord[2]);
else
strcpy(timebuf, (char*)iWord[1]);
TInt r=StringToTime(aTime, timebuf);
if (r==KErrGeneral)
{
Print(EError, "incorrect format for time keyword on line %d\n", iCurrentLine);
exit(0x670);
}
if (r==KErrArgument)
{
Print(EError, "Time out of range on line %d\n", iCurrentLine);
exit(0x670);
}
}
TInt64 ObeyFileReader::iTimeNow=0;
void ObeyFileReader::TimeNow(TInt64& aTime)
{
if (iTimeNow==0)
{
TInt sysTime=time(0); // seconds since midnight Jan 1st, 1970
sysTime-=(30*365*24*60*60+7*24*60*60); // seconds since midnight Jan 1st, 2000
TInt64 daysTo2000AD=730497;
TInt64 t=daysTo2000AD*24*3600+sysTime; // seconds since 0000
t=t+3600; // BST (?)
iTimeNow=t*1000000; // milliseconds
}
aTime=iTimeNow;
}
/**
Funtion to get the current oby file line
*/
TText* ObeyFileReader::GetCurrentObeyStatement() const
{
return iCurrentObeyStatement;
}
// File attributes.
const FileAttributeKeyword ObeyFileReader::iAttributeKeywords[] =
{
{"attrib",3 ,0,1,EAttributeAtt, "File attributes in ROM file system"},
{"exattrib",3 ,0,1,EAttributeAttExtra, "File extra attributes in ROM file system"},
// {_K("compress") ,1,1,EAttributeCompress, "Compress file"},
{"stack",3 ,1,1,EAttributeStack, "?"},
{"fixed",3 ,1,0,EAttributeFixed, "Relocate to a fixed address space"},
{"priority",3 ,1,1,EAttributePriority, "Override process priority"},
{_K("uid1") ,1,1,EAttributeUid1, "Override first UID"},
{_K("uid2") ,1,1,EAttributeUid2, "Override second UID"},
{_K("uid3") ,1,1,EAttributeUid3, "Override third UID"},
{_K("heapmin") ,1,1,EAttributeHeapMin, "Override initial heap size"},
{_K("heapmax") ,1,1,EAttributeHeapMax, "Override maximum heap size"},
{_K("capability") ,1,1,EAttributeCapability, "Override capabilities"},
{_K("unpaged") ,1,0,EAttributeUnpaged, "Don't page code or data for this file"},
{_K("paged") ,1,0,EAttributePaged, "Page code and data for this file"},
{_K("unpagedcode") ,1,0,EAttributeUnpagedCode, "Don't page code for this file"},
{_K("pagedcode") ,1,0,EAttributePagedCode, "Page code for this file"},
{_K("unpageddata") ,1,0,EAttributeUnpagedData, "Don't page data for this file"},
{_K("pageddata") ,1,0,EAttributePagedData, "Page data for this file"},
{0,0,0,0,EAttributeAtt,0}
};
TInt ObeyFileReader::NextAttribute(TInt& aIndex, TInt aHasFile, enum EFileAttribute& aKeyword, TText*& aArg)
{
NextAttribute:
if (aIndex >= iNumWords)
return KErrEof;
TText* word=iWord[aIndex++];
const FileAttributeKeyword* k;
for (k=iAttributeKeywords; k->iKeyword!=0; k++)
{
if (k->iKeywordLength == 0)
{
// Exact match on keyword
if (stricmp((const char*)word, k->iKeyword) != 0)
continue;
}
else
{
// Prefix match
if (strnicmp((const char*)word, k->iKeyword, k->iKeywordLength) != 0)
continue;
}
// found a match
if (k->iNumArgs>0)
{
TInt argIndex = aIndex;
aIndex += k->iNumArgs; // interface only really supports 1 argument
if (aIndex>iNumWords)
{
Print(EError, "Missing argument for attribute %s on line %d\n", word, iCurrentLine);
return KErrArgument;
}
aArg=iWord[argIndex];
}
if (k->iIsFileAttribute && !aHasFile)
{
Print(EError, "File attribute %s applied to non-file on line %d\n", word, iCurrentLine);
return KErrNotSupported;
}
aKeyword=k->iAttributeEnum;
return KErrNone;
}
Print(EWarning, "Unknown attribute '%s' skipped on line %d\n", word, iCurrentLine);
goto NextAttribute;
}
/**
Constructor:
1.Obey file instance.
2.used by both rofs and datadrive image.
@param aReader - obey file reader object.
*/
CObeyFile::CObeyFile(ObeyFileReader& aReader):
iRomFileName(NULL),
iExtensionRofsName(0),
iKernelRofsName(0),
iRomSize(0),
iVersion(0,0,0),
iCheckSum(0),
iNumberOfFiles(0),
iTime(0),
iRootDirectory(0),
iNumberOfDataFiles(0),
iDriveFileName(0),
iDataSize(0),
iDriveFileFormat(0),
iConfigurableFatAttributes(new ConfigurableFatAttributes),
iReader(aReader),
iMissingFiles(0),
iLastExecutable(0),
iFirstFile(0),
iCurrentFile(0),
iAutoSize(EFalse),
iAutoPageSize(4096),
iPagingOverrideParsed(0),
iCodePagingOverrideParsed(0),
iDataPagingOverrideParsed(0),
iPatchData(new CPatchDataProcessor)
{
iNextFilePtrPtr = &iFirstFile ;
}
/**
Obey file Destructor.
1.Release the tree memory.
2.Release all allocated memory if any.
*/
CObeyFile::~CObeyFile()
//
// Destructor
//
{
if(iDriveFileName)
delete[] iDriveFileName;
if(iDriveFileFormat)
delete[] iDriveFileFormat;
iRootDirectory->deleteTheFirstNode();
iRootDirectory->InitializeCount();
Release();
delete [] iRomFileName;
if (iRootDirectory)
iRootDirectory->Destroy();
delete iConfigurableFatAttributes;
delete iPatchData;
}
TBool CObeyFile::AutoSize()
{
return iAutoSize;
}
TUint32 CObeyFile::AutoPageSize()
{
return iAutoPageSize;
}
void CObeyFile::Release()
//
// Free resources not needed after building a ROM
//
{
iFirstFile = 0;
iNextFilePtrPtr = &iFirstFile;
}
TRomBuilderEntry *CObeyFile::FirstFile()
{
iCurrentFile = iFirstFile;
return iCurrentFile;
}
TRomBuilderEntry *CObeyFile::NextFile()
{
iCurrentFile = iCurrentFile ? iCurrentFile->iNext : 0;
return iCurrentFile;
}
TText* CObeyFile::ProcessCoreImage()
{
// check for coreimage keyword and return filename
iReader.Rewind();
enum EKeyword keyword;
TText* coreImageFileName = 0;
while (iReader.NextLine(1,keyword) != KErrEof)
{
if (keyword == EKeywordCoreImage)
{
#if defined(__TOOLS2__) && defined (_STLP_THREADS)
istringstream val(iReader.Word(1),(ios_base::in+ios_base::out));
#elif __TOOLS2__
istringstream val(iReader.Word(1),(std::_Ios_Openmode)(ios_base::in+ios_base::out));
#else
istrstream val(iReader.Word(1),strlen(iReader.Word(1)));
#endif
iReader.CopyWord(1, coreImageFileName);
iReader.MarkNext(); // ready for processing extension
break;
}
}
return coreImageFileName;
}
void CObeyFile::SkipToExtension()
{
iReader.Rewind();
enum EKeyword keyword;
while (iReader.NextLine(1,keyword) != KErrEof)
{
if (keyword == EKeywordExtensionRofs)
{
iReader.Mark(); // ready for processing extension
break;
}
}
}
TInt CObeyFile::ProcessRofs()
{
//
// First pass through the obey file to set up key variables
//
iReader.Rewind();
TInt count=0;
enum EKeyword keyword;
while (iReader.NextLine(1,keyword) != KErrEof)
{
if (keyword == EKeywordExtensionRofs)
{
if (count==0)
return KErrNotFound; // no core ROFS, just extension ROFSs.
break;
}
count++;
if (! ProcessKeyword(keyword))
return KErrGeneral;
}
if (!GotKeyVariables())
return KErrGeneral;
//
// second pass to process the file specifications in the obey file building
// up the TRomNode directory structure and the TRomBuilderEntry list
//
iReader.Rewind();
iRootDirectory = new TRomNode((TText*)"");
iLastExecutable = iRootDirectory;
TInt align=0;
while (iReader.NextLine(2,keyword)!=KErrEof)
{
if (keyword == EKeywordExtensionRofs)
break;
if (keyword == EKeywordHide)
keyword = EKeywordHideV2;
switch (keyword)
{
case EKeywordHide:
case EKeywordAlias:
case EKeywordRename:
if (!ProcessRenaming(keyword))
return KErrGeneral;
break;
case EKeywordPatchDllData:
{
// Collect patchdata statements to process at the end
StringVector patchDataTokens;
SplitPatchDataStatement(patchDataTokens);
iPatchData->AddPatchDataStatement(patchDataTokens);
break;
}
default:
if (!ProcessFile(align, keyword))
return KErrGeneral;
align=0;
break;
}
}
if(!ParsePatchDllData())
return KErrGeneral;
iReader.Mark(); // ready for processing the extension rom(s)
if (iMissingFiles!=0)
{
return KErrGeneral;
}
if ( 0 == iNumberOfFiles )
{
Print(EError, "No files specified.\n");
return KErrGeneral;
}
return KErrNone;
}
TBool CObeyFile::Process()
{
TBool result = ETrue;
iReader.Rewind();
enum EKeyword keyword;
while(iReader.NextLine(1, keyword) != KErrEof)
{
String key = iReader.Word(0);
String value = iReader.Word(1);
if(iKeyValues.find(key) != iKeyValues.end())
{
iKeyValues[key].push_back(value);
}
else
{
StringVector values;
values.push_back(value);
iKeyValues[key]=values;
}
}
return result;
}
StringVector CObeyFile::getValues(const String& aKey)
{
StringVector values;
if(iKeyValues.find(aKey) != iKeyValues.end())
{
values = iKeyValues[aKey];
}
return values;
}
/**
Process drive obey file and construct the tree.
@return - Return the status,
'KErrnone' for Success,
'KErrGeneral' for failure (required keywords not there in obey file or failed
to construct the tree).
*/
TInt CObeyFile::ProcessDataDrive()
{
iReader.Rewind();
enum EKeyword keyword;
// First pass through the obey file to set up key variables
while (iReader.NextLine(1,keyword) != KErrEof)
{
if (!ProcessDriveKeyword(keyword))
return KErrGeneral;
}
if (!GotKeyDriveVariables())
return KErrGeneral;
// Second pass to process the file specifications in the obey file.
// Build the TRomNode directory structure and the TRomBuilderEntry list
iReader.Rewind();
iRootDirectory = new TRomNode((TText*)"//");
iLastExecutable = iRootDirectory;
while(iReader.NextLine(2,keyword)!=KErrEof)
{
switch (keyword)
{
case EKeywordPatchDllData:
{ // Collect patchdata statements to process at the end
StringVector patchDataTokens;
SplitPatchDataStatement(patchDataTokens);
iPatchData->AddPatchDataStatement(patchDataTokens);
break;
}
case EKeywordHide:
case EKeywordFile:
case EKeywordData:
case EKeywordFileCompress:
case EKeywordFileUncompress:
if (!ProcessDriveFile(keyword))
return KErrGeneral;
break;
default:
break;
}
}
if(!ParsePatchDllData())
return KErrGeneral;
if (iMissingFiles)
{
Print(EError, "Source Files Missing.\n");
return KErrGeneral;
}
if (!iNumberOfFiles)
Print(EWarning,"No files specified.\n");
return KErrNone;
}
/**
Process and stores the keyword information.
@param aKeyword - keyword to update its value to variables.
@return - Return the status i.e Success,
*/
TBool CObeyFile::ProcessDriveKeyword(enum EKeyword aKeyword)
{
TBool success = ETrue;
switch (aKeyword)
{
case EKeywordDataImageName:
iReader.CopyWord(1, iDriveFileName);
break;
case EKeywordDataImageFileSystem:
iReader.CopyWord(1, iDriveFileFormat);
break;
case EKeywordDataImageSize:
{
char* bigString = iReader.Word(1);
if(*bigString == '\0')
{
Print(EWarning,"Not a valid Image Size. Default size is considered\n");
break;
}
#ifdef __LINUX__
errno = 0;
iDataSize = strtoll(bigString,NULL,10);
if((iDataSize == LONG_MAX) || (iDataSize == LONG_MIN) ||(errno == ERANGE))
{
Print(EWarning,"Invalid Range. Default size is considered\n");
}
#else
iDataSize = _atoi64(bigString);
#endif
}
break;
case EKeywordDataImageVolume:
{
// Get the volume label provided by using "volume" keyword.
// e.g. vlolume = NO NAME
String volumeLabel = (char*)iReader.GetCurrentObeyStatement();
String volumeLabelKeyword = "volume";
TUint position = volumeLabel.find(volumeLabelKeyword.c_str(),0,volumeLabelKeyword.size());
position += volumeLabelKeyword.size();
if (volumeLabel.find('=',position) != std::string::npos)
{
position=volumeLabel.find('=',position);
++position;
}
position = volumeLabel.find_first_not_of(' ',position);
if (position != std::string::npos)
{
volumeLabel = volumeLabel.substr(position);
// Remove the new line character from the end
position = volumeLabel.find_first_of("\r\n");
if (position != std::string::npos)
volumeLabel = volumeLabel.substr(0,position);
iConfigurableFatAttributes->iDriveVolumeLabel = volumeLabel.data();
}
else
{
Print(EWarning,"Value for Volume Label is not provided. Default value is considered.\n");
}
break;
}
case EKeywordDataImageSectorSize:
{
char* bigString = iReader.Word(1);
TInt sectorSize = atoi(bigString);
if(sectorSize <= 0)
{
Print(EWarning,"Invalid Sector Size value. Default value is considered.\n");
}
else
{
iConfigurableFatAttributes->iDriveSectorSize = atoi(bigString);
}
}
break;
case EKeywordDataImageNoOfFats:
{
char* bigString = iReader.Word(1);
TInt noOfFats = atoi(bigString);
if (noOfFats <=0)
{
Print(EWarning,"Invalid No of FATs specified. Default value is considered.\n");
}
else
{
iConfigurableFatAttributes->iDriveNoOfFATs = atoi(bigString);
}
}
break;
default:
// unexpected keyword iReader.Word(0), keep going.
break;
}
return success;
}
/**
Checks whether obeyfile has supplied enough variables to continue.
@return - Return the status
ETrue - Supplied valid values,
EFalse- Not valied values.
*/
TBool CObeyFile::GotKeyDriveVariables()
{
TBool retVal=ETrue;
// Mandatory keywords
if (iDriveFileName==0)
{
Print(EError,"The name of the image file has not been supplied.\n");
Print(EError,"Use the keyword \"dataimagename\".\n");
retVal = EFalse;
}
// Check for '-'ve entered value.
if(iDataSize <= 0)
{
Print(EWarning,"Image Size should be positive. Default size is Considered.\n");
}
// File system format.
if(iDriveFileFormat==0)
{
Print(EError,"The name of the file system not been supplied.\n");
Print(EError,"Use the keyword \"dataimagefilesystem\".\n");
retVal = EFalse;
}
// Checking the validity of file system format.
if(iDriveFileFormat)
{
strupr((char *)iDriveFileFormat);
enum TFileSystem check = (TFileSystem)0;
if(!(CDriveImage::FormatTranslation(iDriveFileFormat,check)))
{
Print(EError,"The name of the file system not supported : %s\n",iDriveFileFormat);
retVal = EFalse;
}
}
if(retVal)
Print(ELog,"\nCreating Data Drive image : %s\n", iDriveFileName);
return retVal;
}
/**
Process a parsed line to set up one or more new TRomBuilder entry objects.
@param - obey file keyword.
// iWord[0] = the keyword (file,)
// iWord[1] = the PC pathname
// iWord[2] = the EPOC pathname
// iWord[3] = start of the file attributes
@return - Return the status
ETrue - Successful generation of tree.
EFalse- Fail to generate the tree.
*/
TBool CObeyFile::ProcessDriveFile(enum EKeyword aKeyword)
{
TBool isPeFile = ETrue;
TBool aFileCompressOption, aFileUncompressOption;
TInt epocPathStart=2;
aFileCompressOption = aFileUncompressOption = EFalse;
// do some validation of the keyword
TInt currentLine = iReader.CurrentLine();
switch (aKeyword)
{
case EKeywordData:
case EKeywordHide:
isPeFile = EFalse;
break;
case EKeywordFile:
break;
case EKeywordFileCompress:
aFileCompressOption = ETrue;
break;
case EKeywordFileUncompress:
aFileUncompressOption = ETrue;
break;
default:
return EFalse;
}
if (aKeyword!=EKeywordHide)
{
// check the PC file exists
char* nname = NormaliseFileName(iReader.Word(1));
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
ifstream test(nname);
#else //!__MSVCDOTNET__
ifstream test(nname, ios::nocreate);
#endif //__MSVCDOTNET__
if (!test)
{
Print(EError,"Cannot open file %s for input.\n",iReader.Word(1));
iMissingFiles++;
}
test.close();
if(nname)
free(nname);
nname = 0;
}
else
epocPathStart=1;
iNumberOfFiles++;
TBool endOfName=EFalse;
TText *epocStartPtr=IsValidFilePath(iReader.Text(epocPathStart));
TText *epocEndPtr=epocStartPtr;
if (epocStartPtr==NULL)
{
Print(EError, "Invalid destination path on line %d\n",currentLine);
return EFalse;
}
TRomNode* dir=iRootDirectory;
TRomNode* subDir=0;
TRomBuilderEntry *file=0;
while (!endOfName)
{
endOfName = GetNextBitOfFileName(&epocEndPtr);
if (endOfName) // file
{
TRomNode* alreadyExists=dir->FindInDirectory(epocStartPtr);
if ((aKeyword != EKeywordHide) && alreadyExists) // duplicate file
{
Print(EError, "Duplicate file for %s on line %d\n",iReader.Word(1),iReader.CurrentLine());
return EFalse;
}
else if((aKeyword == EKeywordHide) && (alreadyExists))
{
alreadyExists->iEntry->iHidden = ETrue;
alreadyExists->iHidden = ETrue;
return ETrue;
}
else if((aKeyword == EKeywordHide) && (!alreadyExists))
{
Print(EWarning, "Hiding non-existent file %s on line %d\n",iReader.Word(1),iReader.CurrentLine());
return ETrue;
}
file = new TRomBuilderEntry(iReader.Word(1), epocStartPtr);
file->iExecutable=isPeFile;
if( aFileCompressOption )
{
file->iCompressEnabled = ECompressionCompress;
}
else if(aFileUncompressOption )
{
file->iCompressEnabled = ECompressionUncompress;
}
TRomNode* node=new TRomNode(epocStartPtr, file);
if (node==0)
return EFalse;
TInt r=ParseFileAttributes(node, file, aKeyword);
if (r!=KErrNone)
return EFalse;
if(gCompress != ECompressionUnknown)
{
node->iFileUpdate = ETrue;
}
if((node->iOverride) || (aFileCompressOption) || (aFileUncompressOption))
{
node->iFileUpdate = ETrue;
}
dir->AddFile(node); // to drive directory structure.
}
else
{
// directory
subDir = dir->FindInDirectory(epocStartPtr);
if (!subDir) // sub directory does not exist
{
if(aKeyword==EKeywordHide)
{
Print(EWarning, "Hiding non-existent file %s on line %d\n",iReader.Word(1),iReader.CurrentLine());
return ETrue;
}
subDir = dir->NewSubDir(epocStartPtr);
if (!subDir)
return EFalse;
}
dir=subDir;
epocStartPtr = epocEndPtr;
} // end of else.
}
return ETrue;
}
TInt CObeyFile::SetStackSize(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'stack'.\n");
aNode->SetStackSize( getNumber(aStr) );
return KErrNone;
}
TInt CObeyFile::SetHeapSizeMin(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'heapmin'.\n");
aNode->SetHeapSizeMin( getNumber(aStr) );
return KErrNone;
}
TInt CObeyFile::SetHeapSizeMax(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'heapmax'.\n");
aNode->SetHeapSizeMax( getNumber(aStr) );
return KErrNone;
}
TInt CObeyFile::SetCapability(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr))
{
Print(EDiagnostic,"Old style numeric CAPABILTY specification ignored.\n");
return KErrNone;
}
SCapabilitySet cap;
TInt r = ParseCapabilitiesArg(cap, (char*)aStr);
if( KErrNone == r )
{
aNode->SetCapability( cap );
}
return r;
}
TInt CObeyFile::SetPriority(TRomNode *aNode, TText *aStr)
{
TProcessPriority priority;
if (isNumber(aStr))
{
priority = (TProcessPriority)getNumber(aStr);
}
else
{
char *str=(char *)aStr;
if (stricmp(str, "low")==0)
priority=EPriorityLow;
else if (strnicmp(str, "background", 4)==0)
priority=EPriorityBackground;
else if (strnicmp(str, "foreground", 4)==0)
priority=EPriorityForeground;
else if (stricmp(str, "high")==0)
priority=EPriorityHigh;
else if (strnicmp(str, "windowserver",3)==0)
priority=EPriorityWindowServer;
else if (strnicmp(str, "fileserver",4)==0)
priority=EPriorityFileServer;
else if (strnicmp(str, "realtimeserver",4)==0)
priority=EPriorityRealTimeServer;
else if (strnicmp(str, "supervisor",3)==0)
priority=EPrioritySupervisor;
else
return Print(EError, "Unrecognised priority keyword.\n");
}
if (priority<EPriorityLow || priority>EPrioritySupervisor)
return Print(EError, "Priority out of range.\n");
aNode->SetPriority( priority );
return KErrNone;
}
TInt CObeyFile::SetUid1(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'uid1'.\n");
aNode->SetUid1( getNumber(aStr) );
return KErrNone;
}
TInt CObeyFile::SetUid2(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'uid2'.\n");
aNode->SetUid2( getNumber(aStr) );
return KErrNone;
}
TInt CObeyFile::SetUid3(TRomNode *aNode, TText *aStr)
{
if (isNumber(aStr)==0)
return Print(EError, "Number required as argument for keyword 'uid3'.\n");
aNode->SetUid3( getNumber(aStr) );
return KErrNone;
}
TInt CObeyFile::ParseFileAttributes(TRomNode *aNode, TRomBuilderEntry* aFile, enum EKeyword aKeyword)
//
// Process any inline keywords
//
{
TInt currentLine = iReader.CurrentLine();
enum EFileAttribute attribute;
TInt r=KErrNone;
TInt index=3;
TText* arg=0;
while(r==KErrNone)
{
r=iReader.NextAttribute(index,(aFile!=0),attribute,arg);
if (r!=KErrNone)
break;
switch(attribute)
{
case EAttributeAtt:
r=aNode->SetAtt(arg);
break;
case EAttributeAttExtra:
r=aNode->SetAttExtra(arg, aFile, aKeyword);
break;
case EAttributeStack:
r=SetStackSize(aNode, arg);
break;
case EAttributeFixed:
aNode->SetFixed();
r = KErrNone;
break;
case EAttributeUid1:
r=SetUid1(aNode, arg);
break;
case EAttributeUid2:
r=SetUid2(aNode, arg);
break;
case EAttributeUid3:
r=SetUid3(aNode, arg);
break;
case EAttributeHeapMin:
r=SetHeapSizeMin(aNode, arg);
break;
case EAttributeHeapMax:
r=SetHeapSizeMax(aNode, arg);
break;
case EAttributePriority:
r=SetPriority(aNode, arg);
break;
case EAttributeCapability:
r=SetCapability(aNode, arg);
break;
case EAttributeUnpaged:
aNode->iOverride |= KOverrideCodeUnpaged|KOverrideDataUnpaged;
aNode->iOverride &= ~(KOverrideCodePaged|KOverrideDataPaged);
break;
case EAttributePaged:
aNode->iOverride |= KOverrideCodePaged|KOverrideDataPaged;
aNode->iOverride &= ~(KOverrideCodeUnpaged|KOverrideDataUnpaged);
break;
case EAttributeUnpagedCode:
aNode->iOverride |= KOverrideCodeUnpaged;
aNode->iOverride &= ~KOverrideCodePaged;
break;
case EAttributePagedCode:
aNode->iOverride |= KOverrideCodePaged;
aNode->iOverride &= ~KOverrideCodeUnpaged;
break;
case EAttributeUnpagedData:
aNode->iOverride |= KOverrideDataUnpaged;
aNode->iOverride &= ~KOverrideDataPaged;
break;
case EAttributePagedData:
aNode->iOverride |= KOverrideDataPaged;
aNode->iOverride &= ~KOverrideDataUnpaged;
break;
default:
return Print(EError, "Unrecognised keyword in file attributes on line %d.\n",currentLine);
}
}
if (r==KErrEof)
return KErrNone;
return r;
}
TBool CObeyFile::ProcessFile(TInt /*aAlign*/, enum EKeyword aKeyword)
//
// Process a parsed line to set up one or more new TRomBuilder entry objects.
// iWord[0] = the keyword (file, primary or secondary)
// iWord[1] = the PC pathname
// iWord[2] = the EPOC pathname
// iWord[3] = start of the file attributes
//
{
TBool isPeFile = ETrue;
TBool aFileCompressOption, aFileUncompressOption;
TInt epocPathStart=2;
aFileCompressOption = aFileUncompressOption = EFalse;
TBool warnFlag = EFalse;
static const char aStdPath[] = "SYS\\BIN\\";
static const int sysBinLength = sizeof(aStdPath)-1;
// do some validation of the keyword
TInt currentLine = iReader.CurrentLine();
switch (aKeyword)
{
case EKeywordData:
case EKeywordHideV2:
iNumberOfDataFiles++;
isPeFile = EFalse;
break;
case EKeywordFile:
warnFlag = gEnableStdPathWarning;
break;
case EKeywordFileCompress:
aFileCompressOption = ETrue;
warnFlag = gEnableStdPathWarning;
break;
case EKeywordFileUncompress:
aFileUncompressOption = ETrue;
warnFlag = gEnableStdPathWarning;
break;
default:
Print(EError,"Unexpected keyword '%s' on line %d.\n",iReader.Word(0),currentLine);
return EFalse;
}
if (aKeyword!=EKeywordHideV2)
{
// check the PC file exists
char* nname = NormaliseFileName(iReader.Word(1));
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
ifstream test(nname);
#else //!__MSVCDOTNET__
ifstream test(nname, ios::nocreate);
#endif //__MSVCDOTNET__
if (!test)
{
Print(EError,"Cannot open file %s for input.\n",iReader.Word(1));
iMissingFiles++;
}
test.close();
free(nname);
}
else
epocPathStart=1;
iNumberOfFiles++;
TBool endOfName=EFalse;
TText *epocStartPtr=IsValidFilePath(iReader.Text(epocPathStart));
TText *epocEndPtr=epocStartPtr;
if (epocStartPtr==NULL)
{
Print(EError, "Invalid destination path on line %d\n",currentLine);
return EFalse;
}
if(warnFlag) // Check for the std destination path(for executables) as per platsec.
{
if(strnicmp(aStdPath,(const char*)epocStartPtr,sysBinLength) != 0)
{
Print(EWarning,"Invalid destination path on line %d. \"%s\" \n",currentLine,epocStartPtr);
}
}
TRomNode* dir=iRootDirectory;
TRomNode* subDir=0;
TRomBuilderEntry *file=0;
while (!endOfName)
{
endOfName = GetNextBitOfFileName(&epocEndPtr);
if (endOfName) // file
{
TRomNode* alreadyExists=dir->FindInDirectory(epocStartPtr);
/*
* The EKeywordHideV2 keyword is used to indicate that:
* 1. if the file exists in the same image and then hidden, mark it hidden
* 2. if the file exists in another image, but in this (ROFS) image, it is
* required to hide that file, create a 0 length file entry setting the 'hide'
* flag so that at runtime, file gets hidden in the composite filesystem.
*/
if ((aKeyword != EKeywordHideV2) && alreadyExists) // duplicate file
{
Print(EError, "Duplicate file for %s on line %d\n",iReader.Word(1),iReader.CurrentLine());
return EFalse;
}
TBool aHidden = aKeyword==EKeywordHideV2;
/* The file is only marked hidden and hence the source file name isn't known
* here as hide statement says :
* hide <filename as in ROM>
* Therefore, create TRomBuilderEntry with iFileName as 0 for hidden file when
* the file doesn't exist in the same ROM image. Otherwise, the src file name
* is known because of alreadyExists (which comes from the 'file'/'data' statement).
*/
if(aHidden)
file = new TRomBuilderEntry(0, epocStartPtr);
else
file = new TRomBuilderEntry(iReader.Word(1), epocStartPtr);
file->iExecutable=isPeFile;
file->iHidden= aHidden;
if( aFileCompressOption )
{
file->iCompressEnabled = ECompressionCompress;
}
else if(aFileUncompressOption )
{
file->iCompressEnabled = ECompressionUncompress;
}
TRomNode* node=new TRomNode(epocStartPtr, file);
if (node==0)
return EFalse;
TInt r=ParseFileAttributes(node, file, aKeyword);
if (r!=KErrNone)
return EFalse;
dir->AddFile(node); // to ROFS directory structure
AddFile(file); // to our list of files
}
else // directory
{
subDir = dir->FindInDirectory(epocStartPtr);
if (!subDir) // sub directory does not exist
{
subDir = dir->NewSubDir(epocStartPtr);
if (!subDir)
return EFalse;
}
dir=subDir;
epocStartPtr = epocEndPtr;
}
}
return ETrue;
}
TBool CObeyFile::ProcessRenaming(enum EKeyword aKeyword)
{
// find existing file
TBool endOfName=EFalse;
TText *epocStartPtr=IsValidFilePath(iReader.Text(1));
// Store the current name and new name to maintain renamed file map
String currentName=iReader.Word(1);
String newName=iReader.Word(2);
TText *epocEndPtr=epocStartPtr;
if (epocStartPtr==NULL)
{
Print(EError, "Invalid source path on line %d\n",iReader.CurrentLine());
return EFalse;
}
char saved_srcname[257];
strcpy(saved_srcname, iReader.Word(1));
TRomNode* dir=iRootDirectory;
TRomNode* existingFile=0;
while (!endOfName)
{
endOfName = GetNextBitOfFileName(&epocEndPtr);
if (endOfName) // file
{
existingFile=dir->FindInDirectory(epocStartPtr);
if (existingFile)
{
TInt fileCount=0;
TInt dirCount=0;
existingFile->CountDirectory(fileCount, dirCount);
if (dirCount != 0 || fileCount != 0)
{
Print(EError, "Keyword %s not applicable to directories - line %d\n",iReader.Word(0),iReader.CurrentLine());
return EFalse;
}
}
}
else // directory
{
TRomNode* subDir = dir->FindInDirectory(epocStartPtr);
if (!subDir) // sub directory does not exist
break;
dir=subDir;
epocStartPtr = epocEndPtr;
}
}
if (aKeyword == EKeywordHide)
{
/*
* The EKeywordHide keyword is used to indicate that if the file exists in
* the primary ROFS image and then hidden in extension ROFS, mark it hidden.
*/
if (!existingFile)
{
Print(EWarning, "Hiding non-existent file %s on line %d\n",
saved_srcname, iReader.CurrentLine());
// Just a warning, as we've achieved the right overall effect.
}
else if (existingFile->iFileStartOffset==(TUint)KFileHidden)
{
Print(EWarning, "Hiding already hidden file %s on line %d\n",
saved_srcname, iReader.CurrentLine());
// We will igrore this request, otherwise it will "undelete" it.
}
else
{
//hidden files will not be placed to the image
existingFile->iHidden = ETrue;
}
return ETrue;
}
if (!existingFile)
{
Print(EError, "Can't %s non-existent source file %s on line %d\n",
iReader.Word(0), saved_srcname, iReader.CurrentLine());
return EFalse;
}
epocStartPtr=IsValidFilePath(iReader.Text(2));
epocEndPtr=epocStartPtr;
endOfName=EFalse;
if (epocStartPtr==NULL)
{
Print(EError, "Invalid destination path on line %d\n",iReader.CurrentLine());
return EFalse;
}
TRomNode* newdir=iRootDirectory;
while (!endOfName)
{
endOfName = GetNextBitOfFileName(&epocEndPtr);
if (endOfName) // file
{
TRomNode* alreadyExists=newdir->FindInDirectory(epocStartPtr);
if (alreadyExists && !(alreadyExists->iHidden)) // duplicate file
{
Print(EError, "Duplicate file for %s on line %d\n",saved_srcname,iReader.CurrentLine());
return EFalse;
}
}
else // directory
{
TRomNode* subDir = newdir->FindInDirectory(epocStartPtr);
if (!subDir) // sub directory does not exist
{
subDir = newdir->NewSubDir(epocStartPtr);
if (!subDir)
return EFalse;
}
newdir=subDir;
epocStartPtr = epocEndPtr;
}
}
if (aKeyword == EKeywordRename)
{
// rename => remove existingFile and insert into tree at new place
// has no effect on the iNextExecutable or iNextNodeForSameFile links
TInt r=ParseFileAttributes(existingFile, existingFile->iEntry, aKeyword);
if (r!=KErrNone)
return EFalse;
existingFile->Rename(dir, newdir, epocStartPtr);
// Store the current and new name of file in the renamed file map.
iPatchData->AddToRenamedFileMap(currentName, newName);
return ETrue;
}
// alias => create new TRomNode entry and insert into tree
TRomNode* node = new TRomNode(epocStartPtr, 0);
if (node == 0)
{
Print(EError, "Out of memory\n");
return EFalse;
}
node->Alias(existingFile);
TInt r=ParseFileAttributes(node, 0, aKeyword);
if (r!=KErrNone)
return EFalse;
newdir->AddFile(node); // to ROFS directory structure, though possibly hidden
return ETrue;
}
TInt ParsePagingPolicy(const char* policy)
{
if(stricmp(policy,"NOPAGING")==0)
return EKernelConfigPagingPolicyNoPaging;
else if (stricmp(policy,"ALWAYSPAGE")==0)
return EKernelConfigPagingPolicyAlwaysPage;
else if(stricmp(policy,"DEFAULTUNPAGED")==0)
return EKernelConfigPagingPolicyDefaultUnpaged;
else if(stricmp(policy,"DEFAULTPAGED")==0)
return EKernelConfigPagingPolicyDefaultPaged;
return KErrArgument;
}
TBool CObeyFile::ProcessKeyword(enum EKeyword aKeyword)
{
#ifdef __TOOLS2__
istringstream val(iReader.Word(1));
#else
istrstream val(iReader.Word(1),strlen(iReader.Word(1)));
#endif
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
val >> setbase(0);
#endif //__MSVCDOTNET__
TBool success = ETrue;
switch (aKeyword)
{
case EKeywordRofsName:
iReader.CopyWord(1, iRomFileName);
break;
case EKeywordRofsSize:
val >> iRomSize;
break;
case EKeywordVersion:
val >> iVersion;
break;
case EKeywordRofsChecksum:
val >> iCheckSum;
break;
case EKeywordTime:
iReader.ProcessTime(iTime);
break;
case EKeywordPagingOverride:
{
if(iPagingOverrideParsed)
Print(EWarning, "PagingOverride redefined - previous PagingOverride values lost\n");
if(iCodePagingOverrideParsed)
Print(EWarning, "PagingOverride defined - previous CodePagingOverride values lost\n");
if(iDataPagingOverrideParsed)
Print(EWarning, "PagingOverride defined - previous DataPagingOverride values lost\n");
iPagingOverrideParsed = true;
TInt policy = ParsePagingPolicy(iReader.Word(1));
if(policy<0)
{
Print(EError,"Unrecognised option for PAGINGOVERRIDE keyword\n");
success = false;
}
else
{
gCodePagingOverride = policy;
gDataPagingOverride = policy;
}
}
break;
case EKeywordCodePagingOverride:
{
if(iCodePagingOverrideParsed)
Print(EWarning, "CodePagingOverride redefined - previous CodePagingOverride values lost\n");
if(iPagingOverrideParsed)
Print(EWarning, "CodePagingOverride defined - previous PagingOverride values lost\n");
iCodePagingOverrideParsed = true;
TInt policy = ParsePagingPolicy(iReader.Word(1));
if(policy<0)
{
Print(EError,"Unrecognised option for CODEPAGINGOVERRIDE keyword\n");
success = false;
}
else
gCodePagingOverride = policy;
}
break;
case EKeywordDataPagingOverride:
{
if(iDataPagingOverrideParsed)
Print(EWarning, "DataPagingOverride redefined - previous DataPagingOverride values lost\n");
if(iPagingOverrideParsed)
{
Print(EError, "DataPagingOverride defined - previous PagingOverride values lost\n");
success = false;
break;
}
iDataPagingOverrideParsed = true;
TInt policy = ParsePagingPolicy(iReader.Word(1));
if(policy<0)
{
Print(EError,"Unrecognised option for DATAPAGINGOVERRIDE keyword\n");
success = false;
}
else
gDataPagingOverride = policy;
}
break;
case EKeywordRofsAutoSize:
iAutoSize = ETrue;
val >> iAutoPageSize;
break;
default:
// unexpected keyword iReader.Word(0)
break;
}
return success;
}
TBool CObeyFile::GotKeyVariables()
//
// Checks that the obeyfile has supplied enough variables to continue
//
{
TBool retVal=ETrue;
// Mandatory keywords
if (iRomFileName==0)
{
Print(EAlways,"The name of the image file has not been supplied.\n");
Print(EAlways,"Use the keyword \"rofsname\".\n");
retVal = EFalse;
}
if (iRomSize==0)
{
Print(EAlways,"The size of the image has not been supplied.\n");
Print(EAlways,"Use the keyword \"rofssize\".\n");
retVal = EFalse;
}
// Apply defaults as necessary
if (iTime==0)
{
Print(ELog, "No timestamp specified. Using current time...\n");
ObeyFileReader::TimeNow(iTime);
}
Print(ELog, "\nCreating Rofs image %s\n", iRomFileName);
return retVal;
}
TText *CObeyFile::IsValidFilePath(TText *aPath)
//
// Check the path is valid
//
{
// skip leading "\"
if (*aPath=='\\')
aPath++;
if (*aPath==0)
return NULL; // file ends in a backslash
TText *p=aPath;
TInt len=0;
FOREVER
{
if (*p==0)
return (len ? aPath : NULL);
if (*p=='\\')
{
if (len==0)
return NULL;
len=0;
}
len++;
p++;
}
}
TBool CObeyFile::GetNextBitOfFileName(TText **epocEndPtr)
//
// Move the end pointer past the next directory separator, replacing it with 0
//
{
while (**epocEndPtr != '\\') // until reach the directory separator
{
if (**epocEndPtr==0) // if reach end of string, return TRUE, it's the filename
return ETrue;
(*epocEndPtr)++;
}
**epocEndPtr=0; // overwrite the directory separator with a 0
(*epocEndPtr)++; // point past the 0 ready for the next one
return EFalse;
}
void CObeyFile::AddFile(TRomBuilderEntry* aFile)
{
*iNextFilePtrPtr = aFile;
iNextFilePtrPtr = &(aFile->iNext);
}
TInt CObeyFile::ProcessExtensionRofs(MRofsImage* aKernelRom)
{
//
// First pass through the obey file to set up key variables
//
iReader.Rewind();
enum EKeyword keyword;
// Deal with the "extensionrofs" keyword, which should be first
if (iReader.NextLine(1,keyword) != KErrNone)
return KErrEof;
if (keyword != EKeywordExtensionRofs)
return Print(EError, "Unexpected keyword '%s' at start of extension rom - line %d\n",
iReader.Word(0), iReader.CurrentLine());
iReader.CopyWord(1, iRomFileName);
Print(ELog, "\n========================================================\n");
Print(ELog, "Extension ROFS %s starting at line %d\n\n", iRomFileName, iReader.CurrentLine());
iReader.MarkNext(); // so that we rewind to the line after the extensionrom keyword
while (iReader.NextLine(1,keyword) != KErrEof)
{
if (keyword == EKeywordExtensionRofs)
break;
ProcessExtensionKeyword(keyword);
}
if (!GotExtensionVariables(aKernelRom))
return KErrGeneral;
// second pass to process the file specifications in the obey file building
// up the TRomNode directory structure and the TRomBuilderEntry list
//
iReader.Rewind();
//
if (aKernelRom==0)
return Print(EError, "Option to extend a kernel ROFS image not yet implemented\n");
iRootDirectory = new TRomNode((TText*)"");
iLastExecutable = 0;
(aKernelRom->RootDirectory())->deleteTheFirstNode();
iRootDirectory = aKernelRom->CopyDirectory(iLastExecutable);
aKernelRom->SetRootDirectory(iRootDirectory);
TInt align=0;
while (iReader.NextLine(2,keyword)!=KErrEof)
{
if (keyword == EKeywordExtensionRofs)
break;
switch (keyword)
{
case EKeywordHide:
case EKeywordAlias:
case EKeywordRename:
if (!ProcessRenaming(keyword))
return KErrGeneral;
break;
case EKeywordPatchDllData:
{
// Collect patchdata statements to process at the end
StringVector patchDataTokens;
SplitPatchDataStatement(patchDataTokens);
iPatchData->AddPatchDataStatement(patchDataTokens);
break;
}
default:
if (!ProcessFile(align, keyword))
return KErrGeneral;
align=0;
break;
}
}
if(!ParsePatchDllData() )
return KErrGeneral;
iReader.Mark(); // ready for processing the next extension rom(s)
if (iMissingFiles!=0)
return KErrGeneral;
if (iNumberOfFiles==0)
{
Print(EError, "No files specified.\n");
return KErrGeneral;
}
return KErrNone;
}
void CObeyFile::ProcessExtensionKeyword(enum EKeyword aKeyword)
{
#ifdef __TOOLS2__
istringstream val(iReader.Word(1));
#else
istrstream val(iReader.Word(1),strlen(iReader.Word(1)));
#endif
#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
val >> setbase(0);
#endif //__MSVCDOTNET__
switch (aKeyword)
{
case EKeywordCoreRofsName:
iReader.CopyWord(1, iKernelRofsName);
return;
case EKeywordRofsSize:
val >> iRomSize;
return;
case EKeywordVersion:
val >> iVersion;
return;
case EKeywordRomChecksum:
val >> iCheckSum;
return;
case EKeywordTime:
iReader.ProcessTime(iTime);
return;
case EKeywordRofsAutoSize:
iAutoSize = ETrue;
val >> iAutoPageSize;
return;
default:
Print(EError,"Keyword '%s' not valid in extension ROFS - line %d\n", iReader.Word(0), iReader.CurrentLine());
break;
}
return;
}
TBool CObeyFile::GotExtensionVariables(MRofsImage* aRom)
//
// Checks that the obeyfile has supplied enough variables to continue
//
{
TBool retVal=ETrue;
TText* kernelRofsName = iKernelRofsName;
// Mandatory keywords
if (iRomSize==0)
{
Print(EAlways,"The size of the extension ROFS has not been supplied.\n");
Print(EAlways,"Use the keyword \"rofssize\".\n");
retVal = EFalse;
}
// keywords we need if we don't already have a ROFS image to work from
if (aRom==0)
{
if (iKernelRofsName==0)
{
Print(EAlways,"The name of the core ROFS has not been supplied.\n");
Print(EAlways,"Use the keyword \"rofsname\".\n");
retVal = EFalse;
}
}
else
{
if (iKernelRofsName != 0)
{
Print(EWarning,"Keyword \"rofsname\" ignored.\n");
}
kernelRofsName = aRom->RomFileName();
}
// validation
// Apply defaults as necessary
if (iTime==0)
{
Print(ELog, "No timestamp specified. Using current time...\n");
ObeyFileReader::TimeNow(iTime);
}
// fix up "*" in rofsname
TText newname[256];
TText* p=newname;
TText* q=iRomFileName;
TText c;
while ((c=*q++)!='\0')
{
if (c!='*')
{
*p++=c;
continue;
}
TText *r=kernelRofsName;
while ((c=*r++)!='\0')
*p++=c;
}
*p = '\0';
free(iRomFileName);
iRomFileName = (TText*)strdup((char*)newname);
Print(ELog, "\nCreating ROFS image %s\n", iRomFileName);
return retVal;
}
// Fuction to split patchdata statement
void CObeyFile::SplitPatchDataStatement(StringVector& aPatchDataTokens)
{
// Get the value of symbol size, address/ordinal and new value
// to be patched from the patchdata statement.
// Syntax of patchdata statements is as follows:
// 1) patchdata dll_name ordinal OrdinalNumber size_in_bytes new_value
// 2) patchdata dll_name addr Address size_in_bytes new_value
for(TInt count=1; count<=5; count++)
{
aPatchDataTokens.push_back(iReader.Word(count));
}
// Store the the value of current line which will be used
// when displaying error messages.
OutputStringStream outStrStream;
outStrStream<<iReader.CurrentLine();
aPatchDataTokens.push_back(outStrStream.str());
}
TBool CObeyFile::ParsePatchDllData()
{
// Get the list of patchdata statements
VectorOfStringVector patchDataStatements=iPatchData->GetPatchDataStatements();
// Get the list of renamed file map
MapOfString RenamedFileMap=iPatchData->GetRenamedFileMap();
for(TUint count=0; count<patchDataStatements.size(); count++)
{
StringVector strVector = patchDataStatements.at(count);
String filename=strVector.at(0);
String lineNoStr = strVector.at(5);
TUint lineNo=getNumber(((TText*)lineNoStr.c_str()));
TRomNode* existingFile = NULL;
do
{
TRomNode* dir=iRootDirectory;
TBool endOfName=EFalse;
TText *epocStartPtr=IsValidFilePath((TText*)filename.c_str());
if (epocStartPtr==NULL)
{
Print(EError, "Invalid source path on line %d\n",lineNo);
return EFalse;
}
epocStartPtr = (TText*)NormaliseFileName((const char*)epocStartPtr);
TText *epocEndPtr=epocStartPtr;
while (!endOfName)
{
endOfName = GetNextBitOfFileName(&epocEndPtr);
if (endOfName) // file
{
existingFile=dir->FindInDirectory(epocStartPtr);
if (existingFile)
{
TInt fileCount=0;
TInt dirCount=0;
existingFile->CountDirectory(fileCount, dirCount);
if (dirCount != 0 || fileCount != 0)
{
Print(EError, "Keyword %s not applicable to directories - line %d\n","patchdata",lineNo);
return EFalse;
}
}
}
else // directory
{
TRomNode* subDir = dir->FindInDirectory(epocStartPtr);
if (!subDir) // sub directory does not exist
break;
dir=subDir;
epocStartPtr = epocEndPtr;
}
}
if(!existingFile)
{
// If the E32Image file to be patched is not included then check if the
// file was renamed.
MapOfStringIterator RenamedFileMapIterator;
if ((RenamedFileMapIterator=RenamedFileMap.find(filename)) != RenamedFileMap.end())
filename = (*RenamedFileMapIterator).second;
else
{
Print(EError, "File %s not found - line %d\n", filename.c_str(), lineNo);
return EFalse;
}
}
}while(!existingFile);
TUint32 aSize, aOrdinal, aNewValue, aOffset;
TLinAddr aDataAddr;
aOrdinal = (TUint32)-1;
aDataAddr = (TUint32)-1;
aOffset = 0;
String symbolSize=strVector.at(3);
aSize = getNumber((TText*)symbolSize.c_str());
String aValue=strVector.at(4);
aNewValue = getNumber((TText*)aValue.c_str());
DllDataEntry *dataEntry = new DllDataEntry(aSize, aNewValue);
// Set the address of the data or the ordinal number specified in OBY statement.
String keyword=strVector.at(1);
String keywordValue=strVector.at(2);
/* Check for +OFFSET at the end of the ordinal number or address */
TUint plus = keywordValue.find("+",0);
if (plus != std::string::npos)
{
/* Get the offset that we found after the + sign */
String offset = keywordValue.substr(plus+1);
aOffset = getNumber((TText*)offset.c_str());
keywordValue.resize(plus);
}
if(stricmp (keyword.c_str(), "addr") == 0)
aDataAddr = getNumber((TText*)keywordValue.c_str());
else
aOrdinal = getNumber((TText*)keywordValue.c_str());
dataEntry->iDataAddress = aDataAddr;
dataEntry->iOrdinal = aOrdinal;
dataEntry->iOffset = aOffset;
existingFile->SetDllData();
DllDataEntry *aDllDataEntry= existingFile->iEntry->GetFirstDllDataEntry();
if (aDllDataEntry==NULL)
{
// Set the first node of the patchdata linked list
aDllDataEntry=dataEntry;
existingFile->iEntry->SetFirstDllDataEntry(aDllDataEntry);
}
else
{
// Goto the last node
while((aDllDataEntry->NextDllDataEntry()) != NULL)
{
aDllDataEntry = aDllDataEntry->NextDllDataEntry();
}
// Add the new node at the end of linked list
aDllDataEntry->AddDllDataEntry(dataEntry);
}
}
return ETrue;
}