imgtools/romtools/rofsbuild/r_rofs.cpp
changeset 0 044383f39525
child 590 360bd6b35136
equal deleted inserted replaced
-1:000000000000 0:044383f39525
       
     1 /*
       
     2 * Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <e32std.h>
       
    20 #include <e32std_private.h>
       
    21 #include <e32uid.h>
       
    22 #include <f32file.h>
       
    23 #include "h_utl.h"
       
    24 #include <string.h>
       
    25 #include <stdlib.h>
       
    26 #include "r_obey.h"
       
    27 #include "r_rofs.h"
       
    28 #include "r_coreimage.h"
       
    29 #include "memmap.h"
       
    30 extern TInt gLogLevel;
       
    31 extern TBool gLowMem;
       
    32 extern TBool gFastCompress;
       
    33 extern TInt gThreadNum;
       
    34 ////////////////////////////////////////////////////////////////////////
       
    35 
       
    36 
       
    37 
       
    38 inline TUint32 AlignData(TUint32 anAddr)
       
    39 	{
       
    40 	return ((anAddr+0x0f)&~0x0f);
       
    41 	}
       
    42 
       
    43 
       
    44 ////////////////////////////////////////////////////////////////////////
       
    45 
       
    46 E32Rofs::E32Rofs(CObeyFile *aObey)
       
    47 //
       
    48 // Constructor
       
    49 //
       
    50 	: iObey( aObey ), iOverhead(0)
       
    51 	{
       
    52 
       
    53 	iSize=aObey->iRomSize;
       
    54 	if(gLowMem)
       
    55 	{
       
    56 		iImageMap = new Memmap();
       
    57 
       
    58 		if(iImageMap == NULL)
       
    59 		{
       
    60 			iSize = 0;
       
    61 			Print(EError, "Out of memory.\n");
       
    62 		}
       
    63 		else
       
    64 		{
       
    65 			iImageMap->SetMaxMapSize(iSize);
       
    66 			if(iImageMap->CreateMemoryMap(0, 0xff) == EFalse)
       
    67 			{
       
    68 				iSize = 0;
       
    69 				Print(EError, "Failed to create image map object");
       
    70 
       
    71 				iImageMap->CloseMemoryMap(ETrue);
       
    72 				delete iImageMap;
       
    73 				iImageMap = NULL;
       
    74 			}
       
    75 			else
       
    76 			{
       
    77 				iData = iImageMap->GetMemoryMapPointer();
       
    78 			}
       
    79 		}
       
    80 	}
       
    81 	else
       
    82 	{
       
    83 		iData=new char [iSize];
       
    84 		if (iData==NULL)
       
    85 			iSize=0;
       
    86 		HMem::Set(iData, 0xff, iSize);
       
    87 	}
       
    88 
       
    89 	}
       
    90 
       
    91 E32Rofs::~E32Rofs()
       
    92 //
       
    93 // Destructor
       
    94 //
       
    95 	{
       
    96 
       
    97 	if(gLowMem)
       
    98 	{
       
    99 		iImageMap->CloseMemoryMap(ETrue);
       
   100 		delete iImageMap;
       
   101 	}
       
   102 	else
       
   103 		delete iData;
       
   104 	}
       
   105 
       
   106 
       
   107 TInt E32Rofs::CreateExtension(MRofsImage* aImage) 
       
   108 	{
       
   109 
       
   110 	TUint8* addr=(TUint8*)iData;
       
   111 
       
   112 	TRomNode* pRootDir = aImage->RootDirectory();
       
   113 	
       
   114 
       
   115 	const TInt extensionRofsheaderSize = KExtensionRofsHeaderSize;
       
   116 	
       
   117 	// aImage->iSize contains the max size of the core image
       
   118 
       
   119 	// Layout the directory structure. Does not actually write it
       
   120 	// to the image. Returns the number of bytes used for the directory
       
   121 	// structure within the image.
       
   122 	TInt directoryOffset = extensionRofsheaderSize;
       
   123 	const TInt directorySize = LayoutDirectory( pRootDir, aImage->Size()+directoryOffset );
       
   124 	if( directorySize <= 0 )
       
   125 		{
       
   126 		Print(EError, "Failed laying out directories - return code %d\n", directorySize);
       
   127 		return KErrGeneral;
       
   128 		}
       
   129 
       
   130 	// get offset to start of file data, rounded up to next word boundary
       
   131 	TInt offs = extensionRofsheaderSize + directorySize;
       
   132 	const TInt fileDataStartOffset = offs + ( (4 - offs) & 3);
       
   133 
       
   134 	// Now we traverse the list of entries placing each file
       
   135 	// This updates the directory entries to point to the correct offset
       
   136 	// to the start of the file
       
   137 	const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset + aImage->Size(), aImage->Size());
       
   138 	if( fileDataSize <= 0 )
       
   139 		{
       
   140 		Print(EError, "Failed placing files - return code %d\n", fileDataSize);
       
   141 		return KErrGeneral;
       
   142 		}
       
   143 
       
   144 	// and then put the directory into the image
       
   145 	TInt err = PlaceDirectory( pRootDir, addr - aImage->Size() ); // offset pointer by size of core image
       
   146 	if( err != KErrNone )
       
   147 		{
       
   148 		Print(EError, "Failed placing directory - return code %d\n", err);
       
   149 		return err;
       
   150 		}
       
   151 		
       
   152 	directoryOffset+=aImage->Size(); // offset offset by size of core image
       
   153 	// Now write the header
       
   154 	TExtensionRofsHeader * pHeader = (TExtensionRofsHeader*)iData;
       
   155 	pHeader->iIdentifier[0] = 'R';
       
   156 	pHeader->iIdentifier[1] = 'O';
       
   157 	pHeader->iIdentifier[2] = 'F';
       
   158 	pHeader->iIdentifier[3] = 'x';
       
   159 	pHeader->iHeaderSize = KExtensionRofsHeaderSize;
       
   160 	pHeader->iDirTreeOffset = directoryOffset;
       
   161 	pHeader->iDirTreeSize = iTotalDirectoryBlockSize;
       
   162 	pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize;
       
   163 	pHeader->iDirFileEntriesSize = iTotalFileBlockSize;
       
   164 	pHeader->iRofsFormatVersion = KRofsFormatVersion;
       
   165 	pHeader->iTime = iObey->iTime;
       
   166 	iSizeUsed = fileDataSize + fileDataStartOffset;
       
   167 	pHeader->iImageSize = iSizeUsed;
       
   168 	if (iObey->AutoSize())
       
   169 		MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size
       
   170 	pHeader->iMaxImageSize = iSize;
       
   171 	pHeader->iCheckSum = 0;		// not used yet
       
   172 
       
   173 	return KErrNone;
       
   174 	}
       
   175 	
       
   176 void E32Rofs::MakeAutomaticSize(TUint32 aPageSize)
       
   177 		{
       
   178 		TUint32 size = iSizeUsed;
       
   179 		if (iSizeUsed % aPageSize > 0)
       
   180 			{
       
   181 			//used size needs to be rounded up to nearest page size
       
   182 			size = (iSizeUsed/aPageSize + 1)*aPageSize;
       
   183 			}
       
   184 		iSize = size;
       
   185 		}
       
   186 
       
   187 TInt E32Rofs::Create()
       
   188 //
       
   189 // This is the main entry point to the ROFS image creation
       
   190 //
       
   191 	{
       
   192 	TUint8* addr=(TUint8*)iData;
       
   193 
       
   194 	TRomNode* pRootDir = iObey->iRootDirectory;
       
   195 	const TInt headerSize = KRofsHeaderSize;
       
   196 	// Layout the directory structure. Does not actually write it
       
   197 	// to the image. Returns the number of bytes used for the directory
       
   198 	// structure within the image.
       
   199 	const TInt directoryOffset = headerSize;
       
   200 	const TInt directorySize = LayoutDirectory( pRootDir, directoryOffset );
       
   201 	if( directorySize <= 0 )
       
   202 		{
       
   203 		Print(EError, "Failed laying out directories - return code %d\n", directorySize);
       
   204 		return KErrGeneral;
       
   205 		}
       
   206 
       
   207 	// get offset to start of file data, rounded up to next word boundary
       
   208 	TInt offs = headerSize + directorySize;
       
   209 	const TInt fileDataStartOffset = offs + ( (4 - offs) & 3);
       
   210 
       
   211 	// Now we traverse the list of entries placing each file
       
   212 	// This updates the directory entries to point to the correct offset
       
   213 	// to the start of the file
       
   214 	const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset );
       
   215 	if( fileDataSize < 0 )
       
   216 		{
       
   217 		Print(EError, "Failed placing files - return code %d\n", fileDataSize);
       
   218 		return KErrGeneral;
       
   219 		}
       
   220 
       
   221 	// and then put the directory into the image
       
   222 	TInt err = PlaceDirectory( pRootDir, addr );
       
   223 	if( err != KErrNone )
       
   224 		{
       
   225 		Print(EError, "Failed placing directory - return code %d\n", err);
       
   226 		return err;
       
   227 		}
       
   228 		
       
   229 	// Now write the header
       
   230 	TRofsHeader* pHeader = (TRofsHeader*)iData;
       
   231 	pHeader->iIdentifier[0] = 'R';
       
   232 	pHeader->iIdentifier[1] = 'O';
       
   233 	pHeader->iIdentifier[2] = 'F';
       
   234 	pHeader->iIdentifier[3] = 'S';
       
   235 	pHeader->iHeaderSize = KExtensionRofsHeaderSize;
       
   236 	pHeader->iDirTreeOffset = directoryOffset;
       
   237 	pHeader->iDirTreeSize = iTotalDirectoryBlockSize;
       
   238 	pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize;
       
   239 	pHeader->iDirFileEntriesSize = iTotalFileBlockSize;
       
   240 	pHeader->iRofsFormatVersion = KRofsFormatVersion;
       
   241 	pHeader->iTime = iObey->iTime;
       
   242 	iSizeUsed = fileDataSize + fileDataStartOffset;
       
   243 	pHeader->iImageSize = iSizeUsed;
       
   244 	pHeader->iImageVersion = iObey->iVersion;
       
   245 	if (iObey->AutoSize())
       
   246 		MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size
       
   247 		
       
   248 	pHeader->iMaxImageSize = iSize;
       
   249 	pHeader->iCheckSum = 0;		// not used yet
       
   250 
       
   251 	return KErrNone;
       
   252 	}
       
   253 void E32Rofs::DisplaySizes(TPrintType aWhere)
       
   254 {
       
   255 	Print(aWhere, "Summary of file sizes in rofs:\n");
       
   256 	TRomBuilderEntry *file=iObey->FirstFile();
       
   257 	while(file)
       
   258 		{
       
   259 		file->DisplaySize(aWhere);
       
   260 		file=iObey->NextFile();
       
   261 		}
       
   262 	Print( aWhere, "Directory block size: %d\n"
       
   263 					"File block size:      %d\n"
       
   264 					"Total directory size: %d\n"
       
   265 					"Total image size:     %d\n",
       
   266 					iTotalDirectoryBlockSize,
       
   267 					iTotalFileBlockSize,
       
   268 					iTotalDirectoryBlockSize + iTotalFileBlockSize,
       
   269 					iSizeUsed );
       
   270 
       
   271 }
       
   272 
       
   273 void E32Rofs::LogExecutableAttributes(E32ImageHeaderV *aHdr)
       
   274 {
       
   275 	Print(ELog, "Uids:                    %08x %08x %08x %08x\n", aHdr->iUid1, aHdr->iUid2, aHdr->iUid3, aHdr->iUidChecksum);
       
   276 	Print(ELog, "Data size:               %08x\n", aHdr->iDataSize);
       
   277 	Print(ELog, "Heap min:                %08x\n", aHdr->iHeapSizeMin);
       
   278 	Print(ELog, "Heap max:                %08x\n", aHdr->iHeapSizeMax);
       
   279 	Print(ELog, "Stack size:              %08x\n", aHdr->iStackSize);
       
   280 	Print(ELog, "Secure ID:               %08x\n", aHdr->iS.iSecureId);
       
   281 	Print(ELog, "Vendor ID:               %08x\n", aHdr->iS.iVendorId);
       
   282 	Print(ELog, "Priority:                %d\n\n", aHdr->iProcessPriority);
       
   283 }
       
   284 class Worker : public boost::thread {
       
   285     public:
       
   286     static void thrd_func(E32Rofs* rofs){
       
   287         CBytePair bpe(gFastCompress);
       
   288 
       
   289         bool deferred = false;
       
   290         TPlacingSection* p = rofs->GetFileNode(deferred);
       
   291         while(p) {
       
   292             if(!deferred) 
       
   293                 p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe);
       
   294             p = rofs->GetFileNode(deferred);
       
   295         }
       
   296         rofs->ArriveDeferPoint();
       
   297         p = rofs->GetDeferredJob();
       
   298         while(p) {
       
   299             p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe);
       
   300             p = rofs->GetDeferredJob();
       
   301         }
       
   302     }
       
   303     Worker(E32Rofs* rofs) : boost::thread(thrd_func,rofs) {
       
   304     }
       
   305 };
       
   306 
       
   307 TPlacingSection* E32Rofs::GetFileNode(bool &aDeferred) {
       
   308     //get a node from the node list, the node list is protected by mutex iMuxTree.
       
   309     //The iMuxTree also helps to make sure the order in iVPS is consistent with the node list.
       
   310     //And this is the guarantee of same outputs regardless of how many threads being used.
       
   311     boost::mutex::scoped_lock lock(iMuxTree);
       
   312     aDeferred = false;
       
   313     TRomNode* node = iLastNode;
       
   314     while(node) {
       
   315         if( node->IsFile()) {
       
   316             if(!node->iHidden) {
       
   317                 iLastNode = node->NextNode();
       
   318                 break;
       
   319             }
       
   320         }
       
   321         node = node->NextNode();
       
   322     }
       
   323 
       
   324     if(node && node->IsFile() && !node->iHidden) {
       
   325         TPlacingSection* pps = new TPlacingSection(node);
       
   326         iVPS.push_back(pps);
       
   327         if(node->iAlias) {
       
   328             iQueueAliasNode.push(pps);
       
   329             aDeferred =  true;
       
   330         }
       
   331         return pps;
       
   332     }
       
   333     return NULL;
       
   334 }
       
   335 TPlacingSection* E32Rofs::GetDeferredJob() {
       
   336     // waiting all the normal node have been placed.
       
   337     while(iWorkerArrived < gThreadNum)
       
   338         boost::this_thread::sleep(boost::posix_time::milliseconds(10));
       
   339 
       
   340     // now we can safely handle the alias nodes.
       
   341     boost::mutex::scoped_lock lock(iMuxTree);
       
   342     TPlacingSection* p = NULL;
       
   343     if(!iQueueAliasNode.empty()) {
       
   344         p = iQueueAliasNode.front();
       
   345         iQueueAliasNode.pop();
       
   346     }
       
   347     return p;
       
   348 }
       
   349 void E32Rofs::ArriveDeferPoint() {
       
   350     boost::mutex::scoped_lock lock(iMuxTree);
       
   351     ++iWorkerArrived;
       
   352 }
       
   353 TInt E32Rofs::PlaceFiles( TRomNode* /*aRootDir*/, TUint8* aDestBase, TUint aBaseOffset, TInt aCoreSize ) 
       
   354 	//
       
   355 	// Traverses all entries placing all files and updating directory entry pointers.
       
   356 	// Returns number of bytes placed or -ve error code.
       
   357 	//
       
   358 	{
       
   359             iLastNode = TRomNode::FirstNode();
       
   360             iWorkerArrived = 0;
       
   361 
       
   362             boost::thread_group thrds;
       
   363             Worker** workers = new Worker*[gThreadNum];
       
   364             int i;
       
   365             for (i = 0; i < gThreadNum; ++i) {
       
   366                 workers[i] = new Worker(this);
       
   367                 thrds.add_thread(workers[i]);
       
   368             }
       
   369 
       
   370             thrds.join_all();
       
   371             delete [] workers;
       
   372 
       
   373             TUint offset = aBaseOffset;
       
   374             TUint8* dest = aDestBase;
       
   375             TBool aIgnoreHiddenAttrib = ETrue;
       
   376             TInt len = iVPS.size();
       
   377             TInt maxSize;
       
   378             for(i=0;i<len;i++) {
       
   379                 maxSize = aCoreSize + iSize - offset;
       
   380                 if(maxSize <= 0) {
       
   381                     // Image size is too low to proceed.
       
   382                     return maxSize;
       
   383                 }
       
   384                 if(iVPS[i]->node->iFileStartOffset != (TUint)KFileHidden) {
       
   385                     memcpy(dest,iVPS[i]->buf,iVPS[i]->len);
       
   386                     if(iVPS[i]->node->iEntry->iFileOffset == -1) {
       
   387                         iVPS[i]->node->iEntry->iFileOffset = offset;
       
   388                         iVPS[i]->node->iFileStartOffset = iVPS[i]->node->iEntry->iFileOffset;
       
   389                     }
       
   390                     else {
       
   391                         TRomBuilderEntry* aEntry = (TRomBuilderEntry*)(iVPS[i]->node->iFileStartOffset);
       
   392                         iVPS[i]->node->iFileStartOffset = aEntry->iFileOffset;
       
   393                     }
       
   394                 }
       
   395                 iVPS[i]->len += (4-iVPS[i]->len) & 3;// round up to next word boundary
       
   396                 dest += iVPS[i]->len;
       
   397                 offset += iVPS[i]->len;
       
   398 
       
   399                 if(gLogLevel > DEFAULT_LOG_LEVEL )
       
   400                 {
       
   401                     TRomNode* node = iVPS[i]->node;
       
   402                     TInt aLen = node->FullNameLength(aIgnoreHiddenAttrib);
       
   403                     char *aBuf = new char[aLen+1];
       
   404                     if(gLogLevel & LOG_LEVEL_FILE_DETAILS)
       
   405                     {
       
   406                         node->GetFullName(aBuf, aIgnoreHiddenAttrib);
       
   407                         if(node->iEntry->iFileName)
       
   408                             Print(ELog,"%s\t%d\t%s\t%s\n", node->iEntry->iFileName, node->iEntry->RealFileSize(), (node->iHidden || node->iEntry->iHidden)? "hidden":"", aBuf);
       
   409                         else
       
   410                             Print(ELog,"%s\t%s\n", (node->iHidden || node->iEntry->iHidden) ? "hidden":"", aBuf);
       
   411                     }
       
   412 
       
   413                     if(gLogLevel & LOG_LEVEL_FILE_ATTRIBUTES)
       
   414                     {
       
   415                         if(!node->iHidden && !node->iEntry->iHidden)
       
   416                             Print(ELog, "Device file name:        %s\n", aBuf);
       
   417                         if(node->iEntry->iExecutable)
       
   418                             LogExecutableAttributes((E32ImageHeaderV*)(dest-len));
       
   419                     }
       
   420                     delete[] aBuf;
       
   421                 }
       
   422             }
       
   423 	return offset - aBaseOffset;	// number of bytes used
       
   424 	}
       
   425 
       
   426 
       
   427 
       
   428 
       
   429 
       
   430 
       
   431 TInt E32Rofs::LayoutDirectory( TRomNode* /*aRootDir*/, TUint aBaseOffset ) 
       
   432 	//
       
   433 	// Creates the directory layout but does not write it to the image.
       
   434 	// All directories are given a location in the image.
       
   435 	// Returns the total number of bytes used for the directory (rounded
       
   436 	// up to the nearest word) or a -ve error code.
       
   437 	//
       
   438 	{
       
   439 	TRomNode* node = TRomNode::FirstNode();
       
   440 
       
   441 	TUint offset = aBaseOffset;
       
   442 	while( node )
       
   443 		{
       
   444 		if( node->IsDirectory())
       
   445 			{
       
   446 			// it is a directory block so we have to give it a location
       
   447 			node->SetImagePosition( offset );
       
   448 		
       
   449 			// work out how much space it requires for the directory block
       
   450 			TInt dirLen;
       
   451 			TInt fileLen;
       
   452 			TInt err = node->CalculateDirectoryEntrySize( dirLen, fileLen );
       
   453 			if( err != KErrNone )
       
   454 				{
       
   455 				return err;
       
   456 				}
       
   457 			Print( ELog, "Directory '%s' @offs=0x%x, size=%d\n", node->iName, offset, dirLen );
       
   458 			dirLen += (4-dirLen) & 3;	// round up to next word boundary
       
   459 			offset += dirLen;
       
   460 			}
       
   461 
       
   462 		node = node->NextNode();
       
   463 		}
       
   464 
       
   465 	TInt totalDirectoryBlockSize = offset - aBaseOffset;	// number of bytes used
       
   466 	totalDirectoryBlockSize += (4 - totalDirectoryBlockSize) & 3;		// round up
       
   467 
       
   468 	// Now go round again placing the file blocks
       
   469 	offset = aBaseOffset + totalDirectoryBlockSize;
       
   470 	const TUint fileBlockStartOffset = offset;
       
   471 	node = TRomNode::FirstNode();
       
   472 	while( node )
       
   473 		{
       
   474 		if( node->IsDirectory() )
       
   475 			{
       
   476 			// work out how much space it requires for the file block
       
   477 			TInt dummy;
       
   478 			TInt fileLen;
       
   479 			TInt err = node->CalculateDirectoryEntrySize( dummy, fileLen );
       
   480 
       
   481 			if( err != KErrNone )
       
   482 				{
       
   483 				return fileLen;
       
   484 				}
       
   485 			if( fileLen )
       
   486 				{
       
   487 				node->SetFileBlockPosition( offset );
       
   488 				Print( ELog, "File block for dir '%s' @offs=0x%x, size=%d\n", node->iName, offset, fileLen );
       
   489 				}
       
   490 		
       
   491 			fileLen += (4-fileLen) & 3;	// round up to next word boundary
       
   492 			offset += fileLen;
       
   493 			}
       
   494 
       
   495 		node = node->NextNode();
       
   496 		}
       
   497 
       
   498 	TInt totalFileBlockSize = offset - fileBlockStartOffset;	// number of bytes used
       
   499 	totalFileBlockSize += (4 - totalFileBlockSize) & 3;		// round up
       
   500 
       
   501 	iTotalDirectoryBlockSize = totalDirectoryBlockSize;
       
   502 	iTotalFileBlockSize = totalFileBlockSize;
       
   503 
       
   504 	return totalDirectoryBlockSize + totalFileBlockSize;
       
   505 	}
       
   506 
       
   507 
       
   508 TInt E32Rofs::PlaceDirectory( TRomNode* /*aRootDir*/, TUint8* aDestBase ) 
       
   509 	//
       
   510 	// Writes the directory into the image. 
       
   511 	// Returns KErrNone on success, or error code
       
   512 	//
       
   513 	{
       
   514 	TRomNode* node = TRomNode::FirstNode();
       
   515 
       
   516 	while( node )
       
   517 		{
       
   518 		if( node->IsDirectory() )
       
   519 			{
       
   520 			TInt err = node->Place( aDestBase );
       
   521 			if( err != KErrNone )
       
   522 				{
       
   523 				return err;
       
   524 				}
       
   525 			}
       
   526 		node = node->NextNode();
       
   527 		}
       
   528 	return KErrNone;
       
   529 	}
       
   530 
       
   531 TInt E32Rofs::WriteImage( TInt aHeaderType )
       
   532 	{
       
   533 	ofstream romFile((const char *)iObey->iRomFileName,ios::binary);
       
   534 	if (!romFile)
       
   535 		return Print(EError,"Cannot open ROM file %s for output\n",iObey->iRomFileName);
       
   536 	Write(romFile, aHeaderType);
       
   537 	romFile.close();
       
   538 
       
   539 	return KErrNone;
       
   540 	}
       
   541 
       
   542 TRomNode* E32Rofs::CopyDirectory(TRomNode*& aLastExecutable)
       
   543 	{
       
   544 	return iObey->iRootDirectory->CopyDirectory(aLastExecutable);
       
   545 	}
       
   546 
       
   547 
       
   548 void E32Rofs::Write(ofstream &os, TInt aHeaderType)
       
   549 
       
   550 // Output a rom image
       
   551 
       
   552 	{
       
   553 
       
   554 	switch (aHeaderType)
       
   555 		{
       
   556 	default:
       
   557 	case 0:
       
   558 		Print(EAlways, "\nWriting Rom image without");
       
   559 		break;
       
   560 	case 2:
       
   561 		Print(EAlways, "\nWriting Rom image with PE-COFF");
       
   562 			{
       
   563 			unsigned char coffhead[0x58] = {0};  // zero all the elements
       
   564 
       
   565 			// fill in the constant bits
       
   566 			// this is supposed to be simple, remember
       
   567 			coffhead[1] = 0x0a;
       
   568 			coffhead[2] = 0x01;
       
   569 			coffhead[0x10] = 0x1c;
       
   570 			coffhead[0x12] = 0x0f;
       
   571 			coffhead[0x13] = 0xa1;
       
   572 			coffhead[0x14] = 0x0b;
       
   573 			coffhead[0x15] = 0x01;
       
   574 			coffhead[0x26] = 0x40;
       
   575 			coffhead[0x2a] = 0x40;
       
   576 			coffhead[0x30] = 0x2e;
       
   577 			coffhead[0x31] = 0x74;
       
   578 			coffhead[0x32] = 0x65;
       
   579 			coffhead[0x33] = 0x78;
       
   580 			coffhead[0x34] = 0x74;
       
   581 			coffhead[0x3a] = 0x40;
       
   582 			coffhead[0x3e] = 0x40;
       
   583 			coffhead[0x44] = 0x58;
       
   584 			coffhead[0x54] = 0x20;
       
   585 
       
   586 			// now fill in the text segment size
       
   587 			*(TUint32 *) (&coffhead[0x18]) = ALIGN4K(iSizeUsed);
       
   588 			*(TUint32 *) (&coffhead[0x40]) = ALIGN4K(iSizeUsed);
       
   589 
       
   590 			os.write(reinterpret_cast<char *>(coffhead), sizeof(coffhead));
       
   591 			}
       
   592 		break;
       
   593 		}
       
   594 	Print(EAlways, " header to file %s\n", iObey->iRomFileName);
       
   595 	os.write( iData, iSizeUsed );
       
   596 	}
       
   597 
       
   598 
       
   599 TRomNode* E32Rofs::RootDirectory()
       
   600 	{
       
   601 	return iObey->iRootDirectory;
       
   602 	}
       
   603 void E32Rofs::SetRootDirectory(TRomNode* aDir)
       
   604 	{
       
   605 	iObey->iRootDirectory = aDir;
       
   606 	}
       
   607 TText* E32Rofs::RomFileName()
       
   608 	{
       
   609 	return iObey->iRomFileName;
       
   610 	}
       
   611 TInt E32Rofs::Size()
       
   612 	{
       
   613 	return iSize;
       
   614 	}
       
   615 
       
   616 ///////////////////
       
   617