imgtools/romtools/rombuild/r_obey.cpp
author raptorbot <raptorbot@systemstesthead.symbian.intra>
Fri, 18 Dec 2009 19:57:42 +0000
branchwip
changeset 117 ecf683438dc6
parent 0 044383f39525
child 590 360bd6b35136
permissions -rw-r--r--
Don't mess around with EPOCROOT until actually entering raptor so we know what the original was Put the original epocroot back on the front of the whatcomp output. This allows what output to be either relative or absolute depending on what your epocroot is.

/*
* 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: 
*
*/


#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>
#else
 #include <strstream.h>
 #include <iomanip.h>
#endif 
#endif //__VC32__

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>

#include "e32std.h"
#include "e32std_private.h"
#include "e32rom.h"
#include "u32std.h"

#include "r_rom.h"
#include "r_obey.h"
#include "r_global.h"
#include "h_utl.h"
#include "patchdataprocessor.h"
#include "r_coreimage.h"

#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[] =
{
	{_P("file"),		2,-2, EKeywordFile, "Executable file to be loaded into the ROM"},
	{_P("data"),		2,-2, EKeywordData, "Data file to be copied into the ROM"},
	{_P("primary"),		1+2,-2, EKeywordPrimary, "An EPOC Kernel"},
	{_P("secondary"),	2,-2, EKeywordSecondary, "?"},
	{_P("variant"),		1+2,-2, EKeywordVariant, "?"},
	{_P("extension"),	1+2,-2, EKeywordExtension, "Kernel extension loaded before the secondary"},
	{_P("device"),		1+2,-2, EKeywordDevice, "Kernel extension loaded from the ROM file system"},
	{_P("dll"),			2,-2, EKeywordDll, "Executable file whose entry point must be called"},
	{_P("filecompress"),	2,-2, EKeywordFileCompress, "Non-XIP Executable to be loaded into the ROM compressed"},
	{_P("fileuncompress"),	2,-2, EKeywordFileUncompress, "Non-XIP Executable to be loaded into the ROM uncompressed"},
	{_K("area"),	    1, 3, EKeywordArea, "Declare a relocation area"},
	{_K("align"),	    2, 1, EKeywordAlign, "Override default alignment for following file"},
	{_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("singlekernel"),1, 0, EKeywordSingleKernel, "Single Kernel"},
	{_K("multikernel"),	1, 0, EKeywordMultiKernel, "Multiple Kernels"},
	{_K("bootbinary"),	1, 1, EKeywordBootBinary, "file containing the bootstrap"},
	{_K("romname"),		1, 1, EKeywordRomName, "output file for ROM image"},
	{_K("romsize"),		1, 1, EKeywordRomSize, "size of ROM image"},
	{_K("romlinearbase"),	1, 1, EKeywordRomLinearBase, "linear address of ROM image"},
	{_K("romalign"),	1, 1, EKeywordRomAlign, "default alignment of files in ROM image"},
	{_K("romchecksum"),	1, 1, EKeywordRomChecksum, "desired 32-bit checksum value for the whole ROM image"},
	{_K("kerneldataaddress"),	1, 1, EKeywordKernelDataAddress, "?"},
	{_K("kernelheapmin"),	1, 1, EKeywordKernelHeapMin, "Inital size of the kernel heap"},
	{_K("kernelheapmax"),	1, 1, EKeywordKernelHeapMax, "Maximum size of the kernel heap"},
	{_K("dataaddress"),	1, 1, EKeywordDataAddress, "?"},
	{_K("defaultstackreserve"),	1, 1, EKeywordDefaultStackReserve, "?"},
	{_K("version"),		1, 1, EKeywordVersion, "ROM version number"},
	{_K("romnameodd"),	1, 1, EKeywordRomNameOdd, "output file containing odd halfwords of ROM image"},
	{_K("romnameeven"),	1, 1, EKeywordRomNameEven, "output file containing even halfwords of ROM image"},
	{_K("srecordfilename"),	1, 1, EKeywordSRecordFileName, "output file containing ROM image in S-Record format"},
	{_K("srecordbase"),	1, 1, EKeywordSRecordBase, "Destination address for S-Record download"},
	{_K("kerneltrace"),	1, -1, EKeywordKernelTrace, "Initial value for Kernel tracing flags"},
	{_K("btrace"),	1, -1, EKeywordBTrace, "Initial value for fast-trace filter"},
	{_K("btracemode"),	1, 1, EKeywordBTraceMode, "Initial value for fast-trace mode"},
	{_K("btracebuffer"),	1, 1, EKeywordBTraceBuffer, "Initial size for fast-trace buffer"},
	{_K("collapse"),	1, 3, EKeywordCollapse, "Additional ROM optimisations"},
	{_K("time"),	    1,-1, EKeywordTime, "ROM timestamp"},
	{_K("section"),	    2, 1, EKeywordSection, "Start of replaceable section in old-style 2 section ROM"},
	{_K("extensionrom"),1+2, 1, EKeywordExtensionRom, "Start of definition of optional Extension ROM"},
	{_K("kernelromname"),1, 1, EKeywordKernelRomName, "ROM image on which extension ROM is based"},
	{_K("files"),		0, 0, EKeywordNone, 0},	// backwards compatibility, but now ignored
	{_K("rem"),			0, 0, EKeywordNone, "comment"},
	{_K("stop"),		0, 0, EKeywordNone, "Terminates OBEY file prematurely"},
	{_K("dlldatatop"),	1, 1, EKeywordDllDataTop, "Specify top of DLL data region"},
	{_K("memmodel"),	1, -1, EKeywordMemModel, "Specifies the memory model to be used at runtime"},
	{_K("nowrapper"),	1, 0, EKeywordNoWrapper, "Specifies that no ROM wrapper is required"},
	{_K("epocwrapper"),	1, 0, EKeywordEpocWrapper, "Specifies that an EPOC ROM wrapper is required"},
	{_K("coffwrapper"),	1, 0, EKeywordCoffWrapper, "Specifies that a COFF ROM wrapper is required"},
	{_K("platsecenforcement"),	1, 1, EKeywordPlatSecEnforcement, "Set Platform Security enforment on/off"},
	{_K("platsecdiagnostics"),	1, 1, EKeywordPlatSecDiagnostics, "Set Platform Security diagnostics on/off"},
	{_K("platsecprocessisolation"), 1, 1, EKeywordPlatSecProcessIsolation, "Set Platform Security process isolation on/off"},
	{_K("platsecenforcesysbin"), 1, 1, EKeywordPlatSecEnforceSysBin, "Set Platform Security process isolation on/off"},
	{_K("platsecdisabledcaps"), 1, 1, EKeywordPlatSecDisabledCaps, "Disable the listed Platform Security capabilities"},
	{_K("pagingpolicy"),	1, 1, EKeywordPagingPolicy, "Set the demand paging policy NOPAGING|DEFAULTUNPAGED|DEFAULTPAGED"},
	{_K("codepagingpolicy"),	1, 1, EKeywordCodePagingPolicy, "Set the code paging policy NOPAGING|DEFAULTUNPAGED|DEFAULTPAGED"},
	{_K("datapagingpolicy"),	1, 1, EKeywordDataPagingPolicy, "Set the data paging policy NOPAGING|DEFAULTUNPAGED|DEFAULTPAGED"},
	{_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("patchdata"), 2, 5, EKeywordPatchDllData, "Patch exported data"},
	{_K("coreimage"),	1, 1, EKeywordCoreImage, "Core image to be used for extension directory structure"},

	// things we don't normally report in the help information
	{_K("trace"),		1, 1, EKeywordTrace, "(ROMBUILD activity trace flags)"},
	{_K("unicode"),		1, 0, EKeywordUnicode, "(UNICODE rom - the default)"},
	{_K("ascii"),		1, 0, EKeywordAscii, "(Narrow rom)"},
	{_K("languages"),	1,-1, EKeywordLanguages, "(List of supported languages (for test))"},
	{_K("hardware"),	1, 1, EKeywordHardware, "(32-bit Hardware identifier (for test))"},
	{_K("debugport"),	1, 1, EKeywordDebugPort, "(Debug trace sink (magic cookie passed to ASSP/variant))"},
	{_K("compress"),	1, 0, EKeywordCompress, "Compress the ROM image"},
	{_K("demandpagingconfig"),	1, -1, EKeywordDemandPagingConfig, "Demand Paging Config [minPages] [maxPages] [ageRatio]"},
	{_K("pagedrom"),	1, 0, EKeywordPagedRom, "Build ROM immage suitable for demand paging"},
	{_K("filecompressnone"), 		2, -2, EKeywordExecutableCompressionMethodNone, "No compress the individual executable image."},
	{_K("filecompressinflate"),     2, -2, EKeywordExecutableCompressionMethodInflate,  "Inflate compression method for the individual executable image."},
	{_K("filecompressbytepair"),  	2, -2, EKeywordExecutableCompressionMethodBytePair, "Byte pair compresion method for the individual executable image."},
	{_K("kernelconfig"), 1, 2, EKeywordKernelConfig, "Set an arbitrary bit of the kernel config flags to on/off)"},
	{_K("maxunpagedsize"),	1, 1, EKeywordMaxUnpagedMemSize, "Maxinum unpaged size in ROM image. Default is no limited."},
	{_K("hcrdata") , 2, 2,EKeywordHardwareConfigRepositoryData,"HCR image data"},
	{0,0,0,0,EKeywordNone,""} 
	
};

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;
	}

TInt NumberOfVariants=0;

ObeyFileReader::ObeyFileReader(TText* aFileName):
//
// Constructor
//
	iMark(0), iMarkLine(0), iCurrentMark(0), iCurrentLine(0), imaxLength(0),iSuffix(0),iLine(0)
	{

	iFileName = new TText[strlen((const char *)aFileName)+1];
	strcpy((char *)iFileName,(const char *)aFileName);
	}

ObeyFileReader::~ObeyFileReader()
	{
	if (iObeyFile)
		fclose(iObeyFile);
	iObeyFile=0;
	delete [] iFileName;
	delete [] iLine;
	}

TBool ObeyFileReader::Open()
//
// Open the file & return a status
//
	{

 	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);
	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))
			{
			 
			if(EKeywordHardwareConfigRepositoryData == k->iKeywordEnum){ // preq2131 specific 
				Print(EWarning, "Incorrect number of arguments for keyword '%s' on line %d. Extra argument(s) are ignored.\n",
				iWord[0],iCurrentLine);
				aKeyword = k->iKeywordEnum;
				return KErrNone;
			}else{
				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
//

	{

	TUint i; 
	TText *letter=iLine;
	TText *end=iLine+strlen((char *)iLine);
	for (i=0; i<KNumWords; i++)
		iWord[i]=end;

	enum TState {EInWord, EInQuotedWord, EInGap};
	TState state=EInGap;

	i=0;
	while (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::ProcessLanguages(TInt64& aLanguageMask)
	{
	TInt i=1;
	while (i<iNumWords)
		{
		char *aStr=(char *)iWord[i];
		TLanguage l=ELangTest;
		if (stricmp(aStr, "test")==0)
			l=ELangTest;
		else if (stricmp(aStr, "english")==0)
			l=ELangEnglish;
		else if (stricmp(aStr, "french")==0)
			l=ELangFrench;
		else if (stricmp(aStr, "german")==0)
			l=ELangGerman;
		else if (stricmp(aStr, "spanish")==0)
			l=ELangSpanish;
		else if (stricmp(aStr, "italian")==0)
			l=ELangItalian;
		else if (stricmp(aStr, "swedish")==0)
			l=ELangSwedish;
		else if (stricmp(aStr, "danish")==0)
			l=ELangDanish;
		else if (stricmp(aStr, "norwegian")==0)
			l=ELangNorwegian;
		else if (stricmp(aStr, "finnish")==0)
			l=ELangFinnish;
		else if (stricmp(aStr, "american")==0)
			l=ELangAmerican;
		else if (stricmp(aStr, "SwissFrench")==0)
			l=ELangSwissFrench;
		else if (stricmp(aStr, "SwissGerman")==0)
			l=ELangSwissGerman;
		else if (stricmp(aStr, "Portuguese")==0)
			l=ELangPortuguese;
		else if (stricmp(aStr, "Turkish")==0)
			l=ELangTurkish;
		else if (stricmp(aStr, "Icelandic")==0)
			l=ELangIcelandic;
		else if (stricmp(aStr, "Russian")==0)
			l=ELangRussian;
		else if (stricmp(aStr, "Hungarian")==0)
			l=ELangHungarian;
		else if (stricmp(aStr, "Dutch")==0)
			l=ELangDutch;
		else if (stricmp(aStr, "BelgianFlemish")==0)
			l=ELangBelgianFlemish;
		else if (stricmp(aStr, "Australian")==0)
			l=ELangAustralian;
		else if (stricmp(aStr, "BelgianFrench")==0)
			l=ELangBelgianFrench;
		else
			{
			Print(EError, "Unknown language '%s' on line %d", iWord[i], iCurrentLine);
			exit(666);
			}
		aLanguageMask = aLanguageMask+(1<<(TInt)l);
		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;
	}

TInt ObeyFileReader::ProcessAlign(TInt &aAlign)
//
// Process the align keyword
//
	{

	TInt align;
	if (Val(align, Word(1)))
		return Print(EError, "Number required for 'align' keyword on line %d\n", iCurrentLine);
	aAlign=align;
	TInt i;
	for (i=4; i!=0x40000000; i<<=1)
		if (i==aAlign)
			return KErrNone;
	return Print(EError, "Alignment must be a power of 2 and bigger than 4.  Line %d\n", iCurrentLine);
	}


const FileAttributeKeyword ObeyFileReader::iAttributeKeywords[] =
{
	{"stackreserve",6	,1,1,EAttributeStackReserve, "?"},
	{"stack",3			,1,1,EAttributeStack, "?"},
	{"reloc",3			,1,1,EAttributeReloc, "?"},
	{"code-align",10	,1,1,EAttributeCodeAlign, "Additional code alignment constraint"},
	{"data-align",10	,1,1,EAttributeDataAlign, "Additional data alignment constraint"},
	{"fixed",3			,1,0,EAttributeFixed, "Relocate to a fixed address space"},
	{"attrib",3			,0,1,EAttributeAtt, "File attributes in ROM file system"},
	{"priority",3		,1,1,EAttributePriority, "Override process priority"},
	{"patched",5		,1,0,EAttributePatched, "File to be replaced in second section"},
	{_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("keepIAT")		,1,0,EAttributeKeepIAT, "(Retain old-style Import Address Table)"},
	{_K("hide")			,0,0,EAttributeHidden, "Don't record file in the ROM file system"},
	{_K("area")         ,1,1,EAttributeArea, "Relocate file to given area"},
	{_K("process")		,1,1,EAttributeProcessSpecific, "Indicate which process a DLL will attach to"},
	{_K("capability")	,1,1,EAttributeCapability, "Override capabilities"},
	{_K("preferred")	,1,0,EAttributePreferred, "Prefer this over other minor versions of same major version"},
	{_K("unpaged")		,1,0,EAttributeUnpaged, "Don't use demand paging for this file"},
	{_K("paged")		,1,0,EAttributePaged, "Use demand paging for this file"},
	{_K("unpagedcode")	,1,0,EAttributeUnpagedCode, "Don't use code paging for this file"},
	{_K("pagedcode")	,1,0,EAttributePagedCode, "Use code paging for this file"},
	{_K("unpageddata")	,1,0,EAttributeUnpagedData, "Don't use data paging for this file"},
	{_K("pageddata")	,1,0,EAttributePagedData, "Use data paging for this file"},
	{0,0,0,0,EAttributeStackReserve,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;
	}




CObeyFile::CObeyFile(ObeyFileReader& aReader):
	iRomFileName(0),iRomOddFileName(0),iRomEvenFileName(0),
	iSRecordFileName(0),iBootFileName(0),iKernelRomName(0),
	iRomSize(0),iRomLinearBase(0xffffffff),iRomAlign(0),
	iKernDataRunAddress(0),iDataRunAddress(0),iKernelLimit(0xffffffff),
	iKernHeapMin(0),iKernHeapMax(0),iSectionStart(0),iSectionPosition(-1),
	iVersion(0,0,0),iCheckSum(0),iNumberOfPeFiles(0),iNumberOfDataFiles(0),
	iNumberOfPrimaries(0),iNumberOfExtensions(0),iNumberOfVariants(0),
	iNumberOfDevices(0),iNumberOfHCRDataFiles (0),
	//iAllVariantsMask[256],
	iPrimaries(0),iVariants(0),iExtensions(0),iDevices(0),
	iLanguage(0),iHardware(0),iTime(0),iMemModel(E_MM_Moving),iPageSize(0x1000),
	iChunkSize(0x100000),iVirtualAllocSize(0x1000),iKernelModel(ESingleKernel),
	iCollapseMode(ECollapseNone),iSRecordBase(0),iCurrentSectionNumber(0),
	iDefaultStackReserve(0),//iTraceMask[KNumTraceMaskWords];iInitialBTraceFilter[8];
	iInitialBTraceBuffer(0),iInitialBTraceMode(0),iDebugPort(0),
	iDebugPortParsed(EFalse),iRootDirectory(0),iDllDataTop(0x40000000),
	iKernelConfigFlags(0),iPagingPolicyParsed(EFalse),iCodePagingPolicyParsed(EFalse),
	iDataPagingPolicyParsed(EFalse),iPagingOverrideParsed(EFalse),
	iCodePagingOverrideParsed(EFalse),iDataPagingOverrideParsed(EFalse),
	/*iPlatSecDisabledCaps(), */iPlatSecDisabledCapsParsed(EFalse),iMaxUnpagedMemSize(0),
	iReader(aReader),iMissingFiles(0),iLastExecutable(0),iAreaSet(),iFirstFile(0),
	iCurrentFile(0),iLastVariantFile(0),iFirstDllDataEntry(0),
	iUpdatedMaxUnpagedMemSize(EFalse),iPatchData(new CPatchDataProcessor)
	{

	TUint i; 
	for (i=0; i<256; i++)
		iAllVariantsMask[i]=0;
	for (i=0; i<(TUint)KNumTraceMaskWords; i++) 
		iTraceMask[i]=0;
	for (i=0; i<sizeof(iInitialBTraceFilter)/sizeof(TUint32); i++)
		iInitialBTraceFilter[i]=0;	
	memset(&iPlatSecDisabledCaps,0,sizeof(SCapabilitySet));
	iNextFilePtrPtr = &iFirstFile;
	}

CObeyFile::~CObeyFile()
//
// Destructor
//
	{

	Release();
	delete [] iRomFileName;
	if (iRootDirectory)
		iRootDirectory->Destroy();
	delete iPatchData;
	}

void CObeyFile::Release()
//
// Free resources not needed after building a ROM
//
	{
	iAreaSet.ReleaseAllAreas();

	delete [] iBootFileName;
	delete [] iPrimaries;
	delete [] iVariants;
	delete [] iExtensions;
	delete [] iDevices;

	iBootFileName = 0;
	iPrimaries = 0;
	iVariants = 0;
	iExtensions = 0;
	iDevices = 0;
	iFirstFile = 0;
	iNextFilePtrPtr = &iFirstFile;
	}

TRomBuilderEntry *CObeyFile::FirstFile()
	{
	iCurrentFile = iFirstFile;
	return iCurrentFile;
	}

TRomBuilderEntry *CObeyFile::NextFile()
	{
	iCurrentFile = iCurrentFile ? iCurrentFile->iNext : 0;
	return iCurrentFile;
	}

/*
*Set first link in patchdata linked list
**/
void CObeyFile::SetFirstDllDataEntry(DllDataEntry* aDllDataEntry)
{
  	iFirstDllDataEntry = aDllDataEntry;
}

/*
*Get first link in patchdata linked list
**/
DllDataEntry* CObeyFile::GetFirstDllDataEntry() const
{
	return iFirstDllDataEntry;
}

TInt CObeyFile::ProcessKernelRom()
	{
	//
	// 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 == EKeywordExtensionRom)
			{
			if (count==0)
				return KErrNotFound;		// no kernel ROM, just extension ROMs.
			break;
			}

		count++;
		if (! ProcessKeyword(keyword))
			return KErrGeneral;
		}

	if (!GotKeyVariables())
		return KErrGeneral;

	if (! CreateDefaultArea())
		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 == EKeywordExtensionRom)
			break;

		switch (keyword)
			{
		case EKeywordSection:
			if (ParseSection()!=KErrNone)
				return KErrGeneral;
			break;
		case EKeywordAlign:
			if (iReader.ProcessAlign(align)!=KErrNone)
				return KErrGeneral;
			break;
		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 (iNumberOfDataFiles+iNumberOfPeFiles==0)
		{
		Print(EError, "No files specified.\n");
		return KErrGeneral;
		}
	if (!CheckHardwareVariants())
		return KErrGeneral;

	return KErrNone;
	}


TInt CObeyFile::ParseSection()
//
// Process the section keyword
//
	{
	TInt currentLine = iReader.CurrentLine();
	if (iSectionPosition!=-1)
		return Print(EError, "Rom already sectioned.  Line %d\n", currentLine);
	TInt offset;
	if (Val(offset, iReader.Word(1)))
		return Print(EError, "Number required for 'section' keyword on line %d\n", currentLine);
	iSectionStart=offset+iRomLinearBase;
	if (offset>=iRomSize)
		return Print(EError, "Sectioned beyond end of Rom.  Line %d\n", currentLine);
	if (offset&0x0fff)
		return Print(EError, "Section must be on a 4K boundry.  Line %d\n", currentLine);
	iSectionPosition=iNumberOfDataFiles+iNumberOfPeFiles;
	iCurrentSectionNumber++;	
	return KErrNone;
	}

TInt CObeyFile::ParseFileAttributes(TRomNode *aNode, TRomBuilderEntry* aFile)
//
// 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 EAttributeStackReserve:
			r=aFile->SetStackReserve(arg);
			break;
		case EAttributeStack:
			r=aFile->SetStackSize(arg);
			break;
		case EAttributeReloc:
			r=aFile->SetRelocationAddress(arg);
			break;
		case EAttributeCodeAlign:
			r=aFile->SetCodeAlignment(arg);
			break;
		case EAttributeDataAlign:
			r=aFile->SetDataAlignment(arg);
			break;
		case EAttributeFixed:
			r=aFile->SetRelocationAddress(NULL);
			break;
		case EAttributeAtt:
			r=aNode->SetAtt(arg);
			break;
		case EAttributeUid1:
			r=aFile->SetUid1(arg);
			break;
		case EAttributeUid2:
			r=aFile->SetUid2(arg);
			break;
		case EAttributeUid3:
			r=aFile->SetUid3(arg);
			break;
		case EAttributeHeapMin:
			r=aFile->SetHeapSizeMin(arg);
			break;
		case EAttributeHeapMax:
			r=aFile->SetHeapSizeMax(arg);
			break;
		case EAttributePriority:
			r=aFile->SetPriority(arg);
			break;
		case EAttributePatched:
			if (iSectionPosition!=-1)
				return Print(EError, "Not sensible to patch files in top section.  Line %d.\n", currentLine);
			aFile->iPatched=ETrue;
			break;
		case EAttributeKeepIAT:
			aFile->iOverrideFlags |= KOverrideKeepIAT;
			break;
		case EAttributeHidden:
			if (aFile->Extension())
 				return Print(EError, "Cannot hide Extension. Line %d.\n", currentLine);
			aNode->iHidden=ETrue;
			break;
		case EAttributeArea:
			{
			TRACE(TAREA, Print(EScreen, "Area Attribute: %s\n", arg));
			const Area* area = aFile->iArea;
			if (! ParseAreaAttribute(arg, currentLine, area))
				return KErrGeneral;
			}
			break;
		case EAttributeProcessSpecific:
			if (!IsValidFilePath(arg))
				{
				Print(EError, "Invalid file path for process attribute on line %d\n", currentLine);
				return KErrGeneral;
				}
			r=aFile->SetAttachProcess(arg);
			break;
		case EAttributeCapability:
			r=aFile->SetCapability(arg);
			break;
		case EAttributePreferred:
			aFile->iPreferred = ETrue;
			break;
		case EAttributeUnpaged:
			aFile->iOverrideFlags |= KOverrideCodeUnpaged | KOverrideDataUnpaged;
			aFile->iOverrideFlags &= ~(KOverrideCodePaged | KOverrideDataPaged);
			break;
		case EAttributePaged:
			aFile->iOverrideFlags |= KOverrideCodePaged | KOverrideDataPaged;
			aFile->iOverrideFlags &= ~(KOverrideCodeUnpaged | KOverrideDataUnpaged);
			break;
		case EAttributeUnpagedCode:
			aFile->iOverrideFlags |= KOverrideCodeUnpaged;
			aFile->iOverrideFlags &= ~KOverrideCodePaged;
			break;
		case EAttributePagedCode:
			aFile->iOverrideFlags |= KOverrideCodePaged;
			aFile->iOverrideFlags &= ~KOverrideCodeUnpaged;
			break;
		case EAttributeUnpagedData:
			aFile->iOverrideFlags |= KOverrideDataUnpaged;
			aFile->iOverrideFlags &= ~KOverrideDataPaged;
			break;
		case EAttributePagedData:
			aFile->iOverrideFlags |= KOverrideDataPaged;
			aFile->iOverrideFlags &= ~KOverrideDataUnpaged;
			break;

		default:
			return Print(EError, "Unrecognised keyword in file attributes on line %d.\n",currentLine);
			}
		}

	// aFile may be null if processing an extension ROM
	if (aFile && aFile->iPatched && ! aFile->iArea->IsDefault())
		{
		return Print(EError, "Relocation to area at line %d forbidden because file is patched\n", currentLine);
		}

	if (r==KErrEof)
		return KErrNone;
	return r;
	}

TUint32 CObeyFile::ParseVariant()
	{
	char* left=iReader.Suffix();
	if (left == 0 || *left=='\0')
		return KVariantIndependent;
	const char* right=left+strlen(left)-1;
	if (*left=='[' && *right==']')
		{
		TUint variant;
		#ifdef __TOOLS2__
		string s(left+1);
		string s2=s.substr(0,right-(left+1));
		istringstream val(s2,ios::in);
		#else
		istrstream val(left+1, right-(left+1));
		#endif
		

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
		val >> setbase(0);
#endif //__MSVCDOTNET__

		val >> variant;
		if (val.eof() && !val.fail())
			return variant;
		}
//#endif
	Print(EError,"Syntax error in variant, %s keyword on line %d\n", iReader.Word(0), iReader.CurrentLine());
	return KVariantIndependent;
	}

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
//
	{

	TUint imageFlags = 0;
	TUint overrides = 0;
	TBool isPeFile = ETrue;
	TBool isResource = EFalse;
	TBool isNonXIP = EFalse;
	TUint compression = 0;
	TBool callEntryPoint = EFalse;
	TUint hardwareVariant=KVariantIndependent;
	TBool mustBeInSysBin = EFalse;
	TBool tryForSysBin = EFalse;
 	TBool warnFlag = EFalse;

	// do some validation of the keyword
	TInt currentLine = iReader.CurrentLine();

	switch (aKeyword)
		{
	case EKeywordPrimary:
		imageFlags |= KRomImageFlagPrimary;
		overrides |= KOverrideCodeUnpaged | KOverrideDataUnpaged;
		mustBeInSysBin = gPlatSecEnforceSysBin;
 		warnFlag = gEnableStdPathWarning;		
		hardwareVariant=ParseVariant();
		if (iKernelModel==ESingleKernel && !THardwareVariant(hardwareVariant).IsIndependent())
			{
			Print(EError,"Kernel must be independent in single kernel ROMs\n");
			}
		break;

	case EKeywordSecondary:
		imageFlags |= KRomImageFlagSecondary;
		mustBeInSysBin = gPlatSecEnforceSysBin;
 		warnFlag = gEnableStdPathWarning;
		hardwareVariant=ParseVariant();
		break;

	case EKeywordVariant:
		imageFlags |= KRomImageFlagVariant;
		overrides |= KOverrideCodeUnpaged | KOverrideDataUnpaged;
		mustBeInSysBin = gPlatSecEnforceSysBin;
 		warnFlag = gEnableStdPathWarning;		
		hardwareVariant=ParseVariant();
		break;

	case EKeywordExtension:
		imageFlags |= KRomImageFlagExtension;
		overrides |= KOverrideCodeUnpaged | KOverrideDataUnpaged;
		mustBeInSysBin = gPlatSecEnforceSysBin;
 		warnFlag = gEnableStdPathWarning;
		hardwareVariant=ParseVariant();
		break;

	case EKeywordDevice:
		imageFlags |= KRomImageFlagDevice;
		overrides |= KOverrideCodeUnpaged | KOverrideDataUnpaged;
		mustBeInSysBin = gPlatSecEnforceSysBin;
 		warnFlag = gEnableStdPathWarning;		
		hardwareVariant=ParseVariant();
		break;

	case EKeywordExecutableCompressionMethodBytePair:
		compression=KUidCompressionBytePair;
		
	case EKeywordExecutableCompressionMethodInflate:
	case EKeywordFileCompress:
		compression = compression ? compression : KUidCompressionDeflate;

	case EKeywordExecutableCompressionMethodNone:	
	case EKeywordFileUncompress:
		isNonXIP = ETrue;
	case EKeywordData:
		iNumberOfDataFiles++;
		isPeFile = EFalse;
		isResource = ETrue;
		hardwareVariant=ParseVariant();
		tryForSysBin = gPlatSecEnforceSysBin;
		break;	 

	case EKeywordHardwareConfigRepositoryData:
		if(iNumberOfHCRDataFiles){
			Print(EError,"Multiple keywords '%s' on line %d.\n",iReader.Word(0),currentLine);
			return EFalse ;
		}
		compression = EFalse ; 
		overrides |= KOverrideCodeUnpaged | KOverrideDataUnpaged | KOverrideHCRData;
		warnFlag = gEnableStdPathWarning;	 
		iNumberOfHCRDataFiles ++ ;
		isPeFile = EFalse;
		break;

	case EKeywordDll:
		callEntryPoint = ETrue;
		// and fall through to handling for "file"
	
	case EKeywordFile:
		{
			
		char* nname = NormaliseFileName(iReader.Word(1));
		strupr(nname);
		
		if( gCompressionMethod == 0 || NULL != strstr(nname, ".DLL") || callEntryPoint )
		{
			mustBeInSysBin = gPlatSecEnforceSysBin;
 			warnFlag = gEnableStdPathWarning;			
			hardwareVariant=ParseVariant();
		}
		else 
		{
			compression = gCompressionMethod;
			hardwareVariant=ParseVariant();
			tryForSysBin = gPlatSecEnforceSysBin;
		}
		}
		break;

	default:
		Print(EError,"Unexpected keyword '%s' on line %d.\n",iReader.Word(0),currentLine);
		return EFalse;
		}

	if (isPeFile)
		iNumberOfPeFiles++;

	// check the PC file exists
	char* nname = NormaliseFileName(iReader.Word(1));

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
	ifstream test(nname,ios_base::binary );
#else //!__MSVCDOTNET__
	ifstream test(nname,ios::nocreate | ios::binary); 
#endif //__MSVCDOTNET__

	if (!test.is_open())
		{
		Print(EError,"Cannot open file %s for input.\n",iReader.Word(1));
		if(EKeywordHardwareConfigRepositoryData == aKeyword)
			{
			free(nname);
			return EFalse ;
			}
		iMissingFiles++;
		}
		
	if(EKeywordHardwareConfigRepositoryData == aKeyword)
		{ // check hcr file 

		TUint32 magicWord = 0;
		test.read(reinterpret_cast<char*>(&magicWord),sizeof(TUint32));
		if(0x66524348 != magicWord)
			{
			Print(EError,"Invalid hardware configuration repository data file %s .\n",iReader.Word(1));
			test.close();
			free(nname);
			return EFalse;
			}

		}
	test.close();
	free(nname);
 	

 	TBool endOfName=EFalse;
	TText *epocStartPtr=IsValidFilePath(iReader.Text(2));
	if (epocStartPtr==NULL)
		{
		Print(EError, "Invalid destination path on line %d\n",currentLine);
		return EFalse;
		}
	epocStartPtr = (TText*)NormaliseFileName((const char*)epocStartPtr);

	if(tryForSysBin)
		{
		if(strnicmp((const char*)epocStartPtr, "system\\bin\\", 11)==0)
			mustBeInSysBin = 1;
		if(strnicmp((const char*)epocStartPtr, "system\\libs\\", 12)==0)
			mustBeInSysBin = 1;
		if(strnicmp((const char*)epocStartPtr, "system\\programs\\", 16)==0)
			mustBeInSysBin = 1;
		}

	static const char sysBin[] = "sys\\bin\\";
	static const int sysBinLength = sizeof(sysBin)-1;

 	if (strnicmp((const char*)epocStartPtr, sysBin, sysBinLength)!=0)
 	{		
 		if(mustBeInSysBin)
		{
 			TInt len = strlen((char*)epocStartPtr);
 			TInt i = len;
 			while(--i>=0) if(epocStartPtr[i]=='\\') break;
 			++i;
 			char* old = (char*)epocStartPtr;
 			epocStartPtr = (TText*)malloc(sysBinLength+(len-i)+1);
 			strcpy((char*)epocStartPtr,sysBin);
 			strcat((char*)epocStartPtr,old+i);

 			Print(EDiagnostic, "%s moved to %s\n", old, epocStartPtr);
 			delete old;
		}
 		else if (warnFlag)
 		{
 			Print(EWarning, "Outside standard path at %s\n", epocStartPtr);
 		}		
 	}	

	TText *epocEndPtr=epocStartPtr;
	AUTO_FREE(epocStartPtr);	
		
	TRomNode* dir=iRootDirectory;
	TRomNode* subDir=0;
	TRomBuilderEntry *file=0;
	while (!endOfName)
		{
		endOfName = GetNextBitOfFileName(&epocEndPtr);
		if (endOfName) // file
			{
			TRomNode* alreadyExists=dir->FindInDirectory(epocStartPtr,hardwareVariant);
			if (alreadyExists) // duplicate file
				{
				Print(EError, "Duplicate file for %s on line %d\n",iReader.Word(1),iReader.CurrentLine());
				return EFalse;
				}
			file = new TRomBuilderEntry(iReader.Word(1),epocStartPtr);
			file->iRomImageFlags = imageFlags;
			file->iResource = isResource;
			file->iNonXIP = isNonXIP;
			file->iCompression = compression;
			
			file->iArea = iAreaSet.FindByName(AreaSet::KDefaultAreaName);
			file->iRomSectionNumber = iCurrentSectionNumber;
			file->iHardwareVariant = hardwareVariant;
			file->iOverrideFlags |= overrides;
			if (callEntryPoint)
				file->SetCallEntryPoint(callEntryPoint);
			file->iAlignment=aAlign;
			TUint32 uid;
			file->iBareName = SplitFileName((const char*)file->iName, uid, file->iVersionInName, file->iVersionPresentInName);
			assert(uid==0 && !(file->iVersionPresentInName & EUidPresent));
			if (strchr(file->iBareName, '{') || strchr(file->iBareName, '}'))
				{
				Print(EError, "Illegal character in name %s on line %d\n", file->iName, iReader.CurrentLine());
				delete file;
				return EFalse;
				}
			TRomNode* node=new TRomNode(epocStartPtr, file);
			if (node==0){
				delete file;
				return EFalse;
			}
				
			TInt r=ParseFileAttributes(node, file);
			if (r!=KErrNone){
				delete file;
				delete node;
				return EFalse;
			}

			TRACE(TAREA, Print(EScreen, "File %s area '%s'\n", iReader.Word(1), file->iArea->Name()));

			// Apply some specific overrides to the primary
			if (imageFlags & KRomImageFlagPrimary)
				{
				if (file->iCodeAlignment < iPageSize)
					file->iCodeAlignment = iPageSize;	// Kernel code is at least page aligned
				file->iHeapSizeMin = iKernHeapMin;
				file->iHeapSizeMax = iKernHeapMax;
				file->iOverrideFlags |= KOverrideHeapMin+KOverrideHeapMax;
				}

			if (!file->iPatched)
				dir->AddFile(node);	// to ROM directory structure, though possibly hidden
			if (isPeFile)
				TRomNode::AddExecutableFile(iLastExecutable, node);
			
			AddFile(file);
			}		 
		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;
	}


void CObeyFile::AddFile(TRomBuilderEntry* aFile)
	{
	aFile->iArea->AddFile(aFile);

	*iNextFilePtrPtr = aFile;
	iNextFilePtrPtr = &(aFile->iNext);
	}


TBool CObeyFile::ProcessRenaming(enum EKeyword aKeyword)
	{
	TUint hardwareVariant=ParseVariant();

	// find existing file
	TBool endOfName=EFalse;

	// Store the current name and new name to maintain renamed file map
	String currentName=iReader.Word(1);
	String newName=iReader.Word(2);

	TText *epocStartPtr=IsValidFilePath(iReader.Text(1));
	if (epocStartPtr==NULL)
		{
		Print(EError, "Invalid source path on line %d\n",iReader.CurrentLine());
		return EFalse;
		}
	epocStartPtr = (TText*)NormaliseFileName((const char*)epocStartPtr);
	TText *epocEndPtr=epocStartPtr;
	AUTO_FREE(epocStartPtr);

	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,hardwareVariant);
			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)
		{
		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
			{
			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,existingFile->HardwareVariant());
			if (alreadyExists) // 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->iRomFile->iRbEntry);
		if (r!=KErrNone)
			return EFalse;
		r = existingFile->Rename(dir, newdir, epocStartPtr);
		if (r==KErrBadName)
			{
			Print(EError, "Bad name %s at line %d\n", epocStartPtr, iReader.CurrentLine());
			return EFalse;
			}
		else if (r==KErrArgument)
			{
			Print(EError, "Version in name %s does not match version in file header at line %d\n", epocStartPtr, iReader.CurrentLine());
			return EFalse;
			}
		// 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, existingFile);
	if (node == 0)
		{
		Print(EError, "Out of memory\n");
		return EFalse;
		}

	TInt r = node->Alias(existingFile, iLastExecutable);
	if (r==KErrBadName)
		{
		Print(EError, "Bad name %s at line %d\n", epocStartPtr, iReader.CurrentLine());
		return EFalse;
		}
	else if (r==KErrArgument)
		{
		Print(EError, "Version in name %s does not match version in file header at line %d\n", epocStartPtr, iReader.CurrentLine());
		return EFalse;
		}
	r=ParseFileAttributes(node, 0);
	if (r!=KErrNone)
		return EFalse;

	newdir->AddFile(node);	// to ROM 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)
	{
	TUint hardwareVariant=KVariantIndependent;

	#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 EKeywordUnicode:
		Unicode=ETrue;
		break;
	case EKeywordAscii:
		Unicode=EFalse;
		break;

	case EKeywordSingleKernel:
		iKernelModel=ESingleKernel;
		break;
	case EKeywordMultiKernel:
		iKernelModel=EMultipleKernels;
		break;

	case EKeywordBootBinary:
		iReader.CopyWord(1, iBootFileName);
		break;
	case EKeywordRomName:
		iReader.CopyWord(1, iRomFileName);
		break;
	case EKeywordRomNameOdd:
		iReader.CopyWord(1, iRomOddFileName);
		break;
	case EKeywordRomNameEven:
		iReader.CopyWord(1, iRomEvenFileName);
		break;
	case EKeywordSRecordFileName:
		iReader.CopyWord(1, iSRecordFileName);
		break;

	case EKeywordRomLinearBase:
		val >> iRomLinearBase;
		break;
	case EKeywordRomSize:
		val >> iRomSize;
		break;
	case EKeywordRomAlign:
		val >> iRomAlign;
		break;
	case EKeywordKernelDataAddress:
		val >> iKernDataRunAddress;
		break;
	case EKeywordKernelHeapMin:
		val >> iKernHeapMin;
		break;
	case EKeywordKernelHeapMax:
		val >> iKernHeapMax;
		break;
	case EKeywordDataAddress:
		val >> iDataRunAddress;
		break;
	case EKeywordDefaultStackReserve:
		val >> iDefaultStackReserve;
		break;
	case EKeywordVersion:
		val >> iVersion;
		break;
	case EKeywordSRecordBase:
		val >> iSRecordBase;
		break;
	case EKeywordRomChecksum:
		val >> iCheckSum;
		break;
	case EKeywordHardware:
		val >> iHardware;
		break;
	case EKeywordLanguages:
		iReader.ProcessLanguages(iLanguage);
		break;
	case EKeywordTime:
		iReader.ProcessTime(iTime);
		break;
	case EKeywordDllDataTop:
		val >> iDllDataTop;
		break;

	case EKeywordMemModel:
		{
		char* arg1=iReader.Word(1);
		char* arg2=iReader.Word(2);
		char* arg3=iReader.Word(3);
		char* arg4=iReader.Word(4);
		if (strnicmp(arg1, "moving", 6)==0)
			iMemModel=E_MM_Moving;
		else if (strnicmp(arg1, "direct", 6)==0)
			iMemModel=E_MM_Direct;
		else if (strnicmp(arg1, "multiple", 8)==0)
			iMemModel=E_MM_Multiple;
		else if (strnicmp(arg1, "flexible", 8)==0)
			iMemModel=E_MM_Flexible;
		else
			{
			Print(EError, "Unknown memory model specified\n");
			success = EFalse;
			}
		if (strlen(arg2))
			{
			#ifdef __TOOLS2__
			istringstream arg2s(arg2);
			#else
			istrstream arg2s(arg2,strlen(arg2));
			#endif

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
			arg2s >> setbase(0);
#endif //__MSVCDOTNET__

			arg2s >> iChunkSize;
			}
		if (iMemModel!=E_MM_Direct && strlen(arg3))
			{
				#ifdef __TOOLS2__
			istringstream arg3s(arg3);
			#else
			istrstream arg3s(arg3,strlen(arg3));
			#endif

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
			arg3s >> setbase(0);
#endif //__MSVCDOTNET__

			arg3s >> iPageSize;
			}
		else if (iMemModel==E_MM_Direct)
			iPageSize=iChunkSize;
		if (iMemModel!=E_MM_Direct && strlen(arg4))
			{
			#ifdef __TOOLS2__
			istringstream arg4s(arg4);
			#else
			istrstream arg4s(arg4,strlen(arg4));
			#endif

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
			arg4s >> setbase(0);
#endif //__MSVCDOTNET__

			arg4s >> iVirtualAllocSize;
			}
		else
			iVirtualAllocSize = iPageSize;
		
		break;
		}
	case EKeywordNoWrapper:
		if (gHeaderType<0)
			gHeaderType=0;
		break;
	case EKeywordEpocWrapper:
		if (gHeaderType<0)
			gHeaderType=1;
		break;
	case EKeywordCoffWrapper:
		if (gHeaderType<0)
			gHeaderType=2;
		break;

	case EKeywordPlatSecEnforcement:
		ParseBoolArg(gPlatSecEnforcement,iReader.Word(1));
		if(gPlatSecEnforcement)
			iKernelConfigFlags |= EKernelConfigPlatSecEnforcement;
		else
			iKernelConfigFlags &= ~EKernelConfigPlatSecEnforcement;
		break;
	case EKeywordPlatSecDiagnostics:
		ParseBoolArg(gPlatSecDiagnostics,iReader.Word(1));
		if(gPlatSecDiagnostics)
			iKernelConfigFlags |= EKernelConfigPlatSecDiagnostics;
		else
			iKernelConfigFlags &= ~EKernelConfigPlatSecDiagnostics;
		break;
	case EKeywordPlatSecProcessIsolation:
		{
		TInt processIsolation;
		ParseBoolArg(processIsolation,iReader.Word(1));
		if(processIsolation)
			iKernelConfigFlags |= EKernelConfigPlatSecProcessIsolation;
		else
			iKernelConfigFlags &= ~EKernelConfigPlatSecProcessIsolation;
		break;
		}
	case EKeywordPlatSecEnforceSysBin:
		{
		ParseBoolArg(gPlatSecEnforceSysBin,iReader.Word(1));
		if(gPlatSecEnforceSysBin)
			iKernelConfigFlags |= EKernelConfigPlatSecEnforceSysBin;
		else
			iKernelConfigFlags &= ~EKernelConfigPlatSecEnforceSysBin;
		break;
		}
	case EKeywordPlatSecDisabledCaps:
		if(iPlatSecDisabledCapsParsed)
			Print(EWarning, "PlatSecDisabledCaps redefined - previous values lost\n");
		{
		ParseCapabilitiesArg(iPlatSecDisabledCaps, iReader.Word(1));
		gPlatSecDisabledCaps = iPlatSecDisabledCaps;
		iPlatSecDisabledCapsParsed=ETrue;
		}
		break;
	case EKeywordPagingPolicy:
		{
		if(iPagingPolicyParsed)
			Print(EWarning, "PagingPolicy redefined - previous PagingPolicy values lost\n");
		if(iDataPagingPolicyParsed)
			Print(EWarning, "PagingPolicy defined - previous DataPagingPolicy values lost\n");
		if(iCodePagingPolicyParsed)
			Print(EWarning, "PagingPolicy defined - previous DataPagingPolicy values lost\n");
		iPagingPolicyParsed = true;
		iKernelConfigFlags &= ~(EKernelConfigCodePagingPolicyMask|EKernelConfigDataPagingPolicyMask);
		TInt policy = ParsePagingPolicy(iReader.Word(1));
		if(policy<0)
			{
			Print(EError,"Unrecognised option for PAGINGPOLICY keyword\n");
			success = false;
			}
		else 	{
#ifndef SYMBIAN_WRITABLE_DATA_PAGING
			if ((policy != EKernelConfigPagingPolicyNoPaging) && (iMemModel == E_MM_Flexible))
				Print(EWarning, "SYMBIAN_WRITABLE_DATA_PAPING is not defined. Writable data paging is not warranted on this version of Symbian.");
#endif
			iKernelConfigFlags |= policy << EKernelConfigCodePagingPolicyShift;
			iKernelConfigFlags |= policy << EKernelConfigDataPagingPolicyShift;
			}
		}
		break;
	case EKeywordCodePagingPolicy:
		{
		if(iCodePagingPolicyParsed)
			Print(EWarning, "CodePagingPolicy redefined - previous CodePagingPolicy values lost\n");
		if(iPagingPolicyParsed)
			Print(EWarning, "CodePagingPolicy defined - previous PagingPolicy values lost\n");
		iCodePagingPolicyParsed = true;
		iKernelConfigFlags &= ~EKernelConfigCodePagingPolicyMask;
		TInt policy = ParsePagingPolicy(iReader.Word(1));
		if(policy<0)
			{
			Print(EError,"Unrecognised option for CODEPAGINGPOLICY keyword\n");
			success = false;
			}
		else
			iKernelConfigFlags |= policy << EKernelConfigCodePagingPolicyShift;
		}
		break;
	case EKeywordDataPagingPolicy:
		{
		if(iDataPagingPolicyParsed)
			Print(EWarning, "DataPagingPolicy redefined - previous DataPagingPolicy values lost\n");
		if(iPagingPolicyParsed)
			Print(EWarning, "DataPagingPolicy defined - previous PagingPolicy values lost\n");
		iDataPagingPolicyParsed = true;
		iKernelConfigFlags &= ~EKernelConfigDataPagingPolicyMask;
		TInt policy = ParsePagingPolicy(iReader.Word(1));
		if(policy<0)
			{
			Print(EError,"Unrecognised option for DATAPAGINGPOLICY keyword\n");
			success = false;
			}
		else
#ifndef SYMBIAN_WRITABLE_DATA_PAGING
			if ((policy != EKernelConfigPagingPolicyNoPaging) && (iMemModel == E_MM_Flexible))
				Print(EWarning, "SYMBIAN_WRITABLE_DATA_PAPING is not defined. Writable data paging is not warranted on this version of Symbian.");
#endif
			iKernelConfigFlags |= policy << EKernelConfigDataPagingPolicyShift;
		}
		break;
	case EKeywordPagingOverride:
		{
		if(iPagingOverrideParsed)
			Print(EWarning, "PagingOverride redefined - previous PagingOverride values lost\n");
		if(iCodePagingOverrideParsed)
			Print(EWarning, "PagingOverride defined - previous CodePagingOverride valus lost\n");
		if(iDataPagingOverrideParsed)
			Print(EWarning, "PagingOverride defined - previous DataPagingOverride values lostn");
		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(EWarning, "DataPagingOverride defined - previous PagingOverride values lost\n");
		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 EKeywordDemandPagingConfig:
		{
		memset(&gDemandPagingConfig,0,sizeof(gDemandPagingConfig));
		val >> gDemandPagingConfig.iMinPages;
		if(strlen(iReader.Word(2)))
			{
			#ifdef __TOOLS2__
			istringstream val(iReader.Word(2));
			#else
			istrstream val(iReader.Word(2),strlen(iReader.Word(2)));
		    #endif
			val >> gDemandPagingConfig.iMaxPages;
			if(strlen(iReader.Word(3)))
				{
				#ifdef __TOOLS2__
				istringstream val(iReader.Word(3));
				#else
				istrstream val(iReader.Word(3),strlen(iReader.Word(3)));
				#endif
				val >> gDemandPagingConfig.iYoungOldRatio;
				for(int i=0; i<=2; i++)
					{
					if(!strlen(iReader.Word(4+i)))
						break;
					#ifdef __TOOLS2__
					istringstream val(iReader.Word(4+i));
					#else
					istrstream val(iReader.Word(4+i),strlen(iReader.Word(4+i)));
					#endif
					val >> gDemandPagingConfig.iSpare[i];
					}
				}
			}
		if(gDemandPagingConfig.iMaxPages && gDemandPagingConfig.iMaxPages<gDemandPagingConfig.iMinPages)
			{
			Print(EError,"DemandPagingConfig maxPages must be >= minPages\n");
			success = EFalse;
			break;
			}
		}
		break;
	case EKeywordPagedRom:
		gPagedRom = ETrue;
		break;

	case EKeywordTrace:
		val >> TraceMask;
		break;

	case EKeywordKernelTrace:
		{
		TInt i;
		val >> iTraceMask[0];
		i=1;
		while(strlen(iReader.Word(i+1)) && i<KNumTraceMaskWords)
			{
			#ifdef __TOOLS2__
			istringstream val(iReader.Word(i+1));
			#else
			istrstream val(iReader.Word(i+1),strlen(iReader.Word(i+1)));
			#endif
			#if defined(__MSVCDOTNET__) || defined (__TOOLS2__)
 				val >> setbase(0);
			#endif
			val >> iTraceMask[i];
			++i;
			}
		}
		break;

	case EKeywordBTrace:
		{
		TUint i; 
		val >> iInitialBTraceFilter[0];
		i=1;
		while(strlen(iReader.Word(i+1)) && i<sizeof(iInitialBTraceFilter)/sizeof(TUint32))
			{
			#ifdef __TOOLS2__
			istringstream val(iReader.Word(i+1));
			#else
			istrstream val(iReader.Word(i+1),strlen(iReader.Word(i+1)));
			#endif
			#if defined(__MSVCDOTNET__) || defined (__TOOLS2__)
 				val >> setbase(0);
			#endif
			val >> iInitialBTraceFilter[i];
			++i;
			}
		}
		break;

	case EKeywordBTraceMode:
		val >> iInitialBTraceMode;
		break;

	case EKeywordBTraceBuffer:
		val >> iInitialBTraceBuffer;
		break;

	case EKeywordDebugPort:
		if (iDebugPortParsed)
			Print(EWarning, "DEBUGPORT redefined - previous value lost\n");
		val >> iDebugPort;
		iDebugPortParsed = ETrue;
		break;

	case EKeywordCompress:
		gEnableCompress=ETrue; // Set ROM Compression on.
		break;

	case EKeywordCollapse:
		if (strnicmp(iReader.Word(1), "arm", 3)!=0 || strnicmp(iReader.Word(2), "gcc", 3)!=0)
			{
			Print(EWarning, "COLLAPSE only supported for ARM and GCC - keyword ignored\n");
			}
		else
			{
			TInt cm;
			#ifdef __TOOLS2__
			istringstream cmval(iReader.Word(3));
			#else
			istrstream cmval(iReader.Word(3),strlen(iReader.Word(3)));
			#endif

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
			cmval >> setbase(0);
#endif //__MSVCDOTNET__

			cmval>>cm;
			if (cm<0 || cm>ECollapseAllChainBranches)
				{
				Print(EWarning, "COLLAPSE mode unrecognised - keyword ignored\n");
				}
			else
				iCollapseMode=cm;
			}
		break;

	case EKeywordPrimary:
		iNumberOfPrimaries++;
		break;
	case EKeywordVariant:
		hardwareVariant=ParseVariant();
		if (THardwareVariant(hardwareVariant).IsVariant())
			{
			iNumberOfVariants++;
			TUint layer=THardwareVariant(hardwareVariant).Layer();
			TUint vmask=THardwareVariant(hardwareVariant).VMask();
			iAllVariantsMask[layer] |= vmask;
			}
		else
			{
			Print(EError,"Variant DLLs must belong to variant layer - line %d\n", iReader.CurrentLine());
			break;
			}

		break;
	case EKeywordExtension:
		iNumberOfExtensions++;
		break;
	case EKeywordDevice:
		iNumberOfDevices++;
		break;

	case EKeywordKernelRomName:
		Print(EError,"Keyword '%s' only valid in extension ROMs - line %d\n", iReader.Word(0), iReader.CurrentLine());
		break;

	case EKeywordArea:
		if(! ParseAreaKeyword())
			success = EFalse;
		break;

	case EKeywordExecutableCompressionMethodNone:
		gCompressionMethod = 0;
		break;
		
	case EKeywordExecutableCompressionMethodInflate:
		gCompressionMethod = KUidCompressionDeflate;
		break;
		
	case EKeywordExecutableCompressionMethodBytePair:
		gCompressionMethod = KUidCompressionBytePair;
		break;
		
	case EKeywordKernelConfig:
		{
		TInt bit, setTo;
		val >> bit;
		if(bit<0 || bit>31)
			{
			Print(EError,"KernelConfig bit must be between 0 and 31\n");
			success = EFalse;
			break;
			}
		if(ParseBoolArg(setTo,iReader.Word(2))!=KErrNone)
			{
			success = EFalse;
			break;
			}
		if(setTo)
			iKernelConfigFlags |= 1<<bit;
		else
			iKernelConfigFlags &= ~(1<<bit);
		break;
		}
		
	case EKeywordMaxUnpagedMemSize:
		{
		TInt unpagedSize = -1;
		val >> unpagedSize;
			
		if (!val || unpagedSize < 0)
			{
			Print(EWarning, "Invalid value of MaxUnpagedSize (0 to 0x7FFFFFFF) - value ignored\n");
			break;
			}
			
		iMaxUnpagedMemSize = unpagedSize;
		
		if(iUpdatedMaxUnpagedMemSize)
			{
			Print(EWarning, "MaxUnpagedSize redefined - previous values lost\n");
			}
		else
			{
			iUpdatedMaxUnpagedMemSize = ETrue;
			}
		
		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 ROM has not been supplied.\n");
		Print(EAlways,"Use the keyword \"romname\".\n");
		retVal = EFalse;
		}
	if (iBootFileName==0)
		{
		Print(EAlways,"The name of the bootstrap binary has not been supplied.\n");
		Print(EAlways,"Use the keyword \"bootbinary\".\n");
		retVal = EFalse;
		}
	if (iRomLinearBase==0xFFFFFFFF)
		{
		Print(EAlways,"The base linear address of the ROM has not been supplied.\n");
		Print(EAlways,"Use the keyword \"romlinearbase\".\n");
		retVal = EFalse;
		}
	if (iRomSize==0)
		{
		Print(EAlways,"The size of the ROM has not been supplied.\n");
		Print(EAlways,"Use the keyword \"romsize\".\n");
		retVal = EFalse;
		}
	if (iKernDataRunAddress==0)
		{
		Print(EAlways,"The address for the kernel's data section has not been supplied.\n");
		Print(EAlways,"Use the keyword \"kerneldataaddress\".\n");
		retVal = EFalse;
		}

	// Validation
	if (iNumberOfPrimaries>1 && iKernelModel==ESingleKernel)
		{
		Print(EError,"More than one primary in single-kernel ROM\n");
		retVal = EFalse;
		}
	if (iNumberOfPrimaries==0)
		{
		Print(EError,"No primary file specified\n");
		retVal = EFalse;
		}
	if (iNumberOfVariants==0)
		{
		Print(EError,"No variants specified\n");
		retVal = EFalse;
		}
	if(iNumberOfHCRDataFiles > 1)
		{
		Print(EError,"More than one hcr data files in ROM.\n");
		retVal = EFalse ;
		}
	// Warn about enabling data paging on OS versions where's it's not officially supported
#ifndef SYMBIAN_WRITABLE_DATA_PAGING
	if (iMemModel == E_MM_Flexible &&
		(iKernelConfigFlags & EKernelConfigDataPagingPolicyMask) != EKernelConfigDataPagingPolicyNoPaging)
		{
		Print(EWarning, "Writable data paging is not warranted on this version of Symbian OS.");
		}
#endif
	
	// Apply defaults as necessary
	TheRomLinearAddress=iRomLinearBase;

	if (iDataRunAddress==0)
		{
		iDataRunAddress=0x400000;
		Print(EWarning,"The address for a running ROM app's data section (keyword \"dataaddress\") has not been supplied.\n");
		Print(EWarning,"Will use the default value of 0x%0x.\n", iDataRunAddress);
		retVal = EFalse;
		}
	if (iRomAlign==0)
		{
		iRomAlign=0x1000;
		Print(EWarning,"The ROM section alignment (keyword \"romalign\") has not been supplied.\n");
		Print(EWarning,"Will use the default value of 0x%0x.\n", iRomAlign);
		}
	if (iRomAlign&0x3)
		{
		Print(EWarning, "Rounding rom alignment to multiple of 4.\n");
		iRomAlign=(iRomAlign+0x3)&0xfffffffc;
		}
	if (iKernHeapMin==0)
	 	{
	 	iKernHeapMin=0x10000;
		Print(EWarning,"The kernel heap min size (keyword \"kernelheapmin\") has not been supplied.\n");
		Print(EWarning,"Will use the default value of 0x%0x.\n", iKernHeapMin);
		}
	if (iKernHeapMax==0)
	 	{
	 	iKernHeapMax=0x100000;
		Print(EWarning,"The kernel heap max size (keyword \"kernelheapmax\") has not been supplied.\n");
		Print(EWarning,"Will use the default value of 0x%0x.\n", iKernHeapMax);
		}

	if (iTime==0)
		{
		Print(ELog, "No timestamp specified. Using current time...\n");
		ObeyFileReader::TimeNow(iTime);
		}

	Print(ELog, "\nCreating Rom image %s\n", iRomFileName);
	Print(ELog, "MemModel: %1d\nChunkSize: %08x\nPageSize: %08x\n", iMemModel, iChunkSize, iPageSize);
	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;
	}


TBool CObeyFile::CheckHardwareVariants()
	{
	iPrimaries=new TRomBuilderEntry*[iNumberOfPrimaries];
	iVariants=new TRomBuilderEntry*[iNumberOfVariants];
	THardwareVariant* primaryHwVariants=new THardwareVariant[iNumberOfPrimaries];
	TInt nVar=0;
	TRomBuilderEntry* current=FirstFile();
	THardwareVariant* variantHwVariants=new THardwareVariant[iNumberOfVariants];
	while(current)
		{
		if (current->Variant())
			{
			TInt i;
			for(i=0; i<nVar; i++)
				{
				if (!current->iHardwareVariant.MutuallyExclusive(variantHwVariants[i]))
					{
					delete[] variantHwVariants;
					delete[] primaryHwVariants;
					Print(EError,"Variants not mutually exclusive\n");
					return EFalse;
					}
				}
			iVariants[nVar]=current;
			variantHwVariants[nVar++]=current->iHardwareVariant;
			}
		current=NextFile();
		}
	delete[] variantHwVariants;
	nVar=0;
	current=FirstFile();
	while(current)
		{
		TInt i;
		for (i=0; i<iNumberOfVariants; i++)
			{
			if (iVariants[i]->iHardwareVariant<=current->iHardwareVariant)
				break;
			}
		if (i==iNumberOfVariants)
			{
			Print(EError,"File %s[%08x] does not correspond to any variant\n",
									current->iName,TUint(current->iHardwareVariant));
			delete[] primaryHwVariants;
			return EFalse;
			}
		if (current->Primary())
			{
			for(i=0; i<nVar; i++)
				{
				if (!current->iHardwareVariant.MutuallyExclusive(primaryHwVariants[i]))
					{
					delete[] primaryHwVariants;
					Print(EError,"Primaries not mutually exclusive\n");
					return EFalse;
					}
				}
			iPrimaries[nVar]=current;
			primaryHwVariants[nVar++]=current->iHardwareVariant;
			}
		current=NextFile();
		}
	delete[] primaryHwVariants;
	if (iNumberOfExtensions)
		{
		nVar=0;
		iExtensions=new TRomBuilderEntry*[iNumberOfExtensions];
		TRomBuilderEntry* current=FirstFile();
		while(current)
			{
			if (current->Extension())
				{
				if (current->iHardwareVariant.IsVariant())
					{
					TUint layer=current->iHardwareVariant.Layer();
					TUint vmask=current->iHardwareVariant.VMask();
					if ((iAllVariantsMask[layer]&vmask)==0)
						{
						Print(EError,"Variant-layer extension %s has no corresponding variant DLL\n",current->iName);
						return EFalse;
						}
					}
				iExtensions[nVar++]=current;
				}
			current=NextFile();
			}
		}
	if (iNumberOfDevices)
		{
		nVar=0;
		iDevices=new TRomBuilderEntry*[iNumberOfDevices];
		TRomBuilderEntry* current=FirstFile();
		while(current)
			{
			if (current->Device())
				{
				if (current->iHardwareVariant.IsVariant())
					{
					TUint layer=current->iHardwareVariant.Layer();
					TUint vmask=current->iHardwareVariant.VMask();
					if ((iAllVariantsMask[layer]&vmask)==0)
						{
						Print(EError,"Variant-layer device %s has no corresponding variant DLL\n",current->iName);
						return EFalse;
						}
					}
				iDevices[nVar++]=current;
				}
			current=NextFile();
			}
		}
	NumberOfVariants=iNumberOfVariants;
	return ETrue;
	}


TInt CObeyFile::ProcessExtensionRom(MRomImage*& aKernelRom)
	{
	//
	// First pass through the obey file to set up key variables
	//

	iReader.Rewind();

	enum EKeyword keyword;

	// Deal with the "extensionrom" keyword, which should be first
	
	if (iReader.NextLine(1,keyword) != KErrNone)
		return KErrEof;
	if (keyword != EKeywordExtensionRom)
		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 ROM %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 == EKeywordExtensionRom)
			break;
		ProcessExtensionKeyword(keyword);
		}

	if (!GotExtensionVariables(aKernelRom))
		return KErrGeneral;

	if (! CreateDefaultArea())
		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 ROM image not yet implemented\n");
	iLastExecutable = 0;
	iRootDirectory = aKernelRom->CopyDirectory(iLastExecutable);


	TInt align=0;
	while (iReader.NextLine(2,keyword)!=KErrEof)
		{
		if (keyword == EKeywordExtensionRom)
			break;

		switch (keyword)
			{
		case EKeywordSection:
		case EKeywordArea:
		case EKeywordPrimary:
		case EKeywordSecondary:
		case EKeywordExtension:
		case EKeywordDevice:
		case EKeywordVariant:
		case EKeywordHardwareConfigRepositoryData:
			Print(EError, "Keyword '%s' not supported in extension ROMs - line %d\n",
				iReader.Word(0), iReader.CurrentLine());
			break;

		case EKeywordAlign:
			if (iReader.ProcessAlign(align)!=KErrNone)
				return KErrGeneral;
			break;

		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 (iNumberOfDataFiles+iNumberOfPeFiles==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 EKeywordKernelRomName:
		iReader.CopyWord(1, iKernelRomName);
		return;
	case EKeywordRomNameOdd:
		iReader.CopyWord(1, iRomOddFileName);
		return;
	case EKeywordRomNameEven:
		iReader.CopyWord(1, iRomEvenFileName);
		return;
	case EKeywordSRecordFileName:
		iReader.CopyWord(1, iSRecordFileName);
		return;

	case EKeywordRomLinearBase:
		val >> iRomLinearBase;
		return;
	case EKeywordRomSize:
		val >> iRomSize;
		return;
	case EKeywordRomAlign:
		val >> iRomAlign;
		return;

	case EKeywordDataAddress:
		val >> iDataRunAddress;
		return;
	case EKeywordDefaultStackReserve:
		val >> iDefaultStackReserve;
		return;
	case EKeywordVersion:
		val >> iVersion;
		return;
	case EKeywordSRecordBase:
		val >> iSRecordBase;
		return;
	case EKeywordRomChecksum:
		val >> iCheckSum;
		return;
	case EKeywordTime:
		iReader.ProcessTime(iTime);
		return;

	case EKeywordTrace:
		val >> TraceMask;
		return;

	case EKeywordCollapse:
		if (strnicmp(iReader.Word(1), "arm", 3)!=0 || strnicmp(iReader.Word(2), "gcc", 3)!=0)
			{
			Print(EWarning, "COLLAPSE only supported for ARM and GCC - keyword ignored\n");
			}
		else
			{
			TInt cm;
			#ifdef __TOOLS2__
			istringstream cmval(iReader.Word(3));
			#else
			istrstream cmval(iReader.Word(3),strlen(iReader.Word(3)));
			#endif

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
			cmval >> setbase(0);
#endif //__MSVCDOTNET__

			cmval>>cm;
			if (cm<0 || cm>ECollapseAllChainBranches)
				{
				Print(EWarning, "COLLAPSE mode unrecognised - keyword ignored\n");
				}
			else
				{
				Print(EWarning, "COLLAPSE not currently supported for extension roms\n");
				}
			}
		return;

	case EKeywordCoreImage:
		//Already handled, skip it
		return;

	default:
		Print(EError,"Keyword '%s' not valid in extension ROMs - line %d\n", iReader.Word(0), iReader.CurrentLine());
		break;
		}
	return;
	}

TBool CObeyFile::GotExtensionVariables(MRomImage*& aRom)
//
// Checks that the obeyfile has supplied enough variables to continue
//
   	{

	TBool retVal=ETrue;
	TText* kernelRomName = iKernelRomName;

	// Mandatory keywords

	if (iRomSize==0)
		{
		Print(EAlways,"The size of the extension ROM has not been supplied.\n");
		Print(EAlways,"Use the keyword \"romsize\".\n");
		retVal = EFalse;
		}

	// keywords we need if we don't already have a ROM image to work from

	if (aRom==0)
		{
		if (iKernelRomName==0)
			{
			Print(EAlways,"The name of the kernel ROM has not been supplied.\n");
			Print(EAlways,"Use the keyword \"kernelromname\".\n");
			retVal = EFalse;
			}
		if (iRomLinearBase==0xFFFFFFFF)
			{
			Print(EAlways,"The base linear address of the ROM has not been supplied.\n");
			Print(EAlways,"Use the keyword \"romlinearbase\".\n");
			retVal = EFalse;
			}
		}
	else
		{
		if (iKernelRomName != 0)
			{
			Print(EWarning,"Keyword \"kernelromname\") ignored.\n");
			}
		kernelRomName = aRom->RomFileName();
		}

	// validation

	// Apply defaults as necessary

	if (iRomLinearBase==0xFFFFFFFF && aRom!=0)
		{
		iRomLinearBase = aRom->RomBase() + aRom->RomSize();
		Print(ELog,"Assuming extension ROM is contiguous with kernel ROM\n");
		Print(ELog,"Setting romlinearbase to 0x%08x\n", iRomLinearBase);
		}
	TheRomLinearAddress=iRomLinearBase;

	if (iDataRunAddress==0)
		{
		iDataRunAddress= aRom->DataRunAddress();
		Print(EWarning,"The address for a running ROM app's data section (keyword \"dataaddress\") has not been supplied.\n");
		Print(EWarning,"Will use the default value of 0x%0x.\n", iDataRunAddress);
		}
	if (iRomAlign==0)
		{
		iRomAlign = aRom->RomAlign();
		Print(EWarning,"The ROM section alignment (keyword \"romalign\") has not been supplied.\n");
		Print(EWarning,"Will use the default value of 0x%0x.\n", iRomAlign);
		}
	if (iRomAlign&0x3)
		{
		Print(EWarning, "Rounding rom alignment to multiple of 4.\n");
		iRomAlign=(iRomAlign+0x3)&0xfffffffc;
		}
	if (iTime==0)
		{
		Print(ELog, "No timestamp specified. Using current time...\n");
		ObeyFileReader::TimeNow(iTime);
		}

	// fix up "*" in romname
	TText newname[256];
	TText* p=newname;
	TText* q=iRomFileName;
	TText c;

	while ((c=*q++)!='\0')
		{
		if (c!='*')
			{
			*p++=c;
			continue;
			}
		TText *r=kernelRomName;
		while ((c=*r++)!='\0')
			*p++=c;
		}
	*p = '\0';
	free(iRomFileName);
	iRomFileName = (TText*)strdup((char*)newname);

	Print(ELog, "\nCreating Rom image %s\n", iRomFileName);
	return retVal;
	}


////////////////////////////////////////////////////////////////////////
// AREA RELATED CODE
////////////////////////////////////////////////////////////////////////

/**
 Process an area declaration.
 */

TBool CObeyFile::ParseAreaKeyword()
	{
	const char* name = iReader.Word(1);
	TLinAddr start;
	TUint length;
	if(Val(start, iReader.Word(2)) != KErrNone || Val(length, iReader.Word(3)) != KErrNone)
		{
		Print(EError, "Line %d: Wrong area specification: Should be <name> <start address> <length>\n",
			  iReader.CurrentLine());
		return EFalse;
		}

	if (! AddAreaAndHandleError(name, start, length, iReader.CurrentLine()))
		return EFalse;

	return ETrue;
	}


/**
 Process an "area=xxx" file attribute.
 */

TBool CObeyFile::ParseAreaAttribute(const TText* aArg, TInt aLineNumber, const Area*& aArea)
	{
	if (iSectionPosition != -1)
		{
		Print(EError, "Line %d: Relocation to area forbidden in second section\n", aLineNumber);
		return EFalse;
		}

	aArea = iAreaSet.FindByName(reinterpret_cast<const char*>(aArg));
	if (aArea == 0)
		{
		Print(EError, "Line %d: Attempt to use an unknown area named '%s'\n", aLineNumber, aArg);
		return EFalse;
		}

	return ETrue;
	}


TBool CObeyFile::CreateDefaultArea()
	{
	return AddAreaAndHandleError(AreaSet::KDefaultAreaName, iRomLinearBase, iRomSize);
	}


TBool CObeyFile::AddAreaAndHandleError(const char* aName, TLinAddr aDestBaseAddr, TUint aLength, TInt aLineNumber)
	{
	TBool added = EFalse;
	
	const char lineInfoFmt[] = "Line %d:";
	char lineInfo[sizeof(lineInfoFmt)+10];
	if (aLineNumber > 0)
		sprintf(lineInfo, lineInfoFmt, aLineNumber);
	else
		lineInfo[0] = '\0';

	const char* overlappingArea;
	switch (iAreaSet.AddArea(aName, aDestBaseAddr, aLength, overlappingArea))
		{
	case AreaSet::EAdded:
		TRACE(TAREA, Print(EScreen, "Area '%s' added to AreaSet\n", aName));
		added = ETrue;
		break;
	case AreaSet::EOverlap:
		Print(EError, "%s Area '%s' collides with area '%s'\n", lineInfo, aName, overlappingArea);
		break;
	case AreaSet::EDuplicateName:
		Print(EError, "%s Name '%s' already reserved for another area\n", lineInfo, aName);
		break;
	case AreaSet::EOverflow:
		Print(EError, "%s Area overflow (0x%X+0x%X > 0x%X)\n", lineInfo, aDestBaseAddr, aLength, -1);
		break;
	default:
		assert(0);				// can't happen
		}

	return added;
	}

TInt getNumber(TText*);


// 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();
	DllDataEntry *aDllDataEntry=NULL;

	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
		{			
			TUint hardwareVariant=ParseVariant();
			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,hardwareVariant,TRUE);
					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 )
			{
				MapOfStringIterator RenamedFileMapIterator;

				// If the E32Image file to be patched is not included then check if the
				// file was renamed.
				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 ((char*)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;
		dataEntry->iRomNode = existingFile;

		if (aDllDataEntry==NULL)
		{
			// Set the first node of the patchdata linked list
			aDllDataEntry = dataEntry;
			SetFirstDllDataEntry(aDllDataEntry);
		}
		else
		{
			// Add the new node at the end of linked list
			aDllDataEntry->AddDllDataEntry(dataEntry);
			aDllDataEntry = aDllDataEntry->NextDllDataEntry();
		}
	}
	return ETrue;
}

int CObeyFile::SkipToExtension()
{
	int found = 0;

	iReader.Rewind();
	enum EKeyword keyword;
	while (iReader.NextLine(1,keyword) != KErrEof)
	{
		if (keyword == EKeywordExtensionRom)
		{
			found = 1;
			iReader.Mark(); // ready for processing extension
			break;
		}
	}

	if(!found)
	{
		Print(EError, "Coreimage option requires valid \"extensionrom\" keyword\n");
	}

	return found;
}

TText* CObeyFile::ProcessCoreImage()
{
	// check for coreimage keyword and return filename
	iReader.Rewind();
	enum EKeyword keyword;
	TText* coreImageFileName = 0;

	iRomAlign = KDefaultRomAlign;
	iDataRunAddress = KDefaultDataRunAddress;

	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);
			break;
		}
		else if ((keyword == EKeywordRomAlign) || (keyword == EKeywordDataAddress))
		{
#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__
			if(keyword == EKeywordRomAlign)
			{
				val >> iRomAlign;
			}
			else
			{
				val >> iDataRunAddress;
			}
		}
	}

	if (iRomAlign&0x3)
	{
		//Rounding rom alignment to multiple of 4
		iRomAlign=(iRomAlign+0x3)&0xfffffffc;
	}

	return coreImageFileName;
}