imgtools/romtools/rofsbuild/r_build.cpp
changeset 0 044383f39525
child 590 360bd6b35136
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imgtools/romtools/rofsbuild/r_build.cpp	Tue Oct 27 16:36:35 2009 +0000
@@ -0,0 +1,1415 @@
+/*
+* Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* @internalComponent * @released
+*
+*/
+
+
+#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>
+
+#if defined(__MSVCDOTNET__) || defined(__TOOLS2__)
+	#include <iomanip>
+	#include <strstream>
+#else //!__MSVCDOTNET__
+	#include <iomanip.h>
+#endif //__MSVCDOTNET__
+
+#ifdef _L
+#undef _L
+#endif
+
+#include "h_utl.h"
+#include "r_obey.h"
+#include "rofs.h"
+#include "e32image.h"
+#include "patchdataprocessor.h"
+
+extern TUint checkSum(const void* aPtr);
+
+extern ECompression gCompress;
+extern TUint gCompressionMethod;
+extern TInt  gCodePagingOverride;
+extern TInt  gDataPagingOverride;
+extern TInt  gLogLevel;
+TBool gDriveImage=EFalse;	// for drive image support.
+
+
+TInt TRomNode::Count=0;
+TRomNode* TRomNode::TheFirstNode = NULL;
+TRomNode* TRomNode::TheLastNode = NULL;
+
+// introduced for data drive files' attribute
+TUint8 TRomNode::sDefaultInitialAttr = (TUint8)KEntryAttReadOnly;
+
+struct SortableEntry
+	{
+	TRofsEntry* iEntry;
+	TBool iIsDir;
+	TUint16 iOffset;
+	};
+
+int compare(const void* l, const void* r)
+	{
+	const SortableEntry* left  = (const SortableEntry*)l;
+	const SortableEntry* right = (const SortableEntry*)r;
+	if (left->iIsDir)
+		{
+		if (!right->iIsDir)
+			return -1;	// dir < file
+		}
+	else
+		{
+		if (right->iIsDir)
+			return +1;	// file > dir
+		}
+
+	// both the same type of entry, sort by name
+	// must first convert to an 8 bit string
+	// array and NULL terminate it.
+	char temp1[500];
+	char temp2[500];
+
+
+TInt i=0;
+	for (i = 0; i < left->iEntry->iNameLength; i++)
+		{
+		temp1[i]=(char) left->iEntry->iName[i];
+		}
+	temp1[i]=0;
+
+	for (i = 0; i < right->iEntry->iNameLength; i++)
+		{
+		temp2[i]=(char) right->iEntry->iName[i];
+		}
+	temp2[i]=0;
+
+	return stricmp((const char*)&temp1[0], (const char*)&temp2[0]);
+	}
+
+TRomNode::TRomNode(TText* aName, TRomBuilderEntry* aEntry)
+//
+// Constructor
+//
+	:
+	iNextNode(NULL),
+	iParent(NULL), iSibling(0), iChild(0), iNextNodeForSameFile(0), 
+	iTotalDirectoryBlockSize(0),
+	iTotalFileBlockSize(0),
+	iImagePosition(0),
+	iFileBlockPosition(0),
+	iAtt(sDefaultInitialAttr),
+	iAttExtra(0xFF),
+	iHidden(EFalse),
+	iEntry(aEntry),
+	iFileStartOffset(0), 
+	iSize(0), 
+	iOverride(0),
+	iFileUpdate(EFalse),
+    iAlias(false)
+	{
+	iName = (TText*)NormaliseFileName((const char*)aName);
+	iIdentifier=TRomNode::Count++;
+
+	// Add this node to the flat linked list
+	if( !TheFirstNode )
+		{
+		TheFirstNode = this;
+		}
+	else
+		{
+		TheLastNode->iNextNode = this;
+		}
+	TheLastNode = this;
+
+	if (iEntry)
+		{
+		iEntry->SetRomNode(this);
+		}
+	else
+		{
+		iAtt = (TUint8)KEntryAttDir;
+		}
+	}
+
+TRomNode::~TRomNode()
+	{
+	if (iEntry && !iAlias)
+        {
+		delete iEntry;
+        }
+    iEntry = 0;
+	if(iName)
+		free(iName);
+    iName = 0;
+	}
+
+TRomNode *TRomNode::FindInDirectory(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 ((stricmp((const char *)aName, (const char *)entry->iName))==0) 
+			return entry;
+		else
+			entry=entry->iSibling;
+		}
+	return 0;
+	}
+
+
+
+TInt indend = 0;
+
+void indendStructure(TInt i)
+       {
+	while(i > 0)
+	   {
+	     cout << "    ";
+	     i--;
+	   }
+       };  
+
+// displays the directory structure
+void TRomNode::DisplayStructure(ostream* aOut)
+	{
+	  indendStructure(indend);
+      *aOut  << iName << "\n";
+	  if (iChild)
+	    {
+	      indend++; 
+	      iChild->DisplayStructure(aOut);
+	      indend--;
+	    }
+	  if (iSibling)
+	    iSibling->DisplayStructure(aOut);
+	}
+
+
+void TRomNode::deleteTheFirstNode()
+{
+
+	TheFirstNode = NULL;
+}
+
+
+void TRomNode::InitializeCount()
+{
+	Count = 0;
+}
+void TRomNode::displayFlatList()
+{
+	TRomNode* current =	TheFirstNode;
+	TInt i = 0;
+	while(current)
+	{
+		i++;
+		cout <<  "\n" << i <<": " << current->iName << endl;
+		current = current->NextNode();
+	}
+
+	}
+
+
+
+void TRomNode::AddFile(TRomNode* aChild)
+	{
+	if (iEntry)
+		{
+		Print(EError, "Adding subdirectory to a file!!!\n");
+		return;
+		}
+	Add(aChild);
+	}
+
+TRomNode* TRomNode::NewSubDir(TText *aName)
+	{
+	if (iEntry)
+		{
+		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;
+		}
+	node->iParent = this;
+	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;
+	}
+
+TInt TRomNode::SetAttExtra(TText *anAttWord, TRomBuilderEntry* aFile, enum EKeyword aKeyword)
+//
+// Set the file extra attribute byte from the letters passed
+// Note: The iAttExtra bits are inverted. '0' represent enabled
+//
+	{
+	iAttExtra=0xFF;
+	if (anAttWord==0 || anAttWord[0]=='\0')
+		return Print(EError, "Missing argument for keyword 'exattrib'.\n");
+	for (TText *letter=anAttWord;*letter!=0;letter++)
+		{
+		switch (*letter)
+			{
+		case 'u':
+			iAttExtra |= (KEntryAttUnique >> 23);	// '1' represents disabled in iAttExtra
+			break;
+		case 'U':
+			iAttExtra &= ~(KEntryAttUnique >> 23);	// '0' represent enabled in iAttExtra
+			break;
+		default:
+			return Print(EError, "Unrecognised exattrib - '%c'.\n", *letter);
+			break;
+			}
+		}
+
+	if((~iAttExtra & (KEntryAttUnique >> 23))!=0)	// If the unique file attribute is set
+		{
+		if(aKeyword==EKeywordFile || aKeyword==EKeywordData)	// If the Keyword is File or Data
+			{
+				if(strlen(aFile->iFileName) > (KMaxFileName-KRofsMangleNameLength)) // check whether we have enough space to add the mangle tage
+					return Print(EError, "Lengthy filename with unique attribute to name mangle.\n");
+			}
+		else	// for all other keywords
+			return Print(EError, "exattrib field not allowed for entries except data and file.\n");
+		}
+	return KErrNone;
+	}
+
+
+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;
+	}
+
+
+
+TInt TRomNode::CalculateEntrySize() const
+	// Calculates the amount of ROM space required to hold
+	// this entry. The return is the actual size of the TRofsEntry
+	// structure, not rounded up
+	{
+	TInt requiredSizeBytes = KRofsEntryHeaderSize +	NameLengthUnicode();
+	return requiredSizeBytes;
+	}
+
+TInt TRomNode::CalculateDirectoryEntrySize( TInt& aDirectoryBlockSize,
+										    TInt& aFileBlockSize )
+	// Calculates the total size of the TRofsDir structure required
+	// for this directory and the size of the files block. Traverses all the
+	// children adding their entry sizes. The result is not rounded up.
+	//
+	// On return aDirectoryBlockSize is the number of bytes required for the
+	//	main directory structure. aFileBlockSize is the number of bytes
+	//	required to hold the list of files.
+	//
+	// Returns KErrNone on success
+	{
+
+	TInt offsetBytes=0;
+	TInt padBytes=0;
+	if( 0 == iTotalDirectoryBlockSize )
+		{
+		// need to calculate by walking children	
+		if( !iChild )
+			{
+			return Print(EError, "TRomNode structure corrupt\n");
+			}
+
+		TInt dirBlockSize = KRofsDirHeaderSize;
+		TInt fileBlockSize = 0;
+		TInt fileCount=0;
+		TInt dirCount=0;
+
+		TRomNode* node = iChild;
+		while (node)
+			{
+			TInt entrySize = node->CalculateEntrySize();
+			if( node->IsDirectory() )
+				{
+				dirBlockSize += (4 - dirBlockSize) & 3;	// pad to next word boundary
+				dirBlockSize += entrySize;
+				dirCount++;
+				}
+			else
+				{
+				fileBlockSize += (4 - fileBlockSize) & 3;	// pad to next word boundary
+				fileBlockSize += entrySize;
+				fileCount++;
+				}
+			node = node->iSibling;
+			}
+		
+		offsetBytes = ((fileCount + dirCount) * 2) + 4; //the +4 are the two offset counts,
+		padBytes = offsetBytes % 4;
+
+		iTotalDirectoryBlockSize = dirBlockSize;
+		iTotalFileBlockSize = fileBlockSize;
+		}
+
+	aDirectoryBlockSize = iTotalDirectoryBlockSize + offsetBytes + padBytes;
+	aFileBlockSize = iTotalFileBlockSize;
+	return KErrNone;
+	}
+
+/**
+Place the files and it's attributes (incase of executables)
+Called for both rofs and datadrive creation.
+ 
+@param aDest   - Destination buffer.
+@param aOffset - offset value, used for rofs only.
+@param aMaxSize- Maximum size required for rofs.
+  
+@return - Returns the number of bytes placed or a -ve error code.
+*/ 
+TInt TRomNode::PlaceFile( TUint8* &aDest, TUint aOffset, TUint aMaxSize, CBytePair *aBPE )
+	//
+	// Place the file into the ROM image, making any necessary conversions
+	// along the way.
+	//
+	// Returns the number of bytes placed or a -ve error code.
+	{
+
+	TInt size=0;
+	
+	// file hasn't been placed for drive image. 
+	if(gDriveImage)
+	{
+		size = iEntry->PlaceFile(aDest,aMaxSize,aBPE);
+		iSize = size;
+	}
+	else
+	{
+		if (iEntry->iHidden)
+			iFileStartOffset = KFileHidden;
+		else
+		{
+                    if (iEntry->iFileOffset==0)
+                    {
+                        // file hasn't been placed
+                        size = iEntry->PlaceFile( aDest, aMaxSize, aBPE );
+                        if (size>=0)
+                            iEntry->iFileOffset = aOffset;
+                    }
+                    else {
+                        iFileStartOffset = (TInt)iEntry;
+                    }
+		}
+	}
+
+	// Deal with any override attributes
+	// (omit paging overrides as these are dealt with in TRomBuilderEntry::PlaceFile
+	//  and may also be legitimately specified for non-executable files in ROM)
+	if( iOverride&~(KOverrideCodeUnpaged|KOverrideCodePaged|KOverrideDataUnpaged|KOverrideDataPaged) )
+		{
+		E32ImageHeaderV* hdr = (E32ImageHeaderV*)aDest;
+
+		TUint hdrfmt = hdr->HeaderFormat();
+		if (hdrfmt != KImageHdrFmt_V)
+			{
+			Print(EError,"%s: Can't load old format binary\n", iEntry->iFileName);
+			return KErrNotSupported;
+			}
+		
+		// First need to check that it's a real image header
+		if( (TUint)size > sizeof(E32ImageHeader) )
+			{
+			if( ((TInt)hdr->iSignature == 0x434f5045u) && ((TInt)hdr->iUid1 == KExecutableImageUidValue || (TInt)hdr->iUid1 == KDynamicLibraryUidValue) )
+				{
+				// Should check the CRC as well here...
+				// Something for later
+
+				// Ok, it looks like an image header
+				if( iOverride & KOverrideStack )
+					{
+					hdr->iStackSize = iStackSize;
+					}
+				if( iOverride & KOverrideHeapMin )
+					{
+					hdr->iHeapSizeMin = iHeapSizeMin;
+					}
+				if( iOverride & KOverrideHeapMax )
+					{
+					hdr->iHeapSizeMax = iHeapSizeMax;
+					}
+				if( iOverride & KOverrideFixed )
+					{
+					if( hdr->iFlags & KImageDll )
+						{
+						Print(EError,"%s: Can't used FIXED keyword on a DLL\n", iEntry->iFileName);
+						return KErrNotSupported;
+						}
+					hdr->iFlags |= KImageFixedAddressExe;
+					}
+				if( iOverride & (KOverrideUid1|KOverrideUid2|KOverrideUid3))
+					{
+					if (iOverride & KOverrideUid1)
+						{
+						hdr->iUid1 = iUid1;
+						}
+					if (iOverride & KOverrideUid2)
+						{
+						hdr->iUid2 = iUid2;
+						}
+					if (iOverride & KOverrideUid3)
+						{
+						hdr->iUid3 = iUid3;
+						}
+					// Need to re-checksum the UIDs
+					TUidType ut(TUidType(TUid::Uid(hdr->iUid1), TUid::Uid(hdr->iUid2), TUid::Uid(hdr->iUid3)));
+					hdr->iUidChecksum =  (checkSum(((TUint8*)&ut)+1)<<16)|checkSum(&ut);
+					}
+				if( iOverride & KOverridePriority )
+					{
+					hdr->iProcessPriority = (TUint16)iPriority;
+					}
+				if( iOverride & KOverrideCapability )
+					{
+					hdr->iS.iCaps = iCapability;
+					}
+
+				// Need to re-CRC the header
+				hdr->iHeaderCrc = KImageCrcInitialiser;
+				TUint32 crc = 0;
+				TInt hdrsz = hdr->TotalSize();
+				HMem::Crc32(crc, hdr, hdrsz);
+				hdr->iHeaderCrc = crc;
+				}
+			}
+		}
+
+	return size;
+	}
+
+TInt TRomNode::CountFileAndDir(TInt& aFileCount, TInt& aDirCount)
+	{
+	//
+	// Count the number of file and directory entries for this node
+	//
+	TRomNode* node = iChild;
+
+	aFileCount=0;
+	aDirCount=0;
+	while( node )
+		{
+		if( node->IsFile() )
+			{
+			aFileCount++;
+			}
+		else
+			{
+			aDirCount++;
+			}
+
+		node = node->iSibling;
+		}
+	return KErrNone;
+	}
+
+TInt TRomNode::Place( TUint8* aDestBase )
+	//
+	// Writes this directory entry out to the image.
+	// The image starts at aDestBase.
+	// The position in the image must already have been set with SetImagePosition()
+	// and SetFileBlockPosition().
+	// Returns KErrNone on success
+	//
+	{
+	TUint8* dirBlockBase = aDestBase + iImagePosition;
+	TUint8* fileBlockBase = aDestBase + iFileBlockPosition;
+
+	TRofsDir* pDir = (TRofsDir*)dirBlockBase;
+	pDir->iFirstEntryOffset = KRofsDirFirstEntryOffset;
+	pDir->iFileBlockAddress = iFileBlockPosition;
+	pDir->iFileBlockSize = iTotalFileBlockSize;
+	pDir->iStructSize = (TUint16)iTotalDirectoryBlockSize;
+
+	TRofsEntry* pDirEntry = &(pDir->iSubDir);
+	TRofsEntry* pFileEntry = (TRofsEntry*)fileBlockBase;
+
+	TInt dirCount;
+	TInt fileCount;
+	TInt index = 0;
+	CountFileAndDir(fileCount, dirCount);
+
+	SortableEntry* array = new SortableEntry[fileCount + dirCount];
+	TRomNode* node = iChild;
+
+	while( node )
+		{
+		TRofsEntry* entry;
+
+		if( node->IsFile() )
+			{
+			entry = pFileEntry;
+
+			//Offset in 32bit words from start of file block
+			array[index].iOffset = (TUint16) ((((TUint8*) entry) - fileBlockBase) >> 2);
+			array[index].iIsDir = EFalse;
+			}
+		else
+			{
+			entry = pDirEntry;
+
+			//Offset in 32bit words from start of directory block
+			array[index].iOffset = (TUint16) ((((TUint8*) entry) - dirBlockBase) >> 2);
+			array[index].iIsDir = ETrue;
+			}
+		array[index].iEntry = entry;
+		index++;
+
+		entry->iNameOffset = KRofsEntryNameOffset;
+		entry->iAtt = node->iAtt;
+		entry->iAttExtra = node->iAttExtra;
+
+		TInt entryLen = KRofsEntryHeaderSize;
+		entryLen += node->NameCpy( (char*)&entry->iName, entry->iNameLength );
+		entryLen += (4 - entryLen) & 3;	// round up to nearest word
+		entry->iStructSize = (TUint16)entryLen;
+
+
+		if( node->IsFile() )
+			{
+			// node is a file, entry points to the file
+			// write an entry out into the file block
+			pFileEntry->iFileAddress = node->iFileStartOffset;
+			node->iAtt &= ~KEntryAttDir;
+			pFileEntry->iFileSize = node->iEntry->RealFileSize();
+			memcpy(&pFileEntry->iUids[0], &node->iEntry->iUids[0], sizeof(pFileEntry->iUids));
+			pFileEntry = (TRofsEntry*)( (TUint8*)pFileEntry + entryLen );
+			}
+		else
+			{
+			// node is a subdirectory, entry points to directory
+			pDirEntry->iFileAddress = node->iImagePosition;
+			node->iAtt |= KEntryAttDir;
+			
+			// the size is just the size of the directory block
+			pDirEntry->iFileSize = node->iTotalDirectoryBlockSize;
+			pDirEntry = (TRofsEntry*)( (TUint8*)pDirEntry + entryLen );
+			}
+
+		node = node->iSibling;
+		}
+
+	qsort(array,fileCount + dirCount,sizeof(SortableEntry),&compare);
+
+	//Now copy the contents of sorted array to the image
+	TUint16* currentPtr = (TUint16*) (dirBlockBase + iTotalDirectoryBlockSize);
+
+	*currentPtr=(TUint16)dirCount;
+	currentPtr++;
+	*currentPtr=(TUint16)fileCount;
+	currentPtr++;
+
+	for (index = 0; index < (fileCount + dirCount); index++)
+		{
+		*currentPtr = array[index].iOffset;
+		currentPtr++;
+		}
+	delete[] array;
+	return KErrNone;
+	}
+
+
+
+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;
+		if(iChild==0)
+			{
+				iParent->Remove(this);
+				TRomNode * current = TheFirstNode;
+				TRomNode * prev = current;
+				while(current != this)
+					{
+						prev = current;
+						current = current->NextNode();
+					}
+				prev->SetNextNode(current->NextNode());
+				delete this;
+			}
+		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;
+	}
+
+void TRomNode::CountDirectory(TInt& aFileCount, TInt& aDirCount)
+	{
+	TRomNode *current=iChild;
+	while(current)
+		{
+		if (current->iChild)
+			aDirCount++;
+		else
+ 			aFileCount++;
+	current=current->iSibling;
+		}
+	}
+
+ 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;
+        prev = 0;
+		}
+ 	}
+
+
+
+
+TInt TRomNode::NameCpy(char* aDest, TUint8& aUnicodeLength )
+//
+// Safely copy a file name in the rom entry
+// Returns the number of bytes used. Write the length in unicode characters
+// into aUnicodeLength.
+//
+	{
+
+	if ((aDest==NULL) || (iName==NULL))
+		return 0;
+	const unsigned char* pSourceByte = (const unsigned char*)iName;
+	unsigned char* pTargetByte=(unsigned char*)aDest;
+	for (;;)
+		{
+		const TUint sourceByte=*pSourceByte;
+		if (sourceByte==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);
+		}
+	aUnicodeLength = (TUint8)(numberOfBytesInTarget/2); // returns the length of aDest (in UTF-16 characters for Unicode, not bytes)
+	return numberOfBytesInTarget;
+	}
+
+
+TInt TRomNode::NameLengthUnicode() const
+//
+// Find the unicode lenght of the name
+//
+	{
+
+	if (iName==NULL)
+		return 0;
+
+	const unsigned char* pSourceByte = (const unsigned char*)iName;
+	TInt len = 0;
+	for (;;)
+		{
+		const TUint sourceByte=*pSourceByte;
+		if (sourceByte==0)
+			{
+			break;
+			}
+		if ((sourceByte&0x80)==0)
+			{
+			len += 2;
+			++pSourceByte;
+			}
+		else if ((sourceByte&0xe0)==0xc0)
+			{
+			++pSourceByte;
+			const TUint secondSourceByte=*pSourceByte;
+			if ((secondSourceByte&0xc0)!=0x80)
+				{
+				Print(EError, "Bad UTF-8 '%s'", iName);
+				exit(671);
+				}
+			len += 2;
+			++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);
+				}
+			len += 2;
+			++pSourceByte;
+			}
+		else
+			{
+			Print(EError, "Bad UTF-8 '%s'", iName);
+			exit(674);
+			}
+		}
+	return len;
+	}
+
+
+void TRomNode::AddNodeForSameFile(TRomNode* aPreviousNode, TRomBuilderEntry* aFile)
+	{
+	// sanity checking
+	if (iNextNodeForSameFile != 0 || iEntry != aFile || (aPreviousNode && aPreviousNode->iEntry != iEntry))
+		{
+		Print(EError, "Adding Node for same file: TRomNode structure corrupted\n");
+		exit(666);
+		}
+	iNextNodeForSameFile = aPreviousNode;
+	}
+
+
+
+
+
+//**************************************
+// TRomBuilderEntry
+//**************************************
+
+
+
+TRomBuilderEntry::TRomBuilderEntry(const char *aFileName,TText *aName)
+//
+// Constructor
+//
+:iFirstDllDataEntry(0),	iName(0),iFileName(0),iNext(0), iNextInArea(0),
+iExecutable(EFalse), iFileOffset(EFalse), iCompressEnabled(0),
+iHidden(0), iRomNode(0), iRealFileSize(0)		 
+{
+	if (aFileName)
+   		iFileName = NormaliseFileName(aFileName);
+	if (aName)
+		iName = (TText*)NormaliseFileName((const char*)aName);
+	memset(iUids,0 ,sizeof(TCheckedUid));
+}
+	
+TRomBuilderEntry::~TRomBuilderEntry()
+//
+// Destructor
+//
+	{
+	if(iFileName)
+	{
+	free(iFileName);
+	}
+	iFileName = 0;
+	if(iName)
+	{
+	free(iName);
+	}
+	}
+
+void TRomBuilderEntry::SetRomNode(TRomNode* aNode)
+	{
+	aNode->AddNodeForSameFile(iRomNode, this);
+	iRomNode = aNode;
+	}
+
+
+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::PlaceFile( TUint8* &aDest,TUint aMaxSize, CBytePair *aBPE )
+	//
+	// Place the file in ROM. Since we don't support compression yet all
+	// we have to do is read the file into memory
+	// compress it, if it isn't already compressed.
+	//
+	// Returns the number of bytes used, or -ve error code
+	{
+	TUint compression = 0;
+	TBool executable = iExecutable;
+	Print(ELog,"Reading file %s to image\n", iFileName );
+	TUint32 size=HFile::GetLength((TText*)iFileName);
+	if (size==0)
+		Print(EWarning, "File %s does not exist or is 0 bytes in length.\n",iFileName);
+        if (aDest == NULL) {
+            aMaxSize = size*2;
+            aMaxSize = (aMaxSize>0) ? aMaxSize : 2;
+            aDest = new TUint8[aMaxSize];
+        }
+
+	if (executable)
+		{
+		// indicate if the image will overflow without compression
+	TBool overflow;
+			if(size>aMaxSize)
+			overflow = ETrue;
+		else
+			overflow = EFalse;
+
+		// try to compress this executable
+		E32ImageFile f(aBPE);
+		TInt r = f.Open(iFileName);
+		// is it really a valid E32ImageFile?
+		if (r != KErrNone)
+			{
+			Print(EWarning, "File '%s' is not a valid executable.  Placing file as data.\n", iFileName);
+			executable = EFalse;
+			}
+		else
+			{
+
+			if(iRomNode->iOverride & KOverrideDllData)
+			{
+				DllDataEntry *aDllEntry = iRomNode->iEntry->GetFirstDllDataEntry();
+				TLinAddr* aExportTbl;
+				void *aLocation;
+				TUint aDataAddr;
+				char *aCodeSeg, *aDataSeg;
+
+				aExportTbl = (TLinAddr*)((char*)f.iData + f.iOrigHdr->iExportDirOffset);
+
+				// const data symbol may belong in the Code section. If the address lies within the Code or data section limits, 
+				// get the corresponding location and update it.While considering the Data section limits
+				// don't include the Bss section, as it doesn't exist as yet in the image.
+				while( aDllEntry ){
+					if(aDllEntry->iOrdinal != (TUint32)-1){
+						if(aDllEntry->iOrdinal < 1 || aDllEntry->iOrdinal > (TUint)f.iOrigHdr->iExportDirCount){
+							Print(EWarning, "Invalid ordinal %d specified for DLL %s\n", aDllEntry->iOrdinal, iRomNode->iName);
+							aDllEntry = aDllEntry->NextDllDataEntry();
+							continue;
+						}
+					
+				//	Get the address of the data field via the export table.
+					aDataAddr = (TInt32)(aExportTbl[aDllEntry->iOrdinal - 1] + aDllEntry->iOffset);
+					if( aDataAddr >= f.iOrigHdr->iCodeBase && aDataAddr <= (f.iOrigHdr->iCodeBase + f.iOrigHdr->iCodeSize)){
+						aCodeSeg = (char*)(f.iData + f.iOrigHdr->iCodeOffset);
+						aLocation = (void*)(aCodeSeg + aDataAddr - f.iOrigHdr->iCodeBase );
+						memcpy(aLocation, &aDllEntry->iNewValue, aDllEntry->iSize);
+					}
+					else if(aDataAddr >= f.iOrigHdr->iDataBase && aDataAddr <= (f.iOrigHdr->iDataBase + f.iOrigHdr->iDataSize)){
+						aDataSeg = (char*)(f.iData + f.iOrigHdr->iDataOffset);
+						aLocation = (void*)(aDataSeg + aDataAddr - f.iOrigHdr->iDataBase );
+						memcpy(aLocation, &aDllEntry->iNewValue, aDllEntry->iSize);
+					}
+					else
+					{
+						Print(EWarning, "Patchdata failed as address pointed by ordinal %d of DLL %s doesn't lie within Code or Data section limits\n", aDllEntry->iOrdinal, iRomNode->iName);
+					}
+					}
+					else if(aDllEntry->iDataAddress != (TLinAddr)-1){
+						aDataAddr = aDllEntry->iDataAddress + aDllEntry->iOffset;
+					if( aDataAddr >= f.iOrigHdr->iCodeBase && aDataAddr <= (f.iOrigHdr->iCodeBase + f.iOrigHdr->iCodeSize)){
+						aCodeSeg = (char*)(f.iData + f.iOrigHdr->iCodeOffset);
+						aLocation = (void*)(aCodeSeg + aDataAddr - f.iOrigHdr->iCodeBase );
+						memcpy(aLocation, &aDllEntry->iNewValue, aDllEntry->iSize);
+					}
+					else if(aDataAddr >= f.iOrigHdr->iDataBase && aDataAddr <= (f.iOrigHdr->iDataBase + f.iOrigHdr->iDataSize)){
+						aDataSeg = (char*)(f.iData + f.iOrigHdr->iDataOffset);
+						aLocation = (void*)(aDataSeg + aDataAddr - f.iOrigHdr->iDataBase );
+						memcpy(aLocation, &aDllEntry->iNewValue, aDllEntry->iSize);
+					}
+					else
+					{
+						Print(EWarning, "Patchdata failed as address 0x%x of DLL %s doesn't lie within Code or Data section limits\n", aDllEntry->iOrdinal, iRomNode->iName);
+					}
+					}
+					aDllEntry = aDllEntry->NextDllDataEntry();
+					}
+			}
+
+			compression = f.iHdr->CompressionType();
+			Print(ELog,"Original file:'%s' is compressed by method:%08x\n", iFileName, compression);
+
+
+			TUint32 oldFileComp;
+			TUint32 newFileComp;
+
+			if(compression)
+			{
+				// The E32 image in release directory is compressed
+				oldFileComp = compression;
+			}
+			else
+			{
+				// The E32 image in release directory is uncompressed
+				oldFileComp = 0;
+			}
+
+			if( iCompressEnabled != ECompressionUnknown)
+			{
+				// The new state would be as stated in obey file, i.e. 
+				// filecompress or fileuncompress
+				newFileComp = gCompressionMethod;
+			}
+			else if (gCompress != ECompressionUnknown)
+			{
+				// The new state would be as stated set globally
+				newFileComp = gCompressionMethod;
+			}
+			else
+			{
+				// When not known if compression is to be applied or not,
+				// set it same as that of the E32 image in release directory
+				newFileComp = oldFileComp;
+			}
+
+			if(!gDriveImage)
+			{
+				// overide paging flags...
+				E32ImageHeaderV* h=f.iHdr;
+				if (iRomNode->iOverride & KOverrideCodePaged)
+					{
+					h->iFlags &= ~KImageCodeUnpaged;
+					h->iFlags |= KImageCodePaged;
+					}
+				if (iRomNode->iOverride & KOverrideCodeUnpaged)
+					{
+					h->iFlags |= KImageCodeUnpaged;
+					h->iFlags &= ~KImageCodePaged;
+					}
+				if (iRomNode->iOverride & KOverrideDataPaged)
+					{
+					h->iFlags &= ~KImageDataUnpaged;
+					h->iFlags |= KImageDataPaged;
+					}
+				if (iRomNode->iOverride & KOverrideDataUnpaged)
+					{
+					h->iFlags |= KImageDataUnpaged;
+					h->iFlags &= ~KImageDataPaged;
+					}
+
+				// apply global paging override...
+				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;
+					}
+				f.UpdateHeaderCrc();
+
+				// make sure paged code has correct compression type...
+				if(h->iFlags&KImageCodePaged)
+					{
+					if(newFileComp!=0)
+						newFileComp = KUidCompressionBytePair;
+					}
+			}
+
+			if ( oldFileComp != newFileComp )
+				{
+				
+				if( newFileComp == 0)
+					{
+					Print(ELog,"Decompressing executable '%s'\n", iFileName);
+					f.iHdr->iCompressionType = 0;
+					}
+				else
+					{
+					Print(ELog,"Compressing executable '%s' with method:%08x\n", iFileName, newFileComp);
+					f.iHdr->iCompressionType = newFileComp;
+					}
+				f.UpdateHeaderCrc();
+				if (overflow)
+					{
+					char * buffer = new char [size];
+					// need to check if the compressed file will fit in the image
+   					#if defined(__LINUX__)
+ 					ostrstream os((char*)aDest, aMaxSize, (ios::openmode)(ios::out+ios::binary));
+					#elif defined(__TOOLS2__) && defined (_STLP_THREADS)
+  					ostrstream os((char*)buffer, size,(ios::out+ios::binary));
+  					#elif defined( __TOOLS2__)
+   					ostrstream os((char*)buffer, size,(ios::out+ios::binary));
+					#else
+					ostrstream os( (char*)buffer, size, (ios::out+ios::binary));
+					#endif
+					os << f;
+					TUint compressedSize = os.pcount();
+					if (compressedSize <= aMaxSize)
+						overflow = EFalse;	
+					delete[] buffer;
+					}
+				}
+			if (overflow)
+				{
+				Print(EError, "Can't fit '%s' in image\n", iFileName);
+				Print(EError, "Overflowed by approximately 0x%x bytes.\n", size - aMaxSize);
+				exit(667);
+				}
+  			#if defined(__TOOLS2__) && defined (_STLP_THREADS)
+  			ostrstream os((char*)aDest, aMaxSize,(ios::out+ios::binary));
+  			#elif __TOOLS2__
+			ostrstream os((char*)aDest, aMaxSize, (std::_Ios_Openmode)(ios::out+ios::binary));
+			#else
+			ostrstream os((char*)aDest, aMaxSize, (ios::out+ios::binary));
+			#endif
+			os << f;
+			size = os.pcount();
+			compression = f.iHdr->CompressionType();
+			memcpy(&iUids[0], aDest, sizeof(iUids));
+			}
+		}
+	if (!executable)
+		{
+		if ( size > aMaxSize )
+			{
+			Print(EError, "Can't fit '%s' in image\n", iFileName);
+			Print(EError, "Overflowed by approximately 0x%x bytes.\n", size - aMaxSize);
+			exit(667);
+			}
+		size = HFile::Read((TText*)iFileName, (TAny *)aDest);
+                TUint32 Uidslen = (size > sizeof(iUids)) ? sizeof(iUids) : size;
+                memcpy(&iUids[0], aDest, Uidslen);
+		}
+
+	if (compression)
+		Print(ELog,"Compressed executable File '%s' size: %08x, mode:%08x\n", iFileName, size, compression);
+	else if (iExecutable)
+		Print(ELog,"Executable File '%s' size: %08x\n", iFileName, size);
+	else
+		Print(ELog,"File '%s' size: %08x\n", iFileName, size);
+	iRealFileSize = size;	// required later when directory is written
+	
+	return size;
+	}
+
+
+TRomNode* TRomNode::CopyDirectory(TRomNode*& aLastExecutable)
+	{
+
+	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);
+		else
+			return 0;
+		}
+
+	TRomNode* copy = new TRomNode(iName);
+	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);
+	if (iSibling)
+		copy->iSibling = iSibling->CopyDirectory(aLastExecutable);
+	copy->Clone(this);
+	return copy;
+	}
+
+
+
+
+void TRomNode::Clone(TRomNode* aOriginal)
+	{
+	iAtt = aOriginal->iAtt;
+	iAttExtra = aOriginal->iAttExtra;
+	iEntry = aOriginal->iEntry;
+	iHidden = aOriginal->iHidden;
+	iFileStartOffset = aOriginal->iFileStartOffset;
+	iSize = aOriginal->iSize;
+	iParent = aOriginal->iParent;
+    iAlias = aOriginal->iAlias;
+	}
+
+
+void TRomNode::Alias(TRomNode* aNode)
+	{
+	  // sanity checking
+	if (aNode->iEntry == 0) 
+	{
+		Print(EError, "Aliasing: TRomNode structure corrupted\n");
+		exit(666);
+	}
+	Clone(aNode);
+	iEntry = aNode->iEntry;
+	if (iEntry)
+		{
+		iEntry->SetRomNode(this);
+		}
+    iAlias = true;
+	}
+
+
+void TRomNode::Rename(TRomNode *aOldParent, TRomNode* aNewParent, TText* aNewName)
+	{
+	aOldParent->Remove(this);
+	aNewParent->Add(this);
+	delete [] iName;
+	iName = new TText[strlen((const char *)aNewName)+1];
+	strcpy ((char *)iName, (const char *)aNewName);
+	}
+
+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;
+	}
+
+// Fuction to return first node in the patchdata linked list
+DllDataEntry *TRomBuilderEntry::GetFirstDllDataEntry() const
+{
+	if (iFirstDllDataEntry)
+	{
+		return iFirstDllDataEntry;
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
+// Fuction to set first node in the patchdata linked list
+void TRomBuilderEntry::SetFirstDllDataEntry(DllDataEntry *aDllDataEntry)
+{
+	iFirstDllDataEntry = aDllDataEntry;	
+}
+void TRomBuilderEntry::DisplaySize(TPrintType aWhere)
+{
+	TBool aIgnoreHiddenAttrib = ETrue;
+	TInt aLen = iRomNode->FullNameLength(aIgnoreHiddenAttrib);
+	char *aBuf = new char[aLen+1];
+	if(gLogLevel & LOG_LEVEL_FILE_DETAILS)
+		{
+		iRomNode->GetFullName(aBuf, aIgnoreHiddenAttrib);
+		if(iFileName)
+			Print(aWhere, "%s\t%d\t%s\t%s\n", iFileName, RealFileSize(), (iRomNode->iHidden || iHidden)?"hidden":"", aBuf);
+		else
+			Print(aWhere, "%s\t%s\n", (iRomNode->iHidden || iHidden)?"hidden":"", aBuf);
+		}
+	else
+		{
+		if(iFileName)
+			Print(aWhere, "%s\t%d\n", iFileName, RealFileSize());
+		}
+
+}