diff -r c7c26511138f -r 360bd6b35136 imgtools/romtools/rofsbuild/r_rofs.cpp --- a/imgtools/romtools/rofsbuild/r_rofs.cpp Wed Jun 16 16:51:40 2010 +0300 +++ b/imgtools/romtools/rofsbuild/r_rofs.cpp Wed Jun 23 16:56:47 2010 +0800 @@ -1,617 +1,587 @@ -/* -* Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of the License "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". -* -* Initial Contributors: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* -*/ - - -#include -#include -#include -#include -#include "h_utl.h" -#include -#include -#include "r_obey.h" -#include "r_rofs.h" -#include "r_coreimage.h" -#include "memmap.h" -extern TInt gLogLevel; -extern TBool gLowMem; -extern TBool gFastCompress; -extern TInt gThreadNum; -//////////////////////////////////////////////////////////////////////// - - - -inline TUint32 AlignData(TUint32 anAddr) - { - return ((anAddr+0x0f)&~0x0f); - } - - -//////////////////////////////////////////////////////////////////////// - -E32Rofs::E32Rofs(CObeyFile *aObey) -// -// Constructor -// - : iObey( aObey ), iOverhead(0) - { - - iSize=aObey->iRomSize; - if(gLowMem) - { - iImageMap = new Memmap(); - - if(iImageMap == NULL) - { - iSize = 0; - Print(EError, "Out of memory.\n"); - } - else - { - iImageMap->SetMaxMapSize(iSize); - if(iImageMap->CreateMemoryMap(0, 0xff) == EFalse) - { - iSize = 0; - Print(EError, "Failed to create image map object"); - - iImageMap->CloseMemoryMap(ETrue); - delete iImageMap; - iImageMap = NULL; - } - else - { - iData = iImageMap->GetMemoryMapPointer(); - } - } - } - else - { - iData=new char [iSize]; - if (iData==NULL) - iSize=0; - HMem::Set(iData, 0xff, iSize); - } - - } - -E32Rofs::~E32Rofs() -// -// Destructor -// - { - - if(gLowMem) - { - iImageMap->CloseMemoryMap(ETrue); - delete iImageMap; - } - else - delete iData; - } - - -TInt E32Rofs::CreateExtension(MRofsImage* aImage) - { - - TUint8* addr=(TUint8*)iData; - - TRomNode* pRootDir = aImage->RootDirectory(); - - - const TInt extensionRofsheaderSize = KExtensionRofsHeaderSize; - - // aImage->iSize contains the max size of the core image - - // Layout the directory structure. Does not actually write it - // to the image. Returns the number of bytes used for the directory - // structure within the image. - TInt directoryOffset = extensionRofsheaderSize; - const TInt directorySize = LayoutDirectory( pRootDir, aImage->Size()+directoryOffset ); - if( directorySize <= 0 ) - { - Print(EError, "Failed laying out directories - return code %d\n", directorySize); - return KErrGeneral; - } - - // get offset to start of file data, rounded up to next word boundary - TInt offs = extensionRofsheaderSize + directorySize; - const TInt fileDataStartOffset = offs + ( (4 - offs) & 3); - - // Now we traverse the list of entries placing each file - // This updates the directory entries to point to the correct offset - // to the start of the file - const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset + aImage->Size(), aImage->Size()); - if( fileDataSize <= 0 ) - { - Print(EError, "Failed placing files - return code %d\n", fileDataSize); - return KErrGeneral; - } - - // and then put the directory into the image - TInt err = PlaceDirectory( pRootDir, addr - aImage->Size() ); // offset pointer by size of core image - if( err != KErrNone ) - { - Print(EError, "Failed placing directory - return code %d\n", err); - return err; - } - - directoryOffset+=aImage->Size(); // offset offset by size of core image - // Now write the header - TExtensionRofsHeader * pHeader = (TExtensionRofsHeader*)iData; - pHeader->iIdentifier[0] = 'R'; - pHeader->iIdentifier[1] = 'O'; - pHeader->iIdentifier[2] = 'F'; - pHeader->iIdentifier[3] = 'x'; - pHeader->iHeaderSize = KExtensionRofsHeaderSize; - pHeader->iDirTreeOffset = directoryOffset; - pHeader->iDirTreeSize = iTotalDirectoryBlockSize; - pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize; - pHeader->iDirFileEntriesSize = iTotalFileBlockSize; - pHeader->iRofsFormatVersion = KRofsFormatVersion; - pHeader->iTime = iObey->iTime; - iSizeUsed = fileDataSize + fileDataStartOffset; - pHeader->iImageSize = iSizeUsed; - if (iObey->AutoSize()) - MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size - pHeader->iMaxImageSize = iSize; - pHeader->iCheckSum = 0; // not used yet - - return KErrNone; - } - -void E32Rofs::MakeAutomaticSize(TUint32 aPageSize) - { - TUint32 size = iSizeUsed; - if (iSizeUsed % aPageSize > 0) - { - //used size needs to be rounded up to nearest page size - size = (iSizeUsed/aPageSize + 1)*aPageSize; - } - iSize = size; - } - -TInt E32Rofs::Create() -// -// This is the main entry point to the ROFS image creation -// - { - TUint8* addr=(TUint8*)iData; - - TRomNode* pRootDir = iObey->iRootDirectory; - const TInt headerSize = KRofsHeaderSize; - // Layout the directory structure. Does not actually write it - // to the image. Returns the number of bytes used for the directory - // structure within the image. - const TInt directoryOffset = headerSize; - const TInt directorySize = LayoutDirectory( pRootDir, directoryOffset ); - if( directorySize <= 0 ) - { - Print(EError, "Failed laying out directories - return code %d\n", directorySize); - return KErrGeneral; - } - - // get offset to start of file data, rounded up to next word boundary - TInt offs = headerSize + directorySize; - const TInt fileDataStartOffset = offs + ( (4 - offs) & 3); - - // Now we traverse the list of entries placing each file - // This updates the directory entries to point to the correct offset - // to the start of the file - const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset ); - if( fileDataSize < 0 ) - { - Print(EError, "Failed placing files - return code %d\n", fileDataSize); - return KErrGeneral; - } - - // and then put the directory into the image - TInt err = PlaceDirectory( pRootDir, addr ); - if( err != KErrNone ) - { - Print(EError, "Failed placing directory - return code %d\n", err); - return err; - } - - // Now write the header - TRofsHeader* pHeader = (TRofsHeader*)iData; - pHeader->iIdentifier[0] = 'R'; - pHeader->iIdentifier[1] = 'O'; - pHeader->iIdentifier[2] = 'F'; - pHeader->iIdentifier[3] = 'S'; - pHeader->iHeaderSize = KExtensionRofsHeaderSize; - pHeader->iDirTreeOffset = directoryOffset; - pHeader->iDirTreeSize = iTotalDirectoryBlockSize; - pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize; - pHeader->iDirFileEntriesSize = iTotalFileBlockSize; - pHeader->iRofsFormatVersion = KRofsFormatVersion; - pHeader->iTime = iObey->iTime; - iSizeUsed = fileDataSize + fileDataStartOffset; - pHeader->iImageSize = iSizeUsed; - pHeader->iImageVersion = iObey->iVersion; - if (iObey->AutoSize()) - MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size - - pHeader->iMaxImageSize = iSize; - pHeader->iCheckSum = 0; // not used yet - - return KErrNone; - } -void E32Rofs::DisplaySizes(TPrintType aWhere) -{ - Print(aWhere, "Summary of file sizes in rofs:\n"); - TRomBuilderEntry *file=iObey->FirstFile(); - while(file) - { - file->DisplaySize(aWhere); - file=iObey->NextFile(); - } - Print( aWhere, "Directory block size: %d\n" - "File block size: %d\n" - "Total directory size: %d\n" - "Total image size: %d\n", - iTotalDirectoryBlockSize, - iTotalFileBlockSize, - iTotalDirectoryBlockSize + iTotalFileBlockSize, - iSizeUsed ); - -} - -void E32Rofs::LogExecutableAttributes(E32ImageHeaderV *aHdr) -{ - Print(ELog, "Uids: %08x %08x %08x %08x\n", aHdr->iUid1, aHdr->iUid2, aHdr->iUid3, aHdr->iUidChecksum); - Print(ELog, "Data size: %08x\n", aHdr->iDataSize); - Print(ELog, "Heap min: %08x\n", aHdr->iHeapSizeMin); - Print(ELog, "Heap max: %08x\n", aHdr->iHeapSizeMax); - Print(ELog, "Stack size: %08x\n", aHdr->iStackSize); - Print(ELog, "Secure ID: %08x\n", aHdr->iS.iSecureId); - Print(ELog, "Vendor ID: %08x\n", aHdr->iS.iVendorId); - Print(ELog, "Priority: %d\n\n", aHdr->iProcessPriority); -} -class Worker : public boost::thread { - public: - static void thrd_func(E32Rofs* rofs){ - CBytePair bpe(gFastCompress); - - bool deferred = false; - TPlacingSection* p = rofs->GetFileNode(deferred); - while(p) { - if(!deferred) - p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe); - p = rofs->GetFileNode(deferred); - } - rofs->ArriveDeferPoint(); - p = rofs->GetDeferredJob(); - while(p) { - p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe); - p = rofs->GetDeferredJob(); - } - } - Worker(E32Rofs* rofs) : boost::thread(thrd_func,rofs) { - } -}; - -TPlacingSection* E32Rofs::GetFileNode(bool &aDeferred) { - //get a node from the node list, the node list is protected by mutex iMuxTree. - //The iMuxTree also helps to make sure the order in iVPS is consistent with the node list. - //And this is the guarantee of same outputs regardless of how many threads being used. - boost::mutex::scoped_lock lock(iMuxTree); - aDeferred = false; - TRomNode* node = iLastNode; - while(node) { - if( node->IsFile()) { - if(!node->iHidden) { - iLastNode = node->NextNode(); - break; - } - } - node = node->NextNode(); - } - - if(node && node->IsFile() && !node->iHidden) { - TPlacingSection* pps = new TPlacingSection(node); - iVPS.push_back(pps); - if(node->iAlias) { - iQueueAliasNode.push(pps); - aDeferred = true; - } - return pps; - } - return NULL; -} -TPlacingSection* E32Rofs::GetDeferredJob() { - // waiting all the normal node have been placed. - while(iWorkerArrived < gThreadNum) - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - - // now we can safely handle the alias nodes. - boost::mutex::scoped_lock lock(iMuxTree); - TPlacingSection* p = NULL; - if(!iQueueAliasNode.empty()) { - p = iQueueAliasNode.front(); - iQueueAliasNode.pop(); - } - return p; -} -void E32Rofs::ArriveDeferPoint() { - boost::mutex::scoped_lock lock(iMuxTree); - ++iWorkerArrived; -} -TInt E32Rofs::PlaceFiles( TRomNode* /*aRootDir*/, TUint8* aDestBase, TUint aBaseOffset, TInt aCoreSize ) - // - // Traverses all entries placing all files and updating directory entry pointers. - // Returns number of bytes placed or -ve error code. - // - { - iLastNode = TRomNode::FirstNode(); - iWorkerArrived = 0; - - boost::thread_group thrds; - Worker** workers = new Worker*[gThreadNum]; - int i; - for (i = 0; i < gThreadNum; ++i) { - workers[i] = new Worker(this); - thrds.add_thread(workers[i]); - } - - thrds.join_all(); - delete [] workers; - - TUint offset = aBaseOffset; - TUint8* dest = aDestBase; - TBool aIgnoreHiddenAttrib = ETrue; - TInt len = iVPS.size(); - TInt maxSize; - for(i=0;inode->iFileStartOffset != (TUint)KFileHidden) { - memcpy(dest,iVPS[i]->buf,iVPS[i]->len); - if(iVPS[i]->node->iEntry->iFileOffset == -1) { - iVPS[i]->node->iEntry->iFileOffset = offset; - iVPS[i]->node->iFileStartOffset = iVPS[i]->node->iEntry->iFileOffset; - } - else { - TRomBuilderEntry* aEntry = (TRomBuilderEntry*)(iVPS[i]->node->iFileStartOffset); - iVPS[i]->node->iFileStartOffset = aEntry->iFileOffset; - } - } - iVPS[i]->len += (4-iVPS[i]->len) & 3;// round up to next word boundary - dest += iVPS[i]->len; - offset += iVPS[i]->len; - - if(gLogLevel > DEFAULT_LOG_LEVEL ) - { - TRomNode* node = iVPS[i]->node; - TInt aLen = node->FullNameLength(aIgnoreHiddenAttrib); - char *aBuf = new char[aLen+1]; - if(gLogLevel & LOG_LEVEL_FILE_DETAILS) - { - node->GetFullName(aBuf, aIgnoreHiddenAttrib); - if(node->iEntry->iFileName) - Print(ELog,"%s\t%d\t%s\t%s\n", node->iEntry->iFileName, node->iEntry->RealFileSize(), (node->iHidden || node->iEntry->iHidden)? "hidden":"", aBuf); - else - Print(ELog,"%s\t%s\n", (node->iHidden || node->iEntry->iHidden) ? "hidden":"", aBuf); - } - - if(gLogLevel & LOG_LEVEL_FILE_ATTRIBUTES) - { - if(!node->iHidden && !node->iEntry->iHidden) - Print(ELog, "Device file name: %s\n", aBuf); - if(node->iEntry->iExecutable) - LogExecutableAttributes((E32ImageHeaderV*)(dest-len)); - } - delete[] aBuf; - } - } - return offset - aBaseOffset; // number of bytes used - } - - - - - - -TInt E32Rofs::LayoutDirectory( TRomNode* /*aRootDir*/, TUint aBaseOffset ) - // - // Creates the directory layout but does not write it to the image. - // All directories are given a location in the image. - // Returns the total number of bytes used for the directory (rounded - // up to the nearest word) or a -ve error code. - // - { - TRomNode* node = TRomNode::FirstNode(); - - TUint offset = aBaseOffset; - while( node ) - { - if( node->IsDirectory()) - { - // it is a directory block so we have to give it a location - node->SetImagePosition( offset ); - - // work out how much space it requires for the directory block - TInt dirLen; - TInt fileLen; - TInt err = node->CalculateDirectoryEntrySize( dirLen, fileLen ); - if( err != KErrNone ) - { - return err; - } - Print( ELog, "Directory '%s' @offs=0x%x, size=%d\n", node->iName, offset, dirLen ); - dirLen += (4-dirLen) & 3; // round up to next word boundary - offset += dirLen; - } - - node = node->NextNode(); - } - - TInt totalDirectoryBlockSize = offset - aBaseOffset; // number of bytes used - totalDirectoryBlockSize += (4 - totalDirectoryBlockSize) & 3; // round up - - // Now go round again placing the file blocks - offset = aBaseOffset + totalDirectoryBlockSize; - const TUint fileBlockStartOffset = offset; - node = TRomNode::FirstNode(); - while( node ) - { - if( node->IsDirectory() ) - { - // work out how much space it requires for the file block - TInt dummy; - TInt fileLen; - TInt err = node->CalculateDirectoryEntrySize( dummy, fileLen ); - - if( err != KErrNone ) - { - return fileLen; - } - if( fileLen ) - { - node->SetFileBlockPosition( offset ); - Print( ELog, "File block for dir '%s' @offs=0x%x, size=%d\n", node->iName, offset, fileLen ); - } - - fileLen += (4-fileLen) & 3; // round up to next word boundary - offset += fileLen; - } - - node = node->NextNode(); - } - - TInt totalFileBlockSize = offset - fileBlockStartOffset; // number of bytes used - totalFileBlockSize += (4 - totalFileBlockSize) & 3; // round up - - iTotalDirectoryBlockSize = totalDirectoryBlockSize; - iTotalFileBlockSize = totalFileBlockSize; - - return totalDirectoryBlockSize + totalFileBlockSize; - } - - -TInt E32Rofs::PlaceDirectory( TRomNode* /*aRootDir*/, TUint8* aDestBase ) - // - // Writes the directory into the image. - // Returns KErrNone on success, or error code - // - { - TRomNode* node = TRomNode::FirstNode(); - - while( node ) - { - if( node->IsDirectory() ) - { - TInt err = node->Place( aDestBase ); - if( err != KErrNone ) - { - return err; - } - } - node = node->NextNode(); - } - return KErrNone; - } - -TInt E32Rofs::WriteImage( TInt aHeaderType ) - { - ofstream romFile((const char *)iObey->iRomFileName,ios::binary); - if (!romFile) - return Print(EError,"Cannot open ROM file %s for output\n",iObey->iRomFileName); - Write(romFile, aHeaderType); - romFile.close(); - - return KErrNone; - } - -TRomNode* E32Rofs::CopyDirectory(TRomNode*& aLastExecutable) - { - return iObey->iRootDirectory->CopyDirectory(aLastExecutable); - } - - -void E32Rofs::Write(ofstream &os, TInt aHeaderType) - -// Output a rom image - - { - - switch (aHeaderType) - { - default: - case 0: - Print(EAlways, "\nWriting Rom image without"); - break; - case 2: - Print(EAlways, "\nWriting Rom image with PE-COFF"); - { - unsigned char coffhead[0x58] = {0}; // zero all the elements - - // fill in the constant bits - // this is supposed to be simple, remember - coffhead[1] = 0x0a; - coffhead[2] = 0x01; - coffhead[0x10] = 0x1c; - coffhead[0x12] = 0x0f; - coffhead[0x13] = 0xa1; - coffhead[0x14] = 0x0b; - coffhead[0x15] = 0x01; - coffhead[0x26] = 0x40; - coffhead[0x2a] = 0x40; - coffhead[0x30] = 0x2e; - coffhead[0x31] = 0x74; - coffhead[0x32] = 0x65; - coffhead[0x33] = 0x78; - coffhead[0x34] = 0x74; - coffhead[0x3a] = 0x40; - coffhead[0x3e] = 0x40; - coffhead[0x44] = 0x58; - coffhead[0x54] = 0x20; - - // now fill in the text segment size - *(TUint32 *) (&coffhead[0x18]) = ALIGN4K(iSizeUsed); - *(TUint32 *) (&coffhead[0x40]) = ALIGN4K(iSizeUsed); - - os.write(reinterpret_cast(coffhead), sizeof(coffhead)); - } - break; - } - Print(EAlways, " header to file %s\n", iObey->iRomFileName); - os.write( iData, iSizeUsed ); - } - - -TRomNode* E32Rofs::RootDirectory() - { - return iObey->iRootDirectory; - } -void E32Rofs::SetRootDirectory(TRomNode* aDir) - { - iObey->iRootDirectory = aDir; - } -TText* E32Rofs::RomFileName() - { - return iObey->iRomFileName; - } -TInt E32Rofs::Size() - { - return iSize; - } - -/////////////////// - +/* +* Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include +#include +#include "h_utl.h" +#include +#include +#include "r_obey.h" +#include "r_rofs.h" +#include "r_coreimage.h" +#include "memmap.h" +#include "symbolgenerator.h" +extern TInt gLogLevel; +extern TBool gLowMem; +extern TInt gThreadNum; +extern TBool gGenSymbols; +//////////////////////////////////////////////////////////////////////// + + + +inline TUint32 AlignData(TUint32 anAddr) { + return ((anAddr+0x0f)&~0x0f); +} + + +//////////////////////////////////////////////////////////////////////// + +E32Rofs::E32Rofs(CObeyFile *aObey) +// +// Constructor +// + : iObey( aObey ), iOverhead(0) + { + if(gGenSymbols) + iSymGen = SymbolGenerator::GetInstance(); + else + iSymGen = NULL; + + iSize=aObey->iRomSize; + if(gLowMem) { + iImageMap = new Memmap(); + + if(iImageMap == NULL) { + iSize = 0; + Print(EError, "Out of memory.\n"); + } + else { + iImageMap->SetMaxMapSize(iSize); + if(iImageMap->CreateMemoryMap(0, 0xff) == EFalse) { + iSize = 0; + Print(EError, "Failed to create image map object"); + + iImageMap->CloseMemoryMap(ETrue); + delete iImageMap; + iImageMap = NULL; + } + else { + iData = iImageMap->GetMemoryMapPointer(); + } + } + } + else { + iData=new char [iSize]; + if (iData==NULL) + iSize=0; + HMem::Set(iData, 0xff, iSize); + } + +} + +E32Rofs::~E32Rofs() { + + if(gLowMem) { + iImageMap->CloseMemoryMap(ETrue); + delete iImageMap; + } + else if(iData) + delete []iData; +} + + +TInt E32Rofs::CreateExtension(MRofsImage* aImage) { + + TUint8* addr=(TUint8*)iData; + + TRomNode* pRootDir = aImage->RootDirectory(); + + + const TInt extensionRofsheaderSize = KExtensionRofsHeaderSize; + + // aImage->iSize contains the max size of the core image + + // Layout the directory structure. Does not actually write it + // to the image. Returns the number of bytes used for the directory + // structure within the image. + TInt directoryOffset = extensionRofsheaderSize; + const TInt directorySize = LayoutDirectory( pRootDir, aImage->Size()+directoryOffset ); + if( directorySize <= 0 ) { + Print(EError, "Failed laying out directories - return code %d\n", directorySize); + return KErrGeneral; + } + + // get offset to start of file data, rounded up to next word boundary + TInt offs = extensionRofsheaderSize + directorySize; + const TInt fileDataStartOffset = offs + ( (4 - offs) & 3); + + // Now we traverse the list of entries placing each file + // This updates the directory entries to point to the correct offset + // to the start of the file + const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset + aImage->Size(), aImage->Size()); + if( fileDataSize <= 0 ) { + Print(EError, "Failed placing files - return code %d\n", fileDataSize); + return KErrGeneral; + } + + // and then put the directory into the image + TInt err = PlaceDirectory( pRootDir, addr - aImage->Size() ); // offset pointer by size of core image + if( err != KErrNone ) { + Print(EError, "Failed placing directory - return code %d\n", err); + return err; + } + + directoryOffset+=aImage->Size(); // offset offset by size of core image + // Now write the header + TExtensionRofsHeader * pHeader = (TExtensionRofsHeader*)iData; + pHeader->iIdentifier[0] = 'R'; + pHeader->iIdentifier[1] = 'O'; + pHeader->iIdentifier[2] = 'F'; + pHeader->iIdentifier[3] = 'x'; + pHeader->iHeaderSize = KExtensionRofsHeaderSize; + pHeader->iDirTreeOffset = directoryOffset; + pHeader->iDirTreeSize = iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesSize = iTotalFileBlockSize; + pHeader->iRofsFormatVersion = KRofsFormatVersion; + pHeader->iTime = iObey->iTime; + iSizeUsed = fileDataSize + fileDataStartOffset; + pHeader->iImageSize = iSizeUsed; + if (iObey->AutoSize()) + MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size + pHeader->iMaxImageSize = iSize; + pHeader->iCheckSum = 0; // not used yet + + return KErrNone; +} + +void E32Rofs::MakeAutomaticSize(TUint32 aPageSize) { + TUint32 size = iSizeUsed; + if (iSizeUsed % aPageSize > 0) { + //used size needs to be rounded up to nearest page size + size = (iSizeUsed/aPageSize + 1)*aPageSize; + } + iSize = size; +} + +// +// This is the main entry point to the ROFS image creation +// +TInt E32Rofs::Create() { + TUint8* addr=(TUint8*)iData; + + TRomNode* pRootDir = iObey->iRootDirectory; + const TInt headerSize = KRofsHeaderSize; + // Layout the directory structure. Does not actually write it + // to the image. Returns the number of bytes used for the directory + // structure within the image. + const TInt directoryOffset = headerSize; + const TInt directorySize = LayoutDirectory( pRootDir, directoryOffset ); + if( directorySize <= 0 ) { + Print(EError, "Failed laying out directories - return code %d\n", directorySize); + return KErrGeneral; + } + + // get offset to start of file data, rounded up to next word boundary + TInt offs = headerSize + directorySize; + const TInt fileDataStartOffset = offs + ( (4 - offs) & 3); + + // Now we traverse the list of entries placing each file + // This updates the directory entries to point to the correct offset + // to the start of the file + const TInt fileDataSize = PlaceFiles( pRootDir, addr + fileDataStartOffset, fileDataStartOffset ); + if( fileDataSize < 0 ) { + Print(EError, "Failed placing files - rofssize is too small\n", fileDataSize); + return KErrGeneral; + } + + // and then put the directory into the image + TInt err = PlaceDirectory( pRootDir, addr ); + if( err != KErrNone ) { + Print(EError, "Failed placing directory - return code %d\n", err); + return err; + } + + // Now write the header + TRofsHeader* pHeader = (TRofsHeader*)iData; + pHeader->iIdentifier[0] = 'R'; + pHeader->iIdentifier[1] = 'O'; + pHeader->iIdentifier[2] = 'F'; + pHeader->iIdentifier[3] = 'S'; + pHeader->iHeaderSize = KExtensionRofsHeaderSize; + pHeader->iDirTreeOffset = directoryOffset; + pHeader->iDirTreeSize = iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesOffset = directoryOffset + iTotalDirectoryBlockSize; + pHeader->iDirFileEntriesSize = iTotalFileBlockSize; + pHeader->iRofsFormatVersion = KRofsFormatVersion; + pHeader->iTime = iObey->iTime; + iSizeUsed = fileDataSize + fileDataStartOffset; + pHeader->iImageSize = iSizeUsed; + pHeader->iImageVersion = iObey->iVersion; + if (iObey->AutoSize()) + MakeAutomaticSize(iObey->AutoPageSize()); // change iSize to nearest page size + + pHeader->iMaxImageSize = iSize; + pHeader->iCheckSum = 0; // not used yet + + return KErrNone; +} +void E32Rofs::DisplaySizes(TPrintType aWhere) { + Print(aWhere, "Summary of file sizes in rofs:\n"); + TRomBuilderEntry *file=iObey->FirstFile(); + while(file) { + file->DisplaySize(aWhere); + file=iObey->NextFile(); + } + Print( aWhere, "Directory block size: %d\n" + "File block size: %d\n" + "Total directory size: %d\n" + "Total image size: %d\n", + iTotalDirectoryBlockSize, + iTotalFileBlockSize, + iTotalDirectoryBlockSize + iTotalFileBlockSize, + iSizeUsed ); + +} + +void E32Rofs::LogExecutableAttributes(E32ImageHeaderV *aHdr) { + Print(ELog, "Uids: %08x %08x %08x %08x\n", aHdr->iUid1, aHdr->iUid2, aHdr->iUid3, aHdr->iUidChecksum); + Print(ELog, "Data size: %08x\n", aHdr->iDataSize); + Print(ELog, "Heap min: %08x\n", aHdr->iHeapSizeMin); + Print(ELog, "Heap max: %08x\n", aHdr->iHeapSizeMax); + Print(ELog, "Stack size: %08x\n", aHdr->iStackSize); + Print(ELog, "Secure ID: %08x\n", aHdr->iS.iSecureId); + Print(ELog, "Vendor ID: %08x\n", aHdr->iS.iVendorId); + Print(ELog, "Priority: %d\n\n", aHdr->iProcessPriority); +} +class Worker : public boost::thread { + public: + static void thrd_func(E32Rofs* rofs){ + CBytePair bpe; + + bool deferred = false; + TPlacingSection* p = rofs->GetFileNode(deferred); + while(p) { + if(!deferred) { + p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe); + //no symbol for hidden file + if(rofs->iSymGen && !p->node->iEntry->iHidden) + rofs->iSymGen->AddFile(p->node->iEntry->iFileName,(p->node->iEntry->iCompressEnabled|| p->node->iEntry->iExecutable)); + } + p = rofs->GetFileNode(deferred); + } + rofs->ArriveDeferPoint(); + p = rofs->GetDeferredJob(); + while(p) { + p->len = p->node->PlaceFile(p->buf, (TUint32)-1, 0, &bpe); + p = rofs->GetDeferredJob(); + } + } + Worker(E32Rofs* rofs) : boost::thread(thrd_func,rofs) { + } +}; + +TPlacingSection* E32Rofs::GetFileNode(bool &aDeferred) { + //get a node from the node list, the node list is protected by mutex iMuxTree. + //The iMuxTree also helps to make sure the order in iVPS is consistent with the node list. + //And this is the guarantee of same outputs regardless of how many threads being used. + boost::mutex::scoped_lock lock(iMuxTree); + aDeferred = false; + TRomNode* node = iLastNode; + while(node) { + if( node->IsFile()) { + if(!node->iHidden) { + iLastNode = node->NextNode(); + break; + } + } + node = node->NextNode(); + } + + if(node && node->IsFile() && !node->iHidden) { + TPlacingSection* pps = new TPlacingSection(node); + iVPS.push_back(pps); + if(node->iAlias) { + iQueueAliasNode.push(pps); + aDeferred = true; + } + return pps; + } + return NULL; +} +TPlacingSection* E32Rofs::GetDeferredJob() { + // waiting all the normal node have been placed. + while(iWorkerArrived < gThreadNum) + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + // now we can safely handle the alias nodes. + boost::mutex::scoped_lock lock(iMuxTree); + TPlacingSection* p = NULL; + if(!iQueueAliasNode.empty()) { + p = iQueueAliasNode.front(); + iQueueAliasNode.pop(); + } + return p; +} +void E32Rofs::ArriveDeferPoint() { + boost::mutex::scoped_lock lock(iMuxTree); + ++iWorkerArrived; +} +TInt E32Rofs::PlaceFiles( TRomNode* /*aRootDir*/, TUint8* aDestBase, TUint aBaseOffset, TInt aCoreSize ) + // + // Traverses all entries placing all files and updating directory entry pointers. + // Returns number of bytes placed or -ve error code. + // + { + if(iSymGen) + iSymGen->SetSymbolFileName((const char *)iObey->iRomFileName); + iLastNode = TRomNode::FirstNode(); + iWorkerArrived = 0; + + boost::thread_group thrds; + Worker** workers = new Worker*[gThreadNum]; + int i; + for (i = 0; i < gThreadNum; ++i) { + workers[i] = new Worker(this); + thrds.add_thread(workers[i]); + } + + thrds.join_all(); + delete [] workers; + if(iSymGen) + iSymGen->AddFile("",false); + + TUint offset = aBaseOffset; + TUint8* dest = aDestBase; + TBool aIgnoreHiddenAttrib = ETrue; + TInt len = iVPS.size(); + TInt maxSize; + for(i=0;inode->iFileStartOffset != (TUint)KFileHidden) { + if (iVPS[i]->len > maxSize) { + // Image size is too low to proceed. + return maxSize - iVPS[i]->len; + } + memcpy(dest,iVPS[i]->buf,iVPS[i]->len); + if(iVPS[i]->node->iEntry->iFileOffset == -1) { + iVPS[i]->node->iEntry->iFileOffset = offset; + iVPS[i]->node->iFileStartOffset = iVPS[i]->node->iEntry->iFileOffset; + } + else { + TRomBuilderEntry* aEntry = (TRomBuilderEntry*)(iVPS[i]->node->iFileStartOffset); + iVPS[i]->node->iFileStartOffset = aEntry->iFileOffset; + } + } + iVPS[i]->len += (4-iVPS[i]->len) & 3;// round up to next word boundary + dest += iVPS[i]->len; + offset += iVPS[i]->len; + + if(gLogLevel > DEFAULT_LOG_LEVEL ) + { + TRomNode* node = iVPS[i]->node; + TInt aLen = node->FullNameLength(aIgnoreHiddenAttrib); + char *aBuf = new char[aLen+1]; + if(gLogLevel & LOG_LEVEL_FILE_DETAILS) + { + node->GetFullName(aBuf, aIgnoreHiddenAttrib); + if(node->iEntry->iFileName) + Print(ELog,"%s\t%d\t%s\t%s\n", node->iEntry->iFileName, node->iEntry->RealFileSize(), (node->iHidden || node->iEntry->iHidden)? "hidden":"", aBuf); + else + Print(ELog,"%s\t%s\n", (node->iHidden || node->iEntry->iHidden) ? "hidden":"", aBuf); + } + + if(gLogLevel & LOG_LEVEL_FILE_ATTRIBUTES) + { + if(!node->iHidden && !node->iEntry->iHidden) + Print(ELog, "Device file name: %s\n", aBuf); + if(node->iEntry->iExecutable) + LogExecutableAttributes((E32ImageHeaderV*)(dest-len)); + } + delete[] aBuf; + } + } + return offset - aBaseOffset; // number of bytes used + } + + + + + + +// +// Creates the directory layout but does not write it to the image. +// All directories are given a location in the image. +// Returns the total number of bytes used for the directory (rounded +// up to the nearest word) or a -ve error code. +// +TInt E32Rofs::LayoutDirectory( TRomNode* /*aRootDir*/, TUint aBaseOffset ) { + TRomNode* node = TRomNode::FirstNode(); + + TUint offset = aBaseOffset; + while( node ) { + if( node->IsDirectory()) { + // it is a directory block so we have to give it a location + node->SetImagePosition( offset ); + + // work out how much space it requires for the directory block + TInt dirLen; + TInt fileLen; + TInt err = node->CalculateDirectoryEntrySize( dirLen, fileLen ); + if( err != KErrNone ) { + return err; + } + Print( ELog, "Directory '%s' @offs=0x%x, size=%d\n", node->iName, offset, dirLen ); + dirLen += (4-dirLen) & 3; // round up to next word boundary + offset += dirLen; + } + + node = node->NextNode(); + } + + TInt totalDirectoryBlockSize = offset - aBaseOffset; // number of bytes used + totalDirectoryBlockSize += (4 - totalDirectoryBlockSize) & 3; // round up + + // Now go round again placing the file blocks + offset = aBaseOffset + totalDirectoryBlockSize; + const TUint fileBlockStartOffset = offset; + node = TRomNode::FirstNode(); + while( node ) { + if( node->IsDirectory() ) { + // work out how much space it requires for the file block + TInt dummy; + TInt fileLen; + TInt err = node->CalculateDirectoryEntrySize( dummy, fileLen ); + + if( err != KErrNone ) { + return fileLen; + } + if( fileLen ) { + node->SetFileBlockPosition( offset ); + Print( ELog, "File block for dir '%s' @offs=0x%x, size=%d\n", node->iName, offset, fileLen ); + } + + fileLen += (4-fileLen) & 3; // round up to next word boundary + offset += fileLen; + } + + node = node->NextNode(); + } + + TInt totalFileBlockSize = offset - fileBlockStartOffset; // number of bytes used + totalFileBlockSize += (4 - totalFileBlockSize) & 3; // round up + + iTotalDirectoryBlockSize = totalDirectoryBlockSize; + iTotalFileBlockSize = totalFileBlockSize; + + return totalDirectoryBlockSize + totalFileBlockSize; +} +// +// Writes the directory into the image. +// Returns KErrNone on success, or error code +// + +TInt E32Rofs::PlaceDirectory( TRomNode* /*aRootDir*/, TUint8* aDestBase ) { + TRomNode* node = TRomNode::FirstNode(); + + while( node ) { + if( node->IsDirectory() ) { + TInt err = node->Place( aDestBase ); + if( err != KErrNone ) { + return err; + } + } + node = node->NextNode(); + } + return KErrNone; +} + +TInt E32Rofs::WriteImage( TInt aHeaderType ) { + ofstream romFile((const char *)iObey->iRomFileName,ios_base::binary); + if (!romFile) + return Print(EError,"Cannot open ROM file %s for output\n",iObey->iRomFileName); + Write(romFile, aHeaderType); + romFile.close(); + if(iSymGen) + SymbolGenerator::Release(); + + return KErrNone; +} + +TRomNode* E32Rofs::CopyDirectory(TRomNode*& aLastExecutable) { + return iObey->iRootDirectory->CopyDirectory(aLastExecutable); +} + + +// Output a rom image +void E32Rofs::Write(ofstream &os, TInt aHeaderType) { + + switch (aHeaderType) { + default: + case 0: + Print(EAlways, "\nWriting Rom image without"); + break; + case 2: + Print(EAlways, "\nWriting Rom image with PE-COFF"); { + unsigned char coffhead[0x58] = {0}; // zero all the elements + + // fill in the constant bits + // this is supposed to be simple, remember + coffhead[1] = 0x0a; + coffhead[2] = 0x01; + coffhead[0x10] = 0x1c; + coffhead[0x12] = 0x0f; + coffhead[0x13] = 0xa1; + coffhead[0x14] = 0x0b; + coffhead[0x15] = 0x01; + coffhead[0x26] = 0x40; + coffhead[0x2a] = 0x40; + coffhead[0x30] = 0x2e; + coffhead[0x31] = 0x74; + coffhead[0x32] = 0x65; + coffhead[0x33] = 0x78; + coffhead[0x34] = 0x74; + coffhead[0x3a] = 0x40; + coffhead[0x3e] = 0x40; + coffhead[0x44] = 0x58; + coffhead[0x54] = 0x20; + + // now fill in the text segment size + *(TUint32 *) (&coffhead[0x18]) = ALIGN4K(iSizeUsed); + *(TUint32 *) (&coffhead[0x40]) = ALIGN4K(iSizeUsed); + + os.write(reinterpret_cast(coffhead), sizeof(coffhead)); + } + break; + } + Print(EAlways, " header to file %s\n", iObey->iRomFileName); + os.write( iData, iSizeUsed ); +} + + +TRomNode* E32Rofs::RootDirectory() { + return iObey->iRootDirectory; +} +void E32Rofs::SetRootDirectory(TRomNode* aDir) { + iObey->iRootDirectory = aDir; +} +const char* E32Rofs::RomFileName() const { + return iObey->iRomFileName; +} +TInt E32Rofs::Size() const { + return iSize; +} + +/////////////////// +