imgtools/romtools/rombuild/r_build.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: 
*
*/


#define __REFERENCE_CAPABILITY_NAMES__
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <e32std.h>
#include <e32std_private.h>
#include <e32rom.h>
#include "u32std.h"
#include <e32uid.h>
#include <f32file.h>
#include "h_utl.h"

#define USE_IAT_FOR_IMPORTS (iOverrideFlags&KOverrideKeepIAT || (iHdr->iCpuIdentifier & 0x1000))

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
#include <iomanip>
#else //!__MSVCDOTNET__
#include <iomanip.h>
#endif

#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
#include <iomanip>
#else //!__MSVCDOTNET__
#include <iomanip.h>
#endif

#include "r_obey.h"
#include "r_global.h"
#include "r_dir.h"

TInt NumRootDirs;

inline TLinAddr ActualToRomAddress(TAny* anAddr)
	{ return TLinAddr(anAddr)-TheRomMem+TheRomLinearAddress; }

TBool THardwareVariant::MutuallyExclusive(THardwareVariant a) const
	{
	if (Layer()<=3 || a.Layer()<=3)
		return EFalse;
	if (Parent()==3 && a.Parent()==3)
		return(Layer()!=a.Layer());
	if (Parent()==3 && a.Parent()!=Layer())
		return ETrue;
	if (a.Parent()==3 && Parent()!=a.Layer())
		return ETrue;
	if (Layer()!=a.Layer())
		return ETrue;
	return((VMask()&a.VMask())==0);
	}

TBool THardwareVariant::IsVariant() const
	{
	if (Layer()<=3 || Parent()==3)
		return EFalse;
	TUint v=VMask();
	TInt i;
	for (i=0; i<16; i++)
		{
		if (v==TUint(1<<i))
			return ETrue;
		}
	return EFalse;
	}

TInt THardwareVariant::Compare(THardwareVariant a) const
	{
	TUint l1=Layer();
	TUint p1=Parent();
	TUint v1=VMask();
	TUint l2=a.Layer();
	TUint p2=a.Parent();
	TUint v2=a.VMask();

	if (l1<=3)
		{
		if (l2<=3)
			{
			return EEqual;
			}
		return EGreater;
		}
	if (l2<=3)
		return ELess;
	if (p1==3)
		{
		if (p2==3)
			{
			if (l1==l2)
				return EEqual;
			return EUnordered;
			}
		if (p2==l1)
			return EGreater;
		return EUnordered;
		}
	if (p2==3)
		{
		if (p1==l2)
			return ELess;
		return EUnordered;
		}
	if (l1!=l2)
		return EUnordered;
	if ((v1&v2)==v1)
		return ELess;
	if ((v1&v2)==v2)
		return EGreater;
	return EUnordered;
	}
//
TInt TRomNode::Count=0;
TRomNode::TRomNode(const TText* aName, TRomBuilderEntry* aEntry)
//
// Constructor from TRomBuilderEntry, i.e. for new file or directory
//
	{
	memset(this, 0, sizeof(TRomNode));
	iAtt = (TUint8)KEntryAttReadOnly;
	iName = (TText*)NormaliseFileName((const char*)aName);
	iIdentifier=TRomNode::Count++;
	iRomFile = new TRomFile;
	if (aEntry)
		{
		iRomFile->iRbEntry = aEntry;
		aEntry->SetRomNode(this);
		iBareName = strdup(aEntry->iBareName);
		iRomFile->iHwvd = aEntry->iHardwareVariant;
		}
	else
		{
		iRomFile->iDir = ETrue;
		iAtt |= (TUint8)KEntryAttDir;
		iBareName = strdup((const char*)iName);
		iRomFile->iHwvd = KVariantIndependent;
		}
	TRACE(TROMNODE,Print(ELog, "TRomNode %d name %s bare %s att %02x romfile %08x\n", iIdentifier,
			iName, iBareName, iAtt, iRomFile));
	}

TRomNode::TRomNode(const TText* aName, TRomNode* aNode)
//
// Constructor from TRomNode, i.e. for aliased file
//
	{
	memset(this, 0, sizeof(TRomNode));
	iAtt = aNode->iAtt;
	iIdentifier=TRomNode::Count++;
	iName = (TText*)NormaliseFileName((const char*)aName);
	iHidden = aNode->iHidden;
	iRomFile = aNode->iRomFile;
	if (iRomFile)
		{
		iRomFile->Open();
		}
	TRACE(TROMNODE,Print(ELog, "TRomNode %d DUP name %s romfile %08x\n", iIdentifier, iName, iRomFile));
	}

TRomNode::TRomNode(const TRomNode& aNode)
//
// Copy constructor - only used in deep copy function
//
	{
	memset(this, 0, sizeof(TRomNode));
	iAtt = aNode.iAtt;
	iIdentifier=TRomNode::Count++;
	iName = (TText*)strdup((const char*)aNode.iName);
	iBareName = strdup(aNode.iBareName);
	iHidden = aNode.iHidden;
	iRomFile = aNode.iRomFile;
	if (iRomFile)
		{
		iRomFile->Open();
		}
	TRACE(TROMNODE,Print(ELog, "TRomNode %d COPY name %s bare %s att %02x romfile %08x\n", iIdentifier,
			iName, iBareName, iAtt, iRomFile));
	}

TRomNode::~TRomNode()
	{
	free(iName);
	free(iBareName);
	if (iRomFile)
		iRomFile->Close();
	}

TRomNode* TRomNode::FindInDirectory(const TText* aName)
//
// Check if the TRomNode for aName exists in aDir, and if so, return it.
//
	{

	TRomNode *entry=iChild; // first subdirectory or file
	while (entry)
		{
		if (!entry->iHidden && (stricmp((const char *)aName, (const char *)entry->iName))==0) 
			return entry;
		else
			entry=entry->iSibling;
		}
	return 0;
	}

TRomNode* TRomNode::FindInDirectory(const TText* aName, THardwareVariant aVariant, TBool aPatchDataFlag)
//
// Check for a file with same name and a compatible hardware variant
//
	{

	TRomNode *entry=iChild; // first subdirectory or file
	while (entry)
		{
		if (((!entry->iHidden)||aPatchDataFlag) && entry->iRomFile && (stricmp((const char *)aName, (const char *)entry->iName))==0) 
			{
			if (!aVariant.MutuallyExclusive(entry->HardwareVariant()))
				return entry;
			}
		entry=entry->iSibling;
		}
	return 0;
	}

void TRomNode::AddFile(TRomNode* aChild)
	{
	if (!(iAtt & KEntryAttDir))
		{
		Print(EError, "Adding subdirectory to a file!!!\n");
		return;
		}
	Add(aChild);
	}

TRomNode* TRomNode::NewSubDir(const TText* aName)
	{
	if (!(iAtt & KEntryAttDir))
		{
		Print(EError, "Adding subdirectory to a file!!!\n");
		return 0;
		}

	TRomNode* node = new TRomNode(aName);
	if (node==0)
		{
		Print(EError, "TRomNode::NewNode: Out of memory\n");
		return 0;
		}
	Add(node);
	return node;
	}

void TRomNode::Add(TRomNode* aChild)
	{
	if (iChild) // this node is a non-empty directory
		{
		TRomNode* dir = iChild; // find where to link in the new node
		while (dir->iSibling)
			dir = dir->iSibling;
		dir->iSibling = aChild;
		}
	else
		iChild = aChild; // else just set it up as the child of the dir
	aChild->iSibling = 0;
	aChild->iParent = this;
	}

void TRomNode::Remove(TRomNode* aChild)
	{
	if (iChild==0)
		{
		Print(EError, "Removing file from a file!!!\n");
		return;
		}
	if (iChild==aChild) // first child in this directory
		{
		iChild = aChild->iSibling;
		aChild->iSibling = 0;
		aChild->iParent = 0;
		return;
		}
	TRomNode* prev = iChild;
	while (prev->iSibling && prev->iSibling != aChild)
		prev = prev->iSibling;
	if (prev==0)
		{
		Print(EError, "Attempting to remove file not in this directory!!!\n");
		return;
		}
	prev->iSibling = aChild->iSibling;
	aChild->iSibling = 0;
	aChild->iParent = 0;
	}

void TRomNode::CountDirectory(TInt& aFileCount, TInt& aDirCount)
	{
	TRomNode *current=iChild;
	while(current)
		{
		if (current->iChild)
			aDirCount++;
		else if (!current->iHidden)
			aFileCount++;
		current=current->iSibling;
		}
	}

/**
 * Walk the contents of the directory, accumulating the
 * files as FileEntry objects in the specified RomFileStructure
 * and recursively handling the sub-directories
 *
 * TRomNode::ProcessDirectory is a pair with
 * RomFileStructure::ProcessDirectory
 */
int TRomNode::ProcessDirectory(RomFileStructure* aRFS)
	{
	TInt r=KErrNone;
	TRomNode *current=iChild;
	while(current)
		{
		if (current->iAtt & (TUint8)KEntryAttDir)
			{
			r=aRFS->ProcessDirectory(current);
			if (r!=KErrNone)
				return r;
			}
		else if (!current->iHidden)
			{
			FileEntry *pE=FileEntry::New(current);
			if (!pE)
				return KErrNoMemory;
			r=aRFS->Add(*pE);
			if (r==KErrOverflow)
				return r;
			}
		current=current->iSibling;
		}
	return r;
	}

void TRomNode::AddExecutableFile(TRomNode*& aLast, TRomNode* aNode)
	{
	aLast->iNextExecutable = aNode;
	aLast = aNode;
	aNode->iAtt |= KEntryAttXIP;
	}

char* TRomNode::BareName() const
	{
	return iBareName;
	}

TUint32 TRomNode::Uid3() const
	{
	return iRomFile->Uid3();
	}

TUint32 TRomNode::ModuleVersion() const
	{
	return iRomFile->ModuleVersion();
	}

THardwareVariant TRomNode::HardwareVariant() const
	{
	return iRomFile->HardwareVariant();
	}

TUint32 TRomNode::ABI() const
	{
	return iRomFile->ABI();
	}

TUint32 TRomFile::Uid3() const
	{
	assert(!iDir);
	if (iRbEntry)
	{
		if(iRbEntry->iHdr)
			return iRbEntry->iHdr->iUid3;
	}
	return RomImgHdr()->iUid3;
	}

TUint32 TRomFile::ModuleVersion() const
	{
	assert(!iDir);
	if (iRbEntry)
	{
		if(iRbEntry->iHdr)
			return iRbEntry->iHdr->ModuleVersion();
	}
	return RomImgHdr()->iModuleVersion;
	}

THardwareVariant TRomFile::HardwareVariant() const
	{
	return iHwvd;
	}

TUint32 TRomFile::ABI() const
	{
	assert(!iDir);
	if (iRbEntry)
	{
		if(iRbEntry->iHdr)
			return iRbEntry->iHdr->ABI();
	}
	return RomImgHdr()->iFlags & KRomImageABIMask;
	}

TInt TRomFile::ExportDirCount() const
	{
	assert(!iDir);
	if (iRbEntry)
	{
		if(iRbEntry->iHdr)
			return iRbEntry->iHdr->iExportDirCount;
	}
	return RomImgHdr()->iExportDirCount;
	}

TUint32 TRomFile::RomImageFlags() const
	{
	assert(!iDir);
	if (iRbEntry)
		{
		if(iRbEntry->iHdr)
		{
		const TUint KRomFlagMask = KImageDll | KImageNoCallEntryPoint | KImageFixedAddressExe | KImageNmdExpData;
		TUint romflags = iRbEntry->iHdr->iFlags & KRomFlagMask;
		return iRbEntry->iRomImageFlags | romflags;
		}
		}
	return RomImgHdr()->iFlags;
	}

TLinAddr TRomFile::DataBssLinearBase() const
	{
	assert(!iDir);
	if (iRbEntry)
		return iRbEntry->iDataBssLinearBase;
	return RomImgHdr()->iDataBssLinearBase;
	}

const SSecurityInfo& TRomFile::SecurityInfo() const
	{
	assert(!iDir);
	if (iRbEntry)
		return iRbEntry->iS;
	return RomImgHdr()->iS;
	}

TInt TRomNode::FullNameLength(TBool aIgnoreHiddenAttrib) const
	{
	TInt l = 0;
	// aIgnoreHiddenAttrib is used to find the complete file name length as
	// in ROM of a hidden file.
	if (iParent && ( !iHidden || aIgnoreHiddenAttrib))
		l = iParent->FullNameLength() + 1;
	l += strlen((const char*)iName);
	return l;
	}

TInt TRomNode::GetFullName(char* aBuf, TBool aIgnoreHiddenAttrib) const
	{
	TInt l = 0;
	TInt nl = strlen((const char*)iName);
	// aIgnoreHiddenAttrib is used to find the complete file name as in ROM of a hidden file.
	if (iParent && ( !iHidden || aIgnoreHiddenAttrib))
		l = iParent->GetFullName(aBuf);
	char* b = aBuf + l;
	if (l)
		*b++ = '\\', ++l;
	memcpy(b, iName, nl);
	b += nl;
	*b = 0;
	l += nl;
	return l;
	}

TInt CompareCapabilities(const SCapabilitySet& aSubCaps, const SCapabilitySet& aSuperCaps, const char* aSubName, const char* aSuperName)
//
//	Check that a aSubCaps are a subset of aSuperCaps
//
	{
	if ((!gPlatSecEnforcement)&&(!gPlatSecDiagnostics))
		return KErrNone;
	TInt i;
	TUint32 c = 0;
	for (i=0; i<SCapabilitySet::ENCapW; ++i)
		c |= (aSubCaps[i] &~ aSuperCaps[i]);
	TInt r = c ? KErrPermissionDenied : KErrNone;
	if (r && aSubName && aSuperName)
		{
		TPrintType printType;
		if(gPlatSecEnforcement)
			printType = EError;
		else
			{
			printType = EWarning;
			r = KErrNone;
			}
		char* buf = (char*)malloc(2);
		if(!buf)
			return KErrNoMemory;
		TInt len = 0;
		for(i=0; i<ECapability_Limit; i++)
			{
			if( (aSubCaps[i>>5] &~ aSuperCaps[i>>5]) & (1<<(i&31)) )
				{
				// append capability name to buf
				const char* name = CapabilityNames[i];
				if(!name)
					continue;
				if(len)
					{
					buf[len++] = ' ';
					}
				int nameLen=strlen(name);
				buf = (char*)realloc(buf,len+nameLen+2);
				if(!buf)
					return KErrNoMemory;
				memcpy(buf+len,CapabilityNames[i],nameLen);
				len += nameLen;
				}
			}
		buf[len]=0;
		Print(printType, "*PlatSec* %s - Capability check failed. Can't load %s because it links to %s which has the following capabilities missing: %s\n",gPlatSecEnforcement?"ERROR":"WARNING",aSubName, aSuperName, buf);
		free(buf);
		}
	return r;
	}

TDllFindInfo::TDllFindInfo(const char* aImportName, const TRomBuilderEntry* aEntry)
	{
	TUint32 flags;
	iBareName = SplitFileName(aImportName, iUid3, iModuleVersion, flags);
	assert(iBareName != 0);
	iHwVariant = aEntry->iHardwareVariant.ReturnVariant(); 
	}

TDllFindInfo::~TDllFindInfo()
	{
	free((void*)iBareName);
	}

// Generate name as follows:
// PC filename (UID3:xxxxxxxx HWVD:xxxxxxxx VER:M.m)
TModuleName::TModuleName(const TRomBuilderEntry* a)
	{
	TInt l = strlen(a->iFileName) + strlen(" (UID3:xxxxxxxx HWVD:xxxxxxxx VER:MMMMM.mmmmm)");
	iName = (char*)malloc(l + 1);
	assert(iName != 0);
	sprintf(iName, "%s (UID3:%08lx HWVD:%08lx VER:%ld.%ld)", a->iFileName, a->iHdr->iUid3,
		a->iHardwareVariant.ReturnVariant(), a->iHdr->ModuleVersion()>>16, a->iHdr->ModuleVersion()&0x0000ffffu);
	}

// Generate name as follows:
// Bare name (UID3:xxxxxxxx HWVD:xxxxxxxx VER:M.m)
TModuleName::TModuleName(const TDllFindInfo& a)
	{
	TInt l = strlen(a.iBareName) + strlen(" (UID3:xxxxxxxx HWVD:xxxxxxxx VER:MMMMM.mmmmm)");
	iName = (char*)malloc(l + 1);
	assert(iName != 0);
	sprintf(iName, "%s (UID3:%08lx HWVD:%08lx VER:%ld.%ld)", a.iBareName, a.iUid3,
		a.iHwVariant, a.iModuleVersion>>16, a.iModuleVersion&0x0000ffffu);
	}

// Generate name as follows:
// Name (UID3:xxxxxxxx HWVD:xxxxxxxx VER:M.m)
TModuleName::TModuleName(const TRomNode& a)
	{
	TBool xip = (a.iAtt & KEntryAttXIP);
	TUint32 uid3 = xip ? a.Uid3() : 0;
	TUint32 hwvd = (TUint)a.HardwareVariant();
	TUint32 ver = xip ? a.ModuleVersion() : 0;
	TInt l = a.FullNameLength() + strlen(" (UID3:xxxxxxxx HWVD:xxxxxxxx VER:MMMMM.mmmmm)");
	iName = (char*)malloc(l + 1);
	assert(iName != 0);
	char* b = iName + a.GetFullName(iName);
	sprintf(b, " (UID3:%08lx HWVD:%08lx VER:%ld.%ld)", uid3, hwvd, ver>>16, ver&0x0000ffffu);
	}

TModuleName::TModuleName(const TRomFile& a, const TRomNode* aRootDir)
	{
	iName = 0;
	if (a.iRbEntry)
		{
		new (this) TModuleName(a.iRbEntry);
		return;
		}
	TRomNode* x = aRootDir->iNextExecutable;
	for(; x; x=x->iNextExecutable)
		{
		if (x->iRomFile == &a)
			{
			new (this) TModuleName(*x);
			return;
			}
		}
	}

TModuleName::~TModuleName()
	{
	free(iName);
	}


/**
 * TRomNode::FindImageFileByName is always called on the root TRomNode, so
 * it doesn't consider the current TRomNode, just the linked items in the
 * iNextExecutable list.
 */
TRomNode* TRomNode::FindImageFileByName(const TDllFindInfo& aInfo, TBool aPrintDiag, TBool& aFallBack)
	{
	TUint r_major = aInfo.iModuleVersion >> 16;
	TUint r_minor = aInfo.iModuleVersion & 0x0000ffffu;
	TRomNode* fallback = NULL;
	aFallBack = EFalse;
	for (TRomNode* x=iNextExecutable; x!=0; x=x->iNextExecutable)
		{
		if (stricmp(x->BareName(), aInfo.iBareName))
			continue;	// name doesn't match
		if (aPrintDiag)
			Print(ELog, "Candidate: %s ", (const char*)TModuleName(*x) );
		if ( !(THardwareVariant(aInfo.iHwVariant) <= x->HardwareVariant()) )
			{
			if (aPrintDiag)
				Print(ELog, "HWVD mismatch - requested %08x\n", aInfo.iHwVariant);
			continue;
			}
		if (aInfo.iUid3 && (aInfo.iUid3 != x->Uid3()))
			{
			if (aPrintDiag)
				Print(ELog, "UID3 mismatch - requested %08x\n", aInfo.iUid3);
			continue;
			}
		TUint x_major = x->ModuleVersion() >> 16;
		TUint x_minor = x->ModuleVersion() & 0x0000ffffu;
		if ( x->ModuleVersion() == 0x00010000 && aInfo.iModuleVersion == 0 )
			{
			// allow requested version 0.0 to link to 1.0 with a warning
			fallback = x;
			}
		if ( x_major != r_major )
			{
			if (aPrintDiag)
				Print(ELog, "Major version mismatch - requested %d\n", r_major);
			continue;
			}
		if ( x_minor < r_minor )
			{
			if (aPrintDiag)
				Print(ELog, "??? Minor version mismatch - requested %d\n", r_minor);
			continue;
			}
		if (aPrintDiag)
			Print(ELog, "OK\n");
		return x;
		}
	if (fallback)
		{
		aFallBack = ETrue;
		return fallback;
		}
	return 0;
	}

TInt TRomNode::CheckForVersionConflicts(const TRomBuilderEntry* a)
	{
	TUint r_major = a->iHdr->ModuleVersion() >> 16;
	TUint r_minor = a->iHdr->ModuleVersion() & 0x0000ffffu;
	TInt errors = 0;
	for (TRomNode* x=iNextExecutable; x!=0; x=x->iNextExecutable)
		{
		if (x->iRomFile->iRbEntry == a)
			continue;	// don't compare a with itself
		if (stricmp(x->BareName(), a->iBareName))
			continue;	// name doesn't match
		if ( a->iHardwareVariant.MutuallyExclusive(x->HardwareVariant()) )
			continue;	// HWVDs are mutually exclusive
		if ( a->iHdr->iUid3 && x->Uid3() && (a->iHdr->iUid3 != x->Uid3()) )
			continue;	// UID3's don't match
		TUint x_major = x->ModuleVersion() >> 16;
		TUint x_minor = x->ModuleVersion() & 0x0000ffffu;
		if (x_major == r_major && x_minor != r_minor)	// allow two copies of same file
			{
			Print(EError, "Version Conflict %s with %s\n", (const char*)TModuleName(a), (const char*)TModuleName(*x) );
			++errors;
			}
		}
	return errors;
	}

TInt E32Rom::WriteHeadersToRom(char *anAddr)
//
// Follow the TRomBuilderEntry tree, writing TRomEntry headers to the rom.
//
	{
	TRACE(TTIMING,Print(EAlways,"0\n"));
	TRACE(TDIR,Print(EAlways,"WriteHeadersToRom()\n"));
	char* start=anAddr;
	TRomRootDirectoryList* dirPointers=(TRomRootDirectoryList*)anAddr;
	anAddr+=NumberOfVariants*sizeof(TRootDirInfo)+sizeof(TInt);
	RomFileStructure* pS=RomFileStructure::New(NumberOfVariants);
	if (!pS)
		Print(EError,"Error creating RomFileStructure\n");
	TInt r=pS->ProcessDirectory(iObey->iRootDirectory);
	if (r!=KErrNone)
		Print(EError,"Error %d processing directory tree\n",r);
	TInt c=pS->Count();
	NumRootDirs=c;
	if (c!=NumberOfVariants)
		Print(EError,"Error processing directory tree NR=%d NV=%d\n",c,NumberOfVariants);
	dirPointers->iNumRootDirs=c;
	TInt i;
	TRACE(TDIR,Print(EAlways,"Count=%d\n",c));
	TRACE(TDIR,pS->DebugPrint());
	for(i=0; i<c; i++)
		{
		DirEntry* pD=(DirEntry*)&(*pS)[i];
		TRomDir* pR=pD->CreateRomEntries(anAddr);
		dirPointers->iRootDir[i].iHardwareVariant=TUint(pD->Variants().Lookup());
		dirPointers->iRootDir[i].iAddressLin=ActualToRomAddress(pR);
		}
	TRACE(TDIR,Print(EAlways,"Beginning final cleanup\n"));
	delete pS;
	TRACE(TTIMING,Print(EAlways,"1\n"));
	return anAddr-start;
	}

 void TRomNode::Destroy()
//
// Follow the TRomNode tree, destroying it
//
	{

 	TRomNode *current = this; // root has no siblings
	while (current)
		{
		if (current->iChild)
			current->iChild->Destroy();
		TRomNode* prev=current;
		current=current->iSibling;
		delete prev;
		}
 	}


TInt TRomNode::SetAtt(TText *anAttWord)
//
// Set the file attribute byte from the letters passed
//
	{
	iAtt=0;
	if (anAttWord==0 || anAttWord[0]=='\0')
		return Print(EError, "Missing argument for keyword 'attrib'.\n");
	for (TText *letter=anAttWord;*letter!=0;letter++)
		{
		switch (*letter)
			{
		case 'R':
		case 'w':
			iAtt |= KEntryAttReadOnly;
			break;
		case 'r':
		case 'W':
			iAtt &= ~KEntryAttReadOnly;
			break;
		case 'H':
			iAtt |= KEntryAttHidden;
			break;
		case 'h':
			iAtt &= ~KEntryAttHidden;
			break;
		case 'S':
			iAtt |= KEntryAttSystem;
			break;
		case 's':
			iAtt &= ~KEntryAttSystem;
			break;
		default:
			return Print(EError, "Unrecognised attrib - '%c'.\n", *letter);
			break;
			}
		}
	return KErrNone;
	}

TRomBuilderEntry::TRomBuilderEntry(const char *aFileName,TText *aName)
//
// Constructor
//
	:
	E32ImageFile(),
	iName(0),
	iResource(EFalse), iNonXIP(EFalse), iPreferred(EFalse), iCompression(0), iPatched(EFalse),iArea(0),
	iOverrideFlags(0),iCodeAlignment(0),iDataAlignment(0),iUid1(0), iUid2(0), iUid3(0),iBareName(0), 
	iHardwareVariant(KVariantIndependent),iDataBssOffset(0xffffffff), 
	iStackReserve(0),iIATRefs(0), iNext(0), iNextInArea(0), 
	iRomImageFlags(0),iProcessName(0), iRomNode(NULL)
	{
	if (aFileName)
   		iFileName = NormaliseFileName((const char*)aFileName);
	if (aName)
		iName = (TText*)NormaliseFileName((const char*)aName);
	}

TRomBuilderEntry::~TRomBuilderEntry()
//
// Destructor
//
	{

	free(iFileName);
	iFileName = 0;
	free(iName);
	iName = 0;
	delete[] iProcessName;
	free(iBareName);
	iBareName = 0;
	delete[] iIATRefs;
	}

TInt isNumber(TText *aString)
	{
	if (aString==NULL)
		return 0;
	if (strlen((char *)aString)==0)
		return 0;
	return isdigit(aString[0]);
	}

TInt getNumber(TText *aStr)
	{
	TUint a;
	#ifdef __TOOLS2__
	istringstream val((char *)aStr);
	#else
	istrstream val((char *)aStr,strlen((char *)aStr));
	#endif

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

	val >> a;
	return a;
	}

TInt TRomBuilderEntry::SetCodeAlignment(TText* aStr)
	{
    if (!aStr || (aStr && isNumber(aStr)==0))
		return Print(EError, "Number required as argument for keyword 'code-align'.\n");
    iCodeAlignment=getNumber(aStr);
    return KErrNone;
	}

TInt TRomBuilderEntry::SetDataAlignment(TText* aStr)
	{
    if (!isNumber(aStr))
		return Print(EError, "Number required as argument for keyword 'data-align'.\n");
    TInt align=getNumber(aStr);
	if (align<0 || (align&0x0F) != 0)
		return Print(EError, "Positive multiple of 16 required for 'data-align'.\n");
	iDataAlignment=align;
    return KErrNone;
	}

TInt TRomBuilderEntry::SetRelocationAddress(TText *aStr)
	{
	if (aStr && isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'reloc'.\n");
	iOverrideFlags |= KOverrideAddress;
	iRelocationAddress=aStr ? getNumber(aStr) : 0xFFFFFFFF;
	return KErrNone;
	}

TInt TRomBuilderEntry::SetStackReserve(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'stackreserve'.\n");
	iOverrideFlags |= KOverrideStackReserve;
	iStackReserve=getNumber(aStr);
	return KErrNone;
	}

TInt TRomBuilderEntry::SetStackSize(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'stack'.\n");
	iOverrideFlags |= KOverrideStack;
	iStackSize=getNumber(aStr);
	return KErrNone;
	}

TInt TRomBuilderEntry::SetHeapSizeMin(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'heapmin'.\n");
	iOverrideFlags |= KOverrideHeapMin;
	iHeapSizeMin=getNumber(aStr);
	return KErrNone;
	}

TInt TRomBuilderEntry::SetHeapSizeMax(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'heapmax'.\n");
	iOverrideFlags |= KOverrideHeapMax;
	iHeapSizeMax=getNumber(aStr);
	return KErrNone;
	}

TInt TRomBuilderEntry::SetCapability(TText *aStr)
	{
	iOverrideFlags |= KOverrideCapability;
	if (isNumber(aStr))
		{
		Print(EDiagnostic,"Old style numeric CAPABILTY specification ignored.\n");
		return KErrNone;
		}
	return ParseCapabilitiesArg(iS.iCaps, (char*)aStr);
	}

TInt TRomBuilderEntry::SetPriority(TText *aStr)
	{
	if (isNumber(aStr))
		iPriority=(TProcessPriority)getNumber(aStr);
	else
		{
		char *str=(char *)aStr;
		if (stricmp(str, "low")==0)
			iPriority=EPriorityLow;
		else if (strnicmp(str, "background", 4)==0)
			iPriority=EPriorityBackground;
		else if (strnicmp(str, "foreground", 4)==0)
			iPriority=EPriorityForeground;
		else if (stricmp(str, "high")==0)
			iPriority=EPriorityHigh;
		else if (strnicmp(str, "windowserver",3)==0)
			iPriority=EPriorityWindowServer;
		else if (strnicmp(str, "fileserver",4)==0)
			iPriority=EPriorityFileServer;
		else if (strnicmp(str, "realtimeserver",4)==0)
			iPriority=EPriorityRealTimeServer;
		else if (strnicmp(str, "supervisor",3)==0)
			iPriority=EPrioritySupervisor;
		else
			return Print(EError, "Unrecognised priority keyword.\n");
		}
	if (iPriority<EPriorityLow || iPriority>EPrioritySupervisor)
		return Print(EError, "Priority out of range.\n");
	iOverrideFlags |= KOverridePriority;
	return KErrNone;
	}

TInt TRomBuilderEntry::SetUid1(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'uid1'.\n");
	iOverrideFlags |= KOverrideUid1;
	iUid1=getNumber(aStr);
	return KErrNone;
	}
TInt TRomBuilderEntry::SetUid2(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'uid2'.\n");
	iOverrideFlags |= KOverrideUid2;
	iUid2=getNumber(aStr);
	return KErrNone;
	}
TInt TRomBuilderEntry::SetUid3(TText *aStr)
	{
	if (isNumber(aStr)==0)
		return Print(EError, "Number required as argument for keyword 'uid3'.\n");
	iOverrideFlags |= KOverrideUid3;
	iUid3=getNumber(aStr);
	return KErrNone;
	}
TInt TRomBuilderEntry::SetCallEntryPoint(TBool aState)
	{
	if (aState)
		iOverrideFlags|=KOverrideCallEntryPoint;
	else
		iOverrideFlags|=KOverrideNoCallEntryPoint;
	return KErrNone;
	}

TInt TRomBuilderEntry::SetAttachProcess(TText *aStr)
	{
	const char* s=(const char*)aStr;
	TInt nd=0;
	if (*s=='\\')
		{
		++s;
		++nd;
		}
	TInt l=strlen(s);
	if (l==0)
		return KErrGeneral;
	const char* ss=s;
	while(*ss!=0 && *ss!='.') ++ss;
	int ext=*ss;	// 0 if no extension
	iProcessName=new TText[l+2+(ext?0:4)];
	char* d=(char *)iProcessName;
	strcpy(d+1, s);
	if (!ext)
		{
		char* t=d+1+l;
		*t++='.';
		*t++='e';
		*t++='x';
		*t++='e';
		*t++=0;
		}
	char* dd=d;
	int ind=nd;
	while(*dd)
		{
		while(*dd && *dd!='\\') ++dd;
		if (*dd=='\\')
			{
			*dd++=0;	// change \ to NUL
			++nd;		// count path elements
			}
		}
	if (!ind && nd)
		++nd;			// add initial \ if not present
	*d=(char)nd;
	return 0;
	}

TInt TRomBuilderEntry::OpenImageFile()
	{
	Print(ELog,"Loading E32Image file %s \n", iFileName);
	TInt err = Open(iFileName);
	if (err != KErrNone)
		{
		Print(EError,"File %s is not a valid E32Image file (error %d)\n", iFileName, err);
		return err;
		}
	TUint hdrfmt = iHdr->HeaderFormat();
	if (hdrfmt != KImageHdrFmt_V)
		{
		Print(EError,"%s: Can't load old format binary\n", iFileName);
		return KErrNotSupported;
		}
	E32ImageHeaderV* h = iHdr;
	
	// Overide any settings in the image file with those in the obey file
	if (iOverrideFlags & (KOverrideUid1|KOverrideUid2|KOverrideUid3))
		{
		TUint uid1 = h->iUid1;
		TUint uid2 = h->iUid2;
		TUint uid3 = h->iUid3;
		if (iOverrideFlags & KOverrideUid1)
			uid1 = iUid1;
		if (iOverrideFlags & KOverrideUid2)
			uid2 = iUid2;
		if (iOverrideFlags & KOverrideUid3)
			uid3 = iUid3;
		SetUids(TUid::Uid(uid1), TUid::Uid(uid2), TUid::Uid(uid3));
		}
	if (iOverrideFlags & KOverrideStack)
		h->iStackSize = iStackSize;
	if (iOverrideFlags & KOverrideHeapMax)
		h->iHeapSizeMax = iHeapSizeMax;
	if (iOverrideFlags & KOverrideHeapMin)
		h->iHeapSizeMin = iHeapSizeMin;
	if (iOverrideFlags & KOverridePriority)
		h->iProcessPriority = (TUint16)iPriority;
	if (iOverrideFlags & KOverrideCapability)
		h->iS.iCaps = iS.iCaps;
	for (TInt i=0; i<SCapabilitySet::ENCapW; ++i)
		{
		h->iS.iCaps[i] |= gPlatSecDisabledCaps[i];
		h->iS.iCaps[i] &= gPlatSecAllCaps[i];
		}

	if (iOverrideFlags & KOverrideCodePaged)
		{
		h->iFlags &= ~KImageCodeUnpaged;
		h->iFlags |= KImageCodePaged;
		}
	if (iOverrideFlags & KOverrideCodeUnpaged)
		{
		h->iFlags |= KImageCodeUnpaged;
		h->iFlags &= ~KImageCodePaged;
		}

	if ((TInt)h->iUid1 == KExecutableImageUidValue)
		{
		if (iOverrideFlags & KOverrideDataPaged)
			{
			h->iFlags &= ~KImageDataUnpaged;
			h->iFlags |= KImageDataPaged;
			}
		if (iOverrideFlags & KOverrideDataUnpaged)
			{
			h->iFlags |= KImageDataUnpaged;
			h->iFlags &= ~KImageDataPaged;
			}
		}

	switch(gCodePagingOverride)
		{
	case EKernelConfigPagingPolicyNoPaging:
		h->iFlags |= KImageCodeUnpaged;
		h->iFlags &= ~KImageCodePaged;
		break;
	case EKernelConfigPagingPolicyAlwaysPage:
		h->iFlags |= KImageCodePaged;
		h->iFlags &= ~KImageCodeUnpaged;
		break;
	case EKernelConfigPagingPolicyDefaultUnpaged:
		if(!(h->iFlags&(KImageCodeUnpaged|KImageCodePaged)))
			h->iFlags |= KImageCodeUnpaged;
		break;
	case EKernelConfigPagingPolicyDefaultPaged:
		if(!(h->iFlags&(KImageCodeUnpaged|KImageCodePaged)))
			h->iFlags |= KImageCodePaged;
		break;
		}
	switch(gDataPagingOverride)
		{
	case EKernelConfigPagingPolicyNoPaging:
		h->iFlags |= KImageDataUnpaged;
		h->iFlags &= ~KImageDataPaged;
		break;
	case EKernelConfigPagingPolicyAlwaysPage:
		h->iFlags |= KImageDataPaged;
		h->iFlags &= ~KImageDataUnpaged;
		break;
	case EKernelConfigPagingPolicyDefaultUnpaged:
		if(!(h->iFlags&(KImageDataUnpaged|KImageDataPaged)))
			h->iFlags |= KImageDataUnpaged;
		break;
	case EKernelConfigPagingPolicyDefaultPaged:
		if(!(h->iFlags&(KImageDataUnpaged|KImageDataPaged)))
			h->iFlags |= KImageDataPaged;
		break;
		}
	
	h->iCompressionType=KUidCompressionDeflate; // XIP images are always uncompressed
	
	Print(ELog,"\t\tcompression format:0x%08x \n", h->iCompressionType);
	if (gLogLevel & LOG_LEVEL_COMPRESSION_INFO)
		Print(ELog,"\t\tgCompress:%d, gCompressionMethod: 0x%08x \n", gEnableCompress , gCompressionMethod);


	// Check the uids

	if ((TInt)h->iUid1 != KExecutableImageUidValue && (TInt)h->iUid1 != KDynamicLibraryUidValue) 
		return Print(EError, "First Uid for %s is not KExecutableImageUid or KDynamicLibraryUid\n", iFileName);

	// Set up the sizes and location of the distinct areas

	iHeaderRange.iSize = sizeof(TRomImageHeader);

	iCodeSection.iSize    = h->iTextSize;
	iCodeSection.iFilePtr = iData + iOrigHdr->iCodeOffset;

	TUint impfmt = h->ImportFormat();

	if (impfmt==KImageImpFmt_PE || impfmt==KImageImpFmt_PE2)
		{
		TInt nimports = NumberOfImports();
		if (nimports)
			{
			iImportAddressTableSection.iSize    = (nimports+1)*4;
			iImportAddressTableSection.iFilePtr = iData + iOrigHdr->iCodeOffset + iOrigHdr->iTextSize;
			iIATRefs = new TLinAddr*[nimports+1];
			memcpy(iIATRefs, iImportAddressTableSection.iFilePtr, (nimports+1)*sizeof(TLinAddr*));
			}

		if (h->iExportDirCount)
			{
			iExportDirSection.iSize    = h->iExportDirCount*4;
			iExportDirSection.iFilePtr = iData + iOrigHdr->iExportDirOffset;
			}

		// assertion - there's no rdata between IAT and Export Directory
		TInt rdatasize = h->iCodeSize;		// overall "readonly" size
		rdatasize -= iCodeSection.iSize;				// text
		rdatasize -= iImportAddressTableSection.iSize;	// IAT plus trailing 0
		rdatasize -= iExportDirSection.iSize;			// export data

		if (rdatasize != 0)
			{
			Print(EWarning, "Unexpected code in %s: %d bytes unexplained\n", iFileName, rdatasize);
			// expand the code to cover text+IAT+rdata
			iCodeSection.iSize = h->iCodeSize - iExportDirSection.iSize;
			}
		else
			{
			if (USE_IAT_FOR_IMPORTS)
				iCodeSection.iSize += iImportAddressTableSection.iSize;	// include IAT
			}
		}
	else
		{
		// ELF-derived images have no IAT and the export directory is included in the code section
		iImportAddressTableSection.iSize    = 0;
		iImportAddressTableSection.iFilePtr = NULL;
		iExportDirSection.iSize    = 0;
		iExportDirSection.iFilePtr = NULL;
		}

	if (h->iDataSize)
		{
		iDataSection.iSize    = h->iDataSize;
		iDataSection.iFilePtr = iData + iOrigHdr->iDataOffset;
		}

	iRomNode->iRomFile->iTotalDataBss = h->iDataSize + h->iBssSize;
	iS = h->iS;
	if (iVersionPresentInName && iVersionInName != h->ModuleVersion())
		{
		Print(EError,"%s: Version in name (%d.%d) does not match version in header (%d.%d)\n", iFileName,
			iVersionInName>>16, iVersionInName&0x0000ffffu, h->ModuleVersion()>>16, h->ModuleVersion()&0x0000ffffu);
		return KErrGeneral;
		}
	return KErrNone;
	}

TInt TRomNode::NameCpy(char* aDest)
//
// Safely copy a file name in the rom entry
//
	{

	if ((aDest==NULL) || (iName==NULL))
		return 0;
	if (Unicode)
		{
		const unsigned char* pSourceByte=iName;
		unsigned char* pTargetByte=(unsigned char*)aDest;
		for (;;)
			{
			const TUint sourceByte=*pSourceByte;
			if (sourceByte==0)
				{
				*pTargetByte=0;
				*(pTargetByte+1)=0;
				break;
				}
			if ((sourceByte&0x80)==0)
				{
				*pTargetByte=(unsigned char)sourceByte;
				++pTargetByte;
				*pTargetByte=0;
				++pTargetByte;
				++pSourceByte;
				}
			else if ((sourceByte&0xe0)==0xc0)
				{
				++pSourceByte;
				const TUint secondSourceByte=*pSourceByte;
				if ((secondSourceByte&0xc0)!=0x80)
					{
					Print(EError, "Bad UTF-8 '%s'", iName);
					exit(671);
					}
				*pTargetByte=(unsigned char)((secondSourceByte&0x3f)|((sourceByte&0x03)<<6));
				++pTargetByte;
				*pTargetByte=(unsigned char)((sourceByte>>2)&0x07);
				++pTargetByte;
				++pSourceByte;
				}
			else if ((sourceByte&0xf0)==0xe0)
				{
				++pSourceByte;
				const TUint secondSourceByte=*pSourceByte;
				if ((secondSourceByte&0xc0)!=0x80)
					{
					Print(EError, "Bad UTF-8 '%s'", iName);
					exit(672);
					}
				++pSourceByte;
				const TUint thirdSourceByte=*pSourceByte;
				if ((thirdSourceByte&0xc0)!=0x80)
					{
					Print(EError, "Bad UTF-8 '%s'", iName);
					exit(673);
					}
				*pTargetByte=(unsigned char)((thirdSourceByte&0x3f)|((secondSourceByte&0x03)<<6));
				++pTargetByte;
				*pTargetByte=(unsigned char)(((secondSourceByte>>2)&0x0f)|((sourceByte&0x0f)<<4));
				++pTargetByte;
				++pSourceByte;
				}
			else
				{
				Print(EError, "Bad UTF-8 '%s'", iName);
				exit(674);
				}
			}
		const TInt numberOfBytesInTarget=(pTargetByte-(unsigned char*)aDest); // this number excludes the trailing null-terminator
		if (numberOfBytesInTarget%2!=0)
			{
			Print(EError, "Internal error");
			exit(675);
			}
		return numberOfBytesInTarget/2; // returns the length of aDest (in UTF-16 characters for Unicode, not bytes)
		}
	strcpy(aDest,(const char*)iName);
	return strlen((const char*)iName);
	}

TInt TRomBuilderEntry::SizeInRom()
//
// Approximate the required size of the file when rommed
//
	{

	TInt size1, size2;
	SizeInSections(size1,size2);
	return size1+size2;
	}

void TRomBuilderEntry::LoadToRom()
//
//
//
	{
	// Copy fixed stuff into iRomImageHeader
	E32ImageHeaderV* h = iHdr;
	const TUint KRomFlagMask = KImageDll | KImageNoCallEntryPoint | KImageFixedAddressExe | KImageNmdExpData | KImageDataPagingMask;
	TUint romflags = h->iFlags & KRomFlagMask;
	TUint abi = h->ABI();
	TUint ept = h->EntryPointFormat();
	TUint impfmt = h->ImportFormat();
	romflags |= (abi | ept);

	iRomImageHeader = (TRomImageHeader*)iHeaderRange.iImagePtr;

	iRomImageHeader->iUid1              = h->iUid1;
	iRomImageHeader->iUid2              = h->iUid2;
	iRomImageHeader->iUid3              = h->iUid3;
	iRomImageHeader->iUidChecksum       = h->iUidChecksum;
	iRomImageHeader->iEntryPoint        = iCodeSection.iRunAddr + h->iEntryPoint;
	iRomImageHeader->iCodeAddress       = iCodeSection.iRunAddr;
	iRomImageHeader->iDataAddress       = iDataSection.iRunAddr;
	iRomImageHeader->iCodeSize          = iCodeSection.iSize+iExportDirSection.iSize;
	iRomImageHeader->iTextSize          = iCodeSection.iSize;
	iRomImageHeader->iDataSize          = iDataSection.iSize;
	iRomImageHeader->iBssSize           = h->iBssSize;
	iRomImageHeader->iTotalDataSize		= iRomNode->iRomFile->iTotalDataBss;
	iRomImageHeader->iHeapSizeMin       = h->iHeapSizeMin;
	iRomImageHeader->iHeapSizeMax       = h->iHeapSizeMax;
	iRomImageHeader->iStackSize         = h->iStackSize;
	iRomImageHeader->iDllRefTable       = (TDllRefTable*)(iDllRefTableRange.iImageAddr);
	iRomImageHeader->iExportDirCount    = h->iExportDirCount;
	iRomImageHeader->iExportDir         = (impfmt==KImageImpFmt_ELF) ?
											iCodeSection.iRunAddr + (h->iExportDirOffset - h->iCodeOffset)
											: iExportDirSection.iRunAddr;
	iRomImageHeader->iS					= h->iS;
	iRomImageHeader->iToolsVersion		= h->iToolsVersion;
	iRomImageHeader->iModuleVersion		= h->ModuleVersion();
	iRomImageHeader->iFlags             = romflags | iRomImageFlags;
	iRomImageHeader->iPriority          = h->ProcessPriority();
	iRomImageHeader->iDataBssLinearBase = iDataBssLinearBase;
	iRomImageHeader->iNextExtension     = 0;
	iRomImageHeader->iHardwareVariant   = iHardwareVariant;
	iRomImageHeader->iExceptionDescriptor = 0;
	TUint32 xd = h->iExceptionDescriptor;
	if ((xd & 1) && (xd != 0xffffffffu))
		iRomImageHeader->iExceptionDescriptor = (xd & ~1) + iRomImageHeader->iCodeAddress;

	if (iPreferred)
		{
		iRomImageHeader->iModuleVersion	&= ~0xffffu;
		iRomImageHeader->iModuleVersion	|= 0x8000u;
		}

	// Relocate the file to reflect the new addresses
	Relocate();

	// Copy the sections
	iCodeSection.Load();
	iExportDirSection.Load();
	iDataSection.Load();
	}

void TRomBuilderEntry::Relocate()
//
// Relocates the iData to new Code and Data addresses
//	
	{
	TUint codeDelta=iRomImageHeader->iCodeAddress       - iHdr->iCodeBase;
	TUint dataDelta=iRomImageHeader->iDataBssLinearBase - iHdr->iDataBase;

	// code section (text, IAT, export directory)

	if (iOrigHdr->iCodeRelocOffset)
		RelocateSection(iData + iOrigHdr->iCodeOffset, iData + iOrigHdr->iCodeRelocOffset,
			codeDelta, dataDelta, (char*)iCodeSection.iImagePtr, iIATRefs);

	// data section 

	if (iOrigHdr->iDataRelocOffset)
		RelocateSection(iData + iOrigHdr->iDataOffset, iData + iOrigHdr->iDataRelocOffset, 
			codeDelta, dataDelta, (char*)iDataSection.iImagePtr, iIATRefs);

	// export directory (only for PE-derived files)
	if (iExportDirSection.iSize)
		{
		TLinAddr* ptr=(TLinAddr*)(iData + iOrigHdr->iExportDirOffset);

		TLinAddr textStart = iHdr->iCodeBase;
		TLinAddr textFinish = textStart + iHdr->iTextSize;
		TLinAddr dataStart = textStart + iHdr->iCodeSize;
		TLinAddr dataFinish = dataStart + iHdr->iDataSize + iHdr->iBssSize;
	 
		TInt i;
		for (i=0; i<iHdr->iExportDirCount; i++, ptr++)
			{
			TLinAddr data=*ptr+textStart;
			if ((data>=textStart) && (data<textFinish))
				*ptr=data+codeDelta; // export something from the text/rdata section
			else if ((data>=dataStart) && (data<dataFinish))
				*ptr=data+dataDelta; // export some data or bss item
			else
				{
				Print(EWarning, "Export directory in %s: item %d -> %08x, which is not text or data!\n", iFileName, i, data);
				*ptr=0x13;	// unlucky for some
				}
			}
		}

	// Replace absent exports with 0
	TLinAddr* ptr = (TLinAddr*)(iData + iOrigHdr->iExportDirOffset);
	TInt i;
	for (i=0; i<iHdr->iExportDirCount; i++, ptr++)
		{
		if ( !( iExportBitMap[i>>3] & (1u << (i&7)) ) )
			*ptr = 0;
		}

	// Update E32ImageHeader, in case we want to do this process again later

	iHdr->iCodeBase += codeDelta;
	iHdr->iDataBase += dataDelta;
	}




TInt TRomBuilderEntry::FixupImports(E32Rom& aRom)
//
// Modify the import stubs to point directly into the export directory of the corresponding DLLs
// using the back pointers captured by detecting relocations referring to the Import Address Table
// The old-style Import Address Table behaviour can be retained by specifying the "keepIAT" attribute.
//
	{
	if (iHdr->iImportOffset == 0)
		return KErrNone;	// nothing to do

	

	TUint impfmt = iHdr->ImportFormat();
	TUint my_abi = iHdr->ABI();
	TRACE(TIMPORT,Print(ELog,"%40s[%08x] flags %08x\n",iFileName,(TUint)iHardwareVariant,iHdr->iFlags));
	const E32ImportSection* importsection = (const E32ImportSection*)(iData + iOrigHdr->iImportOffset);
	TLinAddr **iatRef=iIATRefs;
	TAddressRange iatRange = iCodeSection;
	iatRange.Move(iHdr->iTextSize);
	if (USE_IAT_FOR_IMPORTS)
		{
		if (impfmt == KImageImpFmt_ELF)
			return Print(EError, "Can't retain IAT for %s since it never existed\n", iFileName);
		if (iRomSectionNumber==0 && aRom.iObey->iSectionPosition!=-1)
			return Print(EError, "Can't retain IAT for %s in first section - not yet implemented\n", iFileName);
		Print(ELog, "%s has IAT at %08x\n", iFileName, iatRange.iRunAddr);
		}
	const E32ImportBlock* b = (const E32ImportBlock*)(importsection + 1);
	TInt i = iHdr->iDllRefTableCount;
	TInt numberOfImports=0;
	TUint *impOrdinalP = (TUint*)iImportAddressTableSection.iFilePtr;	// points to original IAT in file
	while (i-->0)
		{
		char* dllname = (char*)importsection + b->iOffsetOfDllName;
		TDllFindInfo find_info(dllname, this);
		TBool fallback;
		TRomNode* romnode = aRom.FindImageFileByName(find_info, EFalse, fallback);
		if (!romnode)
			{
			Print(EError, "Can't fixup imports for\n\t%s\nbecause\n\t%s\nis not in rom.\n",
						 (const char*)TModuleName(this), (const char*)TModuleName(find_info));
			aRom.FindImageFileByName(find_info, ETrue, fallback);
			return KErrGeneral;
			}
		TRomFile* dll=romnode->iRomFile;
		TRACE(TIMPORT,Print(ELog,"%s importing from %s\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info)));
		if (romnode->ABI() != my_abi)
			{
			Print(EWarning, "File %s links to %s with different ABI\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info));
			}
		TInt j;
		numberOfImports += b->iNumberOfImports;
		if (impfmt==KImageImpFmt_ELF)
			impOrdinalP = (TUint*)(b->Imports());	// for ELF must look in import block
		char* codeBase = (char*)iCodeSection.iImagePtr;
		for (j=0; j<b->iNumberOfImports; j++)
			{
			TLinAddr exportAddr = 0xdeadbeef;
			TLinAddr exporter = 0xdeadbeef;
			TUint impOrdinal = *impOrdinalP;
			TUint impOffset = 0;
			if (impfmt==KImageImpFmt_ELF)
				{
				TUint impd = *(TUint*)(codeBase + impOrdinal);
				impOrdinal = impd & 0xffff;
				impOffset = impd >> 16;
				}
			TRACE(TIMPORT,Print(ELog,"Ordinal %d\n", impOrdinal));
			TInt ret=dll->AddressFromOrdinal(exporter, exportAddr, impOrdinal);
			TRACE(TIMPORT,Print(ELog,"export %08x exporter %08x\n",exportAddr,exporter));
			if (ret!=KErrNone)
				{
				Print(EError, "%s wants ordinal %d from %s which only exports %d functions\n",
					iFileName, impOrdinal, 	(const char*)TModuleName(find_info), dll->ExportDirCount());
				exporter=0x13;	// unlucky for some...
				exportAddr=0x13;
				}
			else if (exportAddr == 0 && impOrdinal != 0)
				{
				Print(EError, "%s wants ordinal %d from %s which is absent\n",
					iFileName, impOrdinal, 	(const char*)TModuleName(find_info));
				exporter=0x13;	// unlucky for some...
				exportAddr=0x13;
				}
			if (USE_IAT_FOR_IMPORTS)
				{
				// must be PE-derived
				*iatRef=(unsigned long*)exportAddr; //iatRange.iRunAddr;					// point into IAT ...
				*(TLinAddr*)(iatRange.iImagePtr)=exportAddr;	// ... which has a copy of the export
				iatRange.Move(sizeof(TLinAddr));
				iatRef++;
				}
			else if (impfmt==KImageImpFmt_PE || impfmt==KImageImpFmt_PE2)
				{
				**iatRef=exporter;	// point directly into export directory
				iatRef++;
				}
			else
				{
				// ELF-derived
				*(TUint*)(codeBase + *impOrdinalP) = exportAddr + impOffset;
				}
			impOrdinalP++;
			}
		b = b->NextBlock(impfmt);
		}
	iImportCount=numberOfImports;
	return KErrNone;
	}

const char* KF32ProcessName="efile.exe";
const char* KWservProcessName="ewsrv.exe";
const char* KFbservProcessName="fbserv.exe";
const char* KMdaSvrProcessName="mediaserverstub.exe";
const char* KC32ProcessName="c32exe.exe";

const char* TRomBuilderEntry::GetDefaultAttachProcess()
//
// Work out the attach process from the file extension
//
// Only need to handle DLLs which run in F32, WSERV, FBSERV, MEDIASVR, C32
// F32:		FSY FXT
// WSERV:	ANI
// FBSERV:
// MDASVR:	MDA
// C32:		CSY, PRT, TSY, AGT, AGX
//
	{
	const char* s=(const char*)iName;
	TInt l=strlen(s);
	if (l<4 || s[l-4]!='.')
		return NULL;
	s+=(l-3);
	if (stricmp(s,"fsy")==0)
		return KF32ProcessName;
	if (stricmp(s,"fxt")==0)
		return KF32ProcessName;
	if (stricmp(s,"ani")==0)
		return KWservProcessName;
	if (stricmp(s,"mda")==0)
		return KMdaSvrProcessName;
	if (stricmp(s,"csy")==0)
		return KC32ProcessName;
	if (stricmp(s,"prt")==0)
		return KC32ProcessName;
	if (stricmp(s,"tsy")==0)
		return KC32ProcessName;
	if (stricmp(s,"agt")==0)
		return KC32ProcessName;
	if (stricmp(s,"agx")==0)
		return KC32ProcessName;
	return NULL;
	}

TInt TRomBuilderEntry::FindAttachProcess(E32Rom& aRom)
	{
	if (iRomImageFlags & (KRomImageFlagVariant|KRomImageFlagExtension|KRomImageFlagDevice))
		return KErrNone;
	const char* attp_name=(const char*)iProcessName;
	int nd=0;
	if (attp_name)
		nd=*attp_name++;
	else
		attp_name=GetDefaultAttachProcess();
	if (!attp_name)
		return KErrNone;
	TInt i;
	TUint my_abi = iHdr->ABI();
	TUint abi = 0;
	if (nd)
		{
		// path search
		TRomNode* rn=aRom.iObey->iRootDirectory;
		for (; nd; --nd)
			{
			rn=rn->FindInDirectory((TText*)attp_name);
			if (!rn)
				{
				Print(EError, "Invalid attach process name element %s\n", attp_name);
				return KErrGeneral;
				}
			attp_name+=(strlen(attp_name)+1);
			}
		iRomNode->iRomFile->iAttachProcess=rn->iRomFile;
		abi = iRomNode->iRomFile->iAttachProcess->ABI();
		}
	else
		{
		// filename only search
		for (i=0; i<aRom.iObey->iNumberOfPeFiles; i++)
			{
			TRomBuilderEntry* e=aRom.iPeFiles[i];
			abi = e->iHdr->ABI();
			if (stricmp((const char*)e->iName, attp_name)==0)
				{
				if (iRomNode->iRomFile->iAttachProcess)
					{
					Print(EError, "Ambiguous attach process name %s\n", attp_name);
					return KErrGeneral;
					}
				iRomNode->iRomFile->iAttachProcess=e->iRomNode->iRomFile;
				}
			}
		}
	if (abi != my_abi)
		{
		Print(EWarning, "File %s: Attach process has different ABI\n", (const char*)TModuleName(this));
		}
	return KErrNone;
	}

TInt TRomBuilderEntry::BuildDependenceGraph(E32Rom& aRom)
//
// Fill in the iDeps
//
	{
	TBool is_kernel = ((iRomImageFlags & KRomImageFlagsKernelMask) != 0);
	TRomNode* rn = iRomNode;
	TRomFile* rf = rn->iRomFile;
	TUint my_abi = iHdr->ABI();
	TUint impfmt = iHdr->ImportFormat();
	rf->iNumDeps = iHdr->iDllRefTableCount;
	if (IsDll() && aRom.iObey->iMemModel!=E_MM_Flexible && aRom.iObey->iMemModel!=E_MM_Multiple && (iHdr->iDataSize!=0 || iHdr->iBssSize!=0))
		{
		TInt r=FindAttachProcess(aRom);
		if (r!=KErrNone)
			return r;
		if (aRom.iObey->iMemModel==E_MM_Moving)
			{
			if (rf->iAttachProcess && !(rf->iAttachProcess->RomImageFlags() & KRomImageFlagFixedAddressExe))
				rf->iAttachProcess=NULL;	// ignore attach process if not fixed
			}
		}
	TRomFile* attp=rf->iAttachProcess;
	if (attp)
		++rf->iNumDeps;		// extra implicit dependence on process
	if (rf->iNumDeps)
		{
		rf->iDeps=new TRomFile* [rf->iNumDeps];
		memset(rf->iDeps, 0, rf->iNumDeps*sizeof(TRomFile*));
		}

	TInt err = KErrNone;
	const E32ImportSection* importSection = (const E32ImportSection*)(iData + iOrigHdr->iImportOffset);
	const E32ImportBlock* block = (const E32ImportBlock*)(importSection + 1);
	TInt i;
	for (i=0; i<iHdr->iDllRefTableCount; i++, block = block->NextBlock(impfmt), TRACE(TIMPORT,Print(ELog,"DllRef/dll done\n")) )
		{
		char* dllname = (char*)importSection + block->iOffsetOfDllName;
		TDllFindInfo find_info(dllname, this);
		TBool fallback;
		TRomNode* romnode = aRom.FindImageFileByName(find_info, EFalse, fallback);
		if (!romnode)
			{
			Print(EError, "Can't build dependence graph for\n\t%s\nbecause\n\t%s\nis not in rom.\n",
						 (const char*)TModuleName(this), (const char*)TModuleName(find_info));
			aRom.FindImageFileByName(find_info, ETrue, fallback);
			err = KErrNotFound;
			continue;
			}
		if (fallback)
			{
			Print(EWarning, "File %s links to %s\n\twhich is not in ROM. Version 1.0 of latter used instead.\n",
					 (const char*)TModuleName(this), (const char*)TModuleName(find_info));
			}
		TRACE(TIMPORT,Print(ELog,"%s links to %s\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info)));
		TRACE(TIMPORT,Print(ELog,"Resolves to %s\n", (const char*)TModuleName(*romnode)));
		TBool dep_is_kernel = ((romnode->iRomFile->RomImageFlags() & KRomImageFlagsKernelMask) != 0);
		if (dep_is_kernel != is_kernel)
			{
			if (is_kernel)
				{
				Print(EError, "Kernel side executable\n\t%s\nlinks to user side executable\n\t%s\n",
									 (const char*)TModuleName(this), (const char*)TModuleName(find_info));
				}
			else
				{
				Print(EError, "User side executable\n\t%s\nlinks to kernel side executable\n\t%s\n",
									 (const char*)TModuleName(this), (const char*)TModuleName(find_info));
				}
			err = KErrGeneral;
			continue;
			}
		// prevent the situiation which importer is primary, variant or extension, exporter is device
		if (is_kernel && !Device() && romnode->iRomFile->iRbEntry->Device())	
			{
			Print(EWarning, "Kernel/variant/extension\n\t%s\nlinks to non-extension LDD/PDD\n\t%s\n",
							(const char*)TModuleName(this), (const char*)TModuleName(find_info));
			}
		if (romnode->ABI() != my_abi)
			{
			Print(EWarning, "File %s links to %s with different ABI\n", (const char*)TModuleName(this), (const char*)TModuleName(find_info));
			}

		rf->iDeps[i]=romnode->iRomFile;
		const SSecurityInfo& s1 = iHdr->iS;
		const SSecurityInfo& s2 = romnode->iRomFile->SecurityInfo();
		TInt r = CompareCapabilities(s1.iCaps, s2.iCaps, iFileName, dllname);
		if (r != KErrNone)
			err = r;
		if (romnode->iRomFile==attp)
			attp=NULL;
		}

	if (attp)
		rf->iDeps[rf->iNumDeps-1]=attp;
	TRACE(TIMPORT,Print(ELog,"BuildDep done all\n"));
	return err;
	}

TInt TRomBuilderEntry::ResolveDllRefTable(E32Rom& aRom)
//
// Fill in the DLLRefTable
//
	{
	TRomNode* rn = iRomNode;
	TRomFile* rf = rn->iRomFile;
	(void)aRom;
	if (rf->iNumPDeps==0)
		return KErrNone;	// nothing to do

	TDllRefTable* dllRefTable=(TDllRefTable*)(iDllRefTableRange.iImagePtr);

	TUint16 flags=0;

	dllRefTable->iFlags=flags;
	dllRefTable->iNumberOfEntries=(TUint16)rf->iNumPDeps;

	TInt err = KErrNone;
	TInt i;
	for (i=0; i<rf->iNumPDeps; i++)
		{
		dllRefTable->iEntry[i]=(TRomImageHeader*)rf->iPDeps[i]->iAddresses.iRunAddr;
		}
	TRACE(TIMPORT,Print(ELog,"DllRef done all\n"));
	return err;
	}

void TRomBuilderEntry::DisplaySize(TPrintType aWhere)
	{
	if(gLogLevel > DEFAULT_LOG_LEVEL){

		if(gLogLevel & LOG_LEVEL_FILE_DETAILS)
		{
			// More detailed information about file name in .
			TBool aIgnoreHiddenAttrib = ETrue;
			TInt aLen = iRomNode->FullNameLength(aIgnoreHiddenAttrib);
			char * aBuf = new char[aLen+1];
			iRomNode->GetFullName(aBuf, aIgnoreHiddenAttrib);
			if (iPatched|iRomNode->iHidden)
				Print(aWhere, "%s\t%d\t%s\t%s\n", iFileName, SizeInRom(), iPatched?"patched":"hidden", aBuf);
			else
				Print(aWhere, "%s\t%d\t%s\n", iFileName, SizeInRom(), aBuf);
			delete[] aBuf;
		}
	}
	else{
		if (iPatched|iRomNode->iHidden)
			Print(aWhere, "%s\t%d\t%s\n", iFileName, SizeInRom(), iPatched?"patched":"hidden");
		else
			Print(aWhere, "%s\t%d\n", iFileName, SizeInRom());
	}
	}

/**
 * TRomFile iRomEntry is a linked list through the various
 * distinct TRomEntry objects which may exist for the associated file
 * due to variant processing / aliasing
 */

void TRomFile::SetRomEntry(TRomEntry* aEntry)
	{
	// Need to add to the tail of the list, for backwards compatibility
	// Adding to the front of the list changes the iPrimary and iSecondary
	// values in the TRomHeader when multiple variants are present

	if (iFinal)
		return;			// address already established so no fixup required
	if (iRomEntry==0)
		{
		iRomEntry = aEntry;
		return;
		}
	TRomEntry* entry = iRomEntry;
	while (entry->iAddressLin != 0)
		entry = (TRomEntry*)entry->iAddressLin;
	entry->iAddressLin = (TLinAddr)aEntry;
	}

void TRomBuilderEntry::FixupRomEntries(TInt aSize)
	{
	if (iPatched)
		return;		// patched files don't appear in the ROM file system

	iRomNode->Finalise(aSize);
	}

/**
 * TRomNode::Finalise updates the associated TRomEntry objects with the final size and
 * linear address information supplied by the TRomBuilderEntry. It also stores the
 * summary information for resolving static linkages to this executable (if appropriate)
 * and adjusts the TRomNodes so that they are identical to the ones which would be 
 * obtained by walking the directory structure in an existing ROM.
 */
void TRomNode::Finalise(TInt aSize)
	{
	TRACE(TIMPORT,Print(ELog,"TRomNode %s Finalise %08x %d\n", (const char*)TModuleName(*this), iRomFile->iFinal));
	iRomFile->Finalise(aSize);
	}

/**
 * TRomFile::Finalise updates the associated TRomEntry objects with the final size and
 * linear address information supplied by the TRomBuilderEntry. It also stores the
 * summary information for resolving static linkages to this executable (if appropriate)
 * and adjusts the TRomFiles so that they are identical to the ones which would be 
 * obtained by walking the directory structure in an existing ROM.
 */
void TRomFile::Finalise(TInt aSize)
	{
	if (iFinal)
		return;
	TLinAddr ra = iRbEntry->iHeaderRange.iImageAddr;
	TRomEntry* entry = iRomEntry;
	while (entry)
		{
		TRomEntry* next = (TRomEntry*)entry->iAddressLin;
		entry->iSize = aSize;
		entry->iAddressLin = ra;
		entry = next;
		}
	iAddresses = iRbEntry->iHeaderRange;
	iAddresses.iSize = aSize;
	if ((!iRbEntry->iResource) && (!iRbEntry->HCRDataFile()))
		{
		iExportDir = iAddresses;
		iExportDir.iSize = iRbEntry->iHdr->iExportDirCount * sizeof(TLinAddr);
		iExportDir.Move(RomImgHdr()->iExportDir - iAddresses.iRunAddr);
		}
	iRbEntry = 0;
	iFinal = ETrue;
	}

void TRomBuilderEntry::SetRomNode(TRomNode* aNode)
	{
	iRomNode = aNode;
	}


void TImageSection::Load() const
	{ 
	if (iSize && iImagePtr && iFilePtr) 
		memcpy(iImagePtr,iFilePtr,iSize); 
	}

/**
 * TDllExportInfo is the information about a DLL which is necessary to
 * resolve a static link to that DLL. It all comes from the TRomImageHeader,
 * as it would with a static linkage resolved at runtime.
 */
TRomFile::TRomFile()
	{
	memset(this, 0, sizeof(TRomFile));
	iRefCount = 1;
	iHwvd = KVariantIndependent;
	iDataBssOffsetInExe = -1;
	}

TRomFile::~TRomFile()
	{
	delete[] iDeps;
	delete[] iPDeps;
	}

TInt TRomFile::AddressFromOrdinal(TLinAddr& aEDataAddr, TLinAddr& aExport, TUint aOrdinal)
//
// Get the export address of symbol aOrdinal
//
	{
	if(aOrdinal == 0)
	{
		aEDataAddr = iExportDir.iRunAddr -1 ;
		aExport = *(TLinAddr*)((TLinAddr*)iExportDir.iImagePtr - 1);
		if((TInt)aExport == ExportDirCount()) {
			aEDataAddr = 0;
			aExport = 0;
		}
		return KErrNone;
	}
	
	TUint index = aOrdinal - KOrdinalBase;
	if (index >= (TUint)ExportDirCount())
		return KErrNotFound;
	aEDataAddr = iExportDir.iRunAddr + index * sizeof(TLinAddr);
	aExport = ((TLinAddr*)iExportDir.iImagePtr)[index];
	return KErrNone;
	}


bool TRomFile::ComputeSmpSafe(const TRomBuilderEntry* aRbEntry)
	{
	// A component is SMP safe if:
	//
	// 1. It's E32 image file is marked as SMP safe (MMP keyword SMPSAFE).
	// 2. All components it links to are SMP safe.
	//
	// This implies a recursive dependency structure.

	if (iSmpInfo.isInit)
		{
		// We have already visited this node.
		return iSmpInfo.isSafe;
		}

	// Mark this node as "active," meaning that we are currently evaluating it. We
	// use this to detect cycles in the dependency graph.
	iSmpInfo.isActive = 1;

	iSmpInfo.isSafe = 1;

	// Have we found any cycle in the graph?
	bool is_cycle = 0;

	if ( aRbEntry->iOrigHdr->iFlags & KImageSMPSafe )
		{
		// OK, the E32 file for this node is marked as SMPSAFE. Now we need to check
		// that all nodes we depend on are SMP safe.

		for (int i = 0; i < iNumDeps; i++)
			{
			TRomFile* e = iDeps[i];

			assert(this != e);

			if (e->iSmpInfo.isActive)
				{
				is_cycle = 1;
				}
			else if ( ! e->ComputeSmpSafe(e->iRbEntry) )
				{
				if (gLogLevel & LOG_LEVEL_SMP_INFO)
					{
					Print(ELog,"SMP-unsafe: %s: links to unsafe component %s.\n",
							aRbEntry->iBareName , e->iRbEntry->iBareName);
					}

				iSmpInfo.isSafe = 0;
				break;
				}
			}
		}
	else
		{
		if (gLogLevel & LOG_LEVEL_SMP_INFO)
			{
			Print(ELog,"SMP-unsafe: %s: MMP keyword SMPSAFE not used.\n", aRbEntry->iBareName);
			}

		iSmpInfo.isSafe = 0;
		}

	iSmpInfo.isActive = 0;

	if (!iSmpInfo.isSafe || !is_cycle)
		{
		iSmpInfo.isInit = 1;
		}

	return iSmpInfo.isSafe;
	}

/**
 * TRomNode::CopyDirectory performs a deep copy of the TRomNode structure
 */
TRomNode* TRomNode::CopyDirectory(TRomNode*& aLastExecutable, TRomNode* aParent)
	{
	if (iHidden && iChild==0)
		{
		// Hidden file - do not copy (as it wouldn't be visible in the ROM filestructure)
		if (iSibling)
			return iSibling->CopyDirectory(aLastExecutable, aParent);
		else
			return 0;
		}

	TRomNode* copy = new TRomNode(*this);
	copy->iParent = aParent;
	if(aLastExecutable==0)
		aLastExecutable = copy;		// this must be the root of the structure

	// recursively copy the sub-structures
	if (iChild)
		copy->iChild = iChild->CopyDirectory(aLastExecutable, copy);
	if (iSibling)
		copy->iSibling = iSibling->CopyDirectory(aLastExecutable, aParent);

	if (copy->iAtt & KEntryAttXIP)
		AddExecutableFile(aLastExecutable,copy);
	return copy;
	}

TInt TRomNode::Alias(TRomNode* aNode, TRomNode*& aLastExecutable)
	{
	if (aNode->iAtt & KEntryAttXIP)
		AddExecutableFile(aLastExecutable,this);
	return SetBareName();
	}

TInt TRomNode::Rename(TRomNode *aOldParent, TRomNode* aNewParent, TText* aNewName)
	{
	aOldParent->Remove(this);
	aNewParent->Add(this);
	free(iName);
	iName = (TText*)NormaliseFileName((const char*)aNewName);
	return SetBareName();
	}

TInt TRomNode::SetBareName()
	{
	free(iBareName);
	TUint32 uid;
	TUint32 vin;
	TUint32 flg;
	iBareName = SplitFileName((const char*)iName, uid, vin, flg);
	if (uid || (flg & EUidPresent))
		return KErrBadName;
	if (strchr(iBareName, '{') || strchr(iBareName, '}'))
		return KErrBadName;
	if ((iAtt & KEntryAttXIP) && (flg & EVerPresent))
		{
		TUint32 ver = iRomFile->ModuleVersion();
		if (ver != vin)
			return KErrArgument;
		}
	return KErrNone;
	}