fix: stop using "magic" numbers in string operations for the copyannofile2log feature
fix: When using the copylogfromannofile workaround, extract the build ID and build duration and add to the log as these are useful for analysis. The log should now be identical to the stdout file.
fix: Remove extra blank lines from output in copylogfromannofile mode.
/*
* 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());
}
}