imgtools/romtools/readimage/src/rofs_image_reader.cpp
author timothy.murphy@nokia.com
Fri, 30 Apr 2010 16:07:17 +0100
branchfix
changeset 511 7581d432643a
parent 0 044383f39525
child 590 360bd6b35136
permissions -rw-r--r--
fix: support new trace compiler features for preventing clashes. Automatically turn on OST_TRACE_COMPILER_IN_USE macro. Look for trace header in systemincludes. Make directories in makefile parse to prevent clashes during build. Correct path for autogen headers. Correct case issue with autogen headers on Linux.

/*
* Copyright (c) 2005-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 "common.h"
#include "r_obey.h"
#include "rofs_image_reader.h"
#include "e32_image_reader.h"

RofsImage::RofsImage(RCoreImageReader *aReader) : CCoreImage(aReader) ,
iRofsHeader(0), iRofsExtnHeader(0),iAdjustment(0),  iImageType(RCoreImageReader::E_UNKNOWN)
{
}

RofsImageReader::RofsImageReader(char* aFile) : ImageReader(aFile), iInputFile(0)
{
	iImageReader = new RCoreImageReader(aFile);
	iImage = new RofsImage(iImageReader);
}

RofsImageReader::~RofsImageReader()
{
	if(iInputFile)
		iInputFile->close();
	delete iInputFile;
	delete iImage;
	delete iImageReader;
}

void RofsImageReader::SetSeek(streampos aOff, ios::seek_dir aStartPos)
{
	if(!iInputFile)
		return;

	iInputFile->seekg(aOff, aStartPos);
}

void RofsImageReader::ReadImage()
{
	if(!iImageReader->Open())
	{
		throw ImageReaderException((char*)(iImageReader->Filename()), "Failed to open Image File");
	}
}

void RofsImageReader::Validate()
{
}

TInt RofsImage::ProcessImage()
{
	int result = CreateRootDir();
	if (result == KErrNone)
	{
		if (iReader->Open())
		{
			iImageType = iReader->ReadImageType();
			if (iImageType == RCoreImageReader::E_ROFS)
			{
				iRofsHeader = new TRofsHeader;
				result = iReader->ReadCoreHeader(*iRofsHeader);
				if (result != KErrNone)
					return result;
				
				SaveDirInfo(*iRofsHeader);
				result = ProcessDirectory(0);
			}
#if defined(__TOOLS2__) || defined(__MSVCDOTNET__)
			else if (iImageType == RCoreImageReader::E_ROFX)
#else
			else if (iImageType == RCoreImageReader::TImageType::E_ROFX)
#endif
			{
				iRofsExtnHeader = new TExtensionRofsHeader ;
				result = iReader->ReadExtensionHeader(*iRofsExtnHeader);
				if(result != KErrNone)
					return result;

				long filePos = iReader->FilePosition();
				iAdjustment = iRofsExtnHeader->iDirTreeOffset - filePos;

				SaveDirInfo(*iRofsExtnHeader);
				result = ProcessDirectory(iAdjustment);
			}
			else
			{
				result = KErrNotSupported;
			}
		}
		else
		{
			result = KErrGeneral;
		}
	}

	return result;
}

void RofsImageReader::ProcessImage()
{
	iImage->ProcessImage();
	iRootDirEntry = iImage->RootDirectory();
}

void RofsImageReader::Dump()
{
	if( !((iDisplayOptions & EXTRACT_FILES_FLAG) || (iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG) ||
		(iDisplayOptions & EXTRACT_FILE_SET_FLAG)) )
	{
		
		MarkNodes();
		if(iDisplayOptions & DUMP_HDR_FLAG)
		{
			DumpHeader();
		}
		if( (iDisplayOptions & DUMP_DIR_ENTRIES_FLAG) ||
			(iDisplayOptions & DUMP_VERBOSE_FLAG) )
		{
			DumpDirStructure();
			DumpFileAttributes();
		}
	}
}

void RofsImageReader::DumpHeader()
{
	*out << "Image Name................." << iImgFileName.c_str() << endl;

	int aPos = 0;

	if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFS)
	{
		*out << "ROFS Image" << endl;

		*out << "Image Signature..........." ;
		while(aPos < K_ID_SIZE)
		{
			*out << ((RofsImage*)iImage)->iRofsHeader->iIdentifier[aPos++];
		}
		*out << endl << endl;

		TUint aTotalDirSz = ((RofsImage*)iImage)->iRofsHeader->iDirTreeSize +
							((RofsImage*)iImage)->iRofsHeader->iDirFileEntriesSize;
		(*out).width(8);

		*out << "Directory block size: 0x" << hex << ((RofsImage*)iImage)->iRofsHeader->iDirTreeSize << endl;
		*out <<	"File block size:      0x" << hex << ((RofsImage*)iImage)->iRofsHeader->iDirFileEntriesSize << endl;
		*out << "Total directory size: 0x" << hex << ( aTotalDirSz ) << endl;
		*out << "Total image size:     0x" << hex << ((RofsImage*)iImage)->iRofsHeader->iImageSize << endl;
	}
	else if(((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
	{
		*out << "Extension ROFS Image" << endl;
		*out << "Image Signature..........." ;
		while(aPos < K_ID_SIZE)
		{
			*out << ((RofsImage*)iImage)->iRofsExtnHeader->iIdentifier[aPos++];
		}
		*out << endl << endl;

		TUint aTotalDirSz = ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeSize +
						((RofsImage*)iImage)->iRofsExtnHeader->iDirFileEntriesSize;
		out->width(8);

		*out << "Directory block size: 0x" << hex << ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeSize << endl;
		*out <<	"File block size:      0x" << hex << ((RofsImage*)iImage)->iRofsExtnHeader->iDirFileEntriesSize << endl;
		*out << "Total directory size: 0x" << hex << ( aTotalDirSz ) << endl;
		*out << "Total image size:     0x" << hex << ((RofsImage*)iImage)->iRofsExtnHeader->iImageSize << endl;
	}
}

void RofsImageReader::DumpDirStructure()
{
	 
	*out << "Directory Listing" << endl;
	*out << "=================" << endl; 
	iImage->Display(out);

}

void RofsImageReader::MarkNodes()
{
	TRomNode *aNode = iRootDirEntry->NextNode();

	while( aNode )
	{
		if(aNode->iEntry)
		{
			if( ReaderUtil::IsExecutable(aNode->iEntry->iUids) )
			{
				aNode->iEntry->iExecutable = true;
			}
			else
			{
				aNode->iEntry->iExecutable = false;
			}
		}
		aNode = aNode->NextNode();
	}
}

void RofsImageReader::DumpFileAttributes()
{
	TRomNode *aNode = iRootDirEntry->NextNode();
	E32ImageFile	aE32Img;
	streampos		aFileOffset;
	string			iPath;
	
	while( aNode )
	{
		if( aNode->IsFile() )
		{
			if( !iInputFile )
			{
				// Open the image file once and to access the E32 images within,#
				// seek to the file offsets...
				iInputFile = new ifstream( (char*)(iImageReader->Filename()), ios::binary|ios::in);
				
				if(!iInputFile->is_open())
				{
					throw ImageReaderException((char*)iImageReader->Filename(), "Failed to open file");
				}
			}

			try 
			{
				if( aNode->iEntry->iExecutable)
				{
					aFileOffset = 0;
					if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
					{
						if((TUint)aNode->iEntry->iFileOffset > ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeOffset)
						{
							//This is set only for files within this extended ROFS
							aFileOffset = aNode->iEntry->iFileOffset - ((RofsImage*)iImage)->iAdjustment;
						}
					}
					else
					{
						//This is set only for files within ROFS
						aFileOffset = aNode->iEntry->iFileOffset;
					}

					if( aFileOffset )
					{
						SetSeek(aFileOffset , ios::beg);
						memset(&aE32Img, 0, sizeof(aE32Img));
						aE32Img.Adjust(aNode->iSize);
						aE32Img.iFileSize = aNode->iSize;
						if( iInputFile->fail())
						{
							// Check why is the fail bit set causing all subsequent
							// istream operations to fail.
							// For now, clear the fail bit...
							iInputFile->clear();
						}
						*iInputFile >> aE32Img;
						if(aE32Img.iError != KErrNone)
						{
							throw int (0);
						}
					}
				}
			}
			catch(...)
			{
				// Just in case this was't a valid E32 image and the E32 reader didn't 
				// catch it...
				
				string aStr("Failed to read contents of ");
				aStr.append((char*)aNode->iName);

				throw ImageReaderException((char*)iImageReader->Filename(), (char*)aStr.c_str());
			}

			*out << "********************************************************************" << endl;
			iPath.assign((char*)aNode->iName);	
			GetCompleteNodePath(aNode,iPath,"/");
			*out << "File........................" << iPath.c_str() << endl;
			if( aNode->iEntry->iExecutable )
			{
				if(aFileOffset)
				{
					// When its an E32 Image...
					E32ImageReader::DumpE32Attributes(aE32Img);
					if( iDisplayOptions & DUMP_E32_IMG_FLAG){
						if(stricmp(iE32ImgFileName.c_str(), (const char*)aNode->iName) == 0){
							TUint aSectionOffset = aE32Img.iOrigHdr->iCodeOffset;
							TUint* aCodeSection = (TUint*)(aE32Img.iData + aSectionOffset);
							*out << "\nCode (Size=0x" << hex << aE32Img.iOrigHdr->iCodeSize << ")" << endl;
							DumpData(aCodeSection, aE32Img.iOrigHdr->iCodeSize);

							aSectionOffset = aE32Img.iOrigHdr->iDataOffset;
							TUint* aDataSection = (TUint*)(aE32Img.iData + aSectionOffset);
							if( aE32Img.iOrigHdr->iDataSize){
								*out << "\nData (Size=0x" << hex << aE32Img.iOrigHdr->iDataSize << ")" << endl;
								DumpData(aDataSection, aE32Img.iOrigHdr->iDataSize);
							}
						}
					}
				}
				else
				{
					*out << "Image "<< aNode->iName << " not in the extended ROFS " << iImgFileName.c_str() << endl;
				}
			}
		}

		aNode = aNode->NextNode();
	}
}


/** 
Function iterates through all the entries in the image.If the entry is a file,
then it makes a call to GetFileExtension to check for the extension.

@internalComponent
@released
*/
void RofsImageReader::ExtractImageContents()
{
	if( (iDisplayOptions & EXTRACT_FILE_SET_FLAG) )
	{
		ImageReader::ExtractFileSet(NULL);
	}

	if( iDisplayOptions & EXTRACT_FILES_FLAG || iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG  )
	{
		// get the next Node 
		TRomNode *nextNode = iRootDirEntry->NextNode();
		// current Node.
		TRomNode *currNode = iRootDirEntry;
		// name of the log file.
		string  logFile;
		// output stream for the log file.
		ofstream oFile;

		if( iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG ){		 
			if( ImageReader::iZdrivePath.compare("")){
				// create a string to hold path information.
				string filePath;
				string delimiter;
				delimiter.assign("\\");
				filePath.assign( ImageReader::iZdrivePath );
				// replace backslash with double backslash. 
				FindAndInsertString(filePath,delimiter,delimiter);
				logFile.assign(filePath);
				// create specified directory.
				CreateSpecifiedDir(&filePath[0],"\\\\");
				logFile.append("\\\\");
				logFile.append(ImageReader::iLogFileName);
			}
			else {				
				logFile.assign(ImageReader::iLogFileName);
			}

			// open the specified file in append mode.
			oFile.open(logFile.c_str(),ios::out|ios::app);

			if(!oFile.is_open()) {
				throw ImageReaderException((char*)ImageReader::iLogFileName.c_str(), "Failed to open the log file");
			}
		}

		while( nextNode ){
			if(nextNode->IsDirectory())	{
				// if next node is a directory set current node as next node.
				currNode = nextNode;
			}
			else {
				// get file extension
				CheckFileExtension((char*) nextNode->iName,nextNode->iEntry,currNode,oFile);
			}
			nextNode = nextNode->NextNode();
		}

		if(oFile.is_open()) oFile.close(); 

	}
}


/** 
Function to get check extension of the given file.If the extension of the file is "sis"
then call ExtractFile function to extract the file from the image.  

@internalComponent
@released

@param aFile	- file name. 
@param aEntry	- entry of the file in image.
@param aNode	- current node.
@param aLogFile	- output stream.
*/
void RofsImageReader::CheckFileExtension(char* aFileName,TRomBuilderEntry* aEntry,TRomNode* aNode,ofstream& aLogFile)
{
	//create a string to hold path information.
	string path;
	// check whether the node has parent 
	if(aNode->GetParent())
	{
		// get the complete path 
		path.assign( (char*)aNode->iName );
		GetCompleteNodePath( aNode, path, "\\\\" );
	}
	else
	{
		// else path is the current path
		path.assign("");
	}
	if( iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG && iDisplayOptions & EXTRACT_FILES_FLAG )
	{
	 
		size_t pos = string(aFileName).find_last_of(".");

		const char* extName = "";
		if(pos != string::npos)
			extName = aFileName + pos + 1;	 
		if ( 0 == stricmp(extName,"SIS") || 0 == stricmp(extName,"DAT")) {
			// if the two strings are same then extract the corresponding file.
			ImageReader::ExtractFile(aEntry->iFileOffset,aEntry->RealFileSize(),aFileName,path.c_str(),&ImageReader::iZdrivePath[0]);
		}
		else {
			// log the entry path information on to the specified file.
			WriteEntryToFile(aFileName,aNode,aLogFile);
		}	 
	}
	else if( iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG ) {
		// log the entry path information on to the specified file.
		WriteEntryToFile(aFileName,aNode,aLogFile);
	}
	else {
		// if the two strings are same then extract the corresponding file.
		ImageReader::ExtractFile(aEntry->iFileOffset,aEntry->RealFileSize(),aFileName,path.c_str(),&ImageReader::iZdrivePath[0]);
	}
}

/** 
Function to get the complete path information of a file from an image.

@internalComponent
@released

@param aNode	- starting offset of the file in the image.
@param aName	- name of the current entry in the image.
@param aAppStr	- string to append.
@return - returns full path of the given file.
*/
void RofsImageReader::GetCompleteNodePath(TRomNode* aNode,string& aName,char* aAppStr)
{
	// check if the entry has a parent.
	TRomNode* NodeParent = aNode->GetParent();
	if(NodeParent)
	{
		string str( (char*)NodeParent->iName );
		str.append( aAppStr );
		str.append( aName );
		aName = str;
		GetCompleteNodePath(NodeParent,aName,aAppStr);
	}
}


/** 
Function to write the rom entry to an output stream.

@internalComponent
@released

@param aNode		- starting offset of the file in the image.
@param aFileName	- name of the current entry in the image.
@param aLogFile		- output stream.
*/
void RofsImageReader::WriteEntryToFile(char* aFileName,TRomNode* aNode,ofstream& aLogFile)
{
	//create a string to hold path information.
	string path;
	
	if(aNode->GetParent())
	{
		// get the complete path 
		path.assign( (char*)aNode->iName );
		GetCompleteNodePath( aNode, path, "\\" );
	}
	else
	{
		// else path is the current path
		path.assign("");
	}
	
	if(aLogFile.is_open())
	{
		aLogFile.seekp(0,ios::end);
		aLogFile<<path.c_str()<<"\\"<<aFileName<<"\n";
	}
}

/** 
Function to get the directory structure information.

@internalComponent
@released

@param aFileMap		- map of filename with its size and offset values.
*/
void RofsImageReader::GetFileInfo(FILEINFOMAP &aFileMap)
{
	// get the next Node 
	TRomNode *nextNode = iRootDirEntry->NextNode();
	// current Node.
	TRomNode *currNode = iRootDirEntry;
	// image size
	TUint32 imgSize = GetImageSize();

	while(nextNode)
	{
		if(nextNode->IsDirectory())
		{
			// if next node is a directory set current node as next node.
			currNode = nextNode;
		}
		else
		{
			PFILEINFO fileInfo = new FILEINFO;
			//create a string to hold path information.
			string fileName;
			TUint32 aFileOffset = 0;

			// check whether the node has parent 
			if(currNode->GetParent())
			{
				if( !((currNode->GetParent() == currNode->FirstNode()) && !(currNode->IsDirectory())) )
				{
					// get the complete path 
					fileName.assign( (char*)currNode->iName );
					GetCompleteNodePath( currNode, fileName, (char*)DIR_SEPARATOR );
				}
			}
			else
			{
				// else path is the current path
				fileName.assign("");
			}
			fileName.append(DIR_SEPARATOR);
			fileName.append((char*)nextNode->iName);

			// get the size of the entity.
			fileInfo->iSize = nextNode->iEntry->RealFileSize();

			// get the offset of the entity.
			if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
			{
				if((TUint)nextNode->iEntry->iFileOffset > ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeOffset)
				{
					//This is set only for files within this extended ROFS
					aFileOffset = nextNode->iEntry->iFileOffset - ((RofsImage*)iImage)->iAdjustment;
				}
			}
			else
			{
				//This is set only for files within ROFS
				aFileOffset = nextNode->iEntry->iFileOffset;
			}

			fileInfo->iOffset = aFileOffset;

			if((!fileInfo->iOffset) || ((fileInfo->iOffset + fileInfo->iSize) > imgSize))
			{
				fileInfo->iOffset = 0;
				fileInfo->iSize = 0;
			}

			aFileMap[fileName] = fileInfo;
		}

		nextNode = nextNode->NextNode();
	}
}

/** 
Function to get the ROFS image size.

@internalComponent
@released
*/
TUint32 RofsImageReader::GetImageSize()
{
	TUint32 result = 0;

	if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFS)
	{
		result = ((RofsImage*)iImage)->iRofsHeader->iImageSize;
	}
	else if(((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
	{
		result = ((RofsImage*)iImage)->iRofsExtnHeader->iImageSize;
	}

	return result;
}