imgtools/romtools/readimage/src/image_handler.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 "image_handler.h"
#include "r_obey.h"
#include "r_romnode.h"
#include "r_coreimage.h"
#include "rofs_image_reader.h"
#include "rom_image_reader.h"
#include "e32_image_reader.h"
#include "e32rom.h"
#include "h_ver.h"
#include "sis2iby.h"
#include <time.h>

ECompression gCompress=ECompressionUnknown;
ostream *out = &cout;
string ImageReader::iE32ImgFileName = "";
string ImageReader::iZdrivePath = "";
string ImageReader::iLogFileName = "";
string ImageReader::iPattern = "";

string SisUtils::iOutputPath = ".";
string SisUtils::iExtractPath = ".";

ImageHandler::ImageHandler() : iReader(NULL) ,iOptions(0), iSisUtils(NULL)
{
}

ImageHandler::~ImageHandler()
{
	if(iReader)
		delete iReader;

	if(iSisUtils)
		delete iSisUtils;
}


void ImageHandler::ProcessArgs(int argc, char**argv)
{
	if( argc < 2)
	{
		throw ImageReaderUsageException("", "");
	}

	bool aOutFileGiven = false;
	int aPos = 1;

	while( argc > aPos )
	{
		if(argv[aPos][0] == '-')
		{
			switch(argv[aPos][1])
			{
			case 'd':
			case 'D':
				//dump header info
				iOptions |= DUMP_HDR_FLAG;
				break;
			case 'e':
			case 'E':
				iOptions |= DUMP_E32_IMG_FLAG;
				if(argv[aPos+1])
					ImageReader::iE32ImgFileName = string(argv[aPos+1]);
				else 
					throw ImageReaderUsageException("Usage error", argv[aPos]);
				aPos++;
				break;
			case 'h':
			case 'H':
				PrintUsage();
				exit(EXIT_SUCCESS);
			case 'o':
			case 'O':
				{
					if(argv[aPos][2])
					{
						if((stricmp(argv[aPos],"-OUTDIR")==0))
						{
							if(argv[aPos+1])
							{
								SisUtils::iOutputPath = string(argv[aPos+1]);
							}
							else
								throw ImageReaderUsageException("Usage Error", argv[aPos]);

							aPos++;
						}
						else
							throw ImageReaderUsageException("Usage Error", argv[aPos]);
					}
					else
					{
						aOutFileGiven = true;
						if( argv[aPos+1] )
						{
							// unless using iOutFile.c_str() immediately after 
							// iOutFile = argv[aPos+1];
							// iOutFile will not be assign correctly,
							// is it a defect of gcc 3.4.5 ?
							iOutFile = string(argv[aPos+1]);						
							aPos++;
						}
					}
				}
				break;
			case 'r':
			case 'R':
				{
					if(argv[aPos][2])
						throw ImageReaderUsageException("Usage Error", argv[aPos]);

					iOptions |= RECURSIVE_FLAG;
				}
				break;
			case 's':
			case 'S':
				{
					if(argv[aPos][2])
					{
						if(stricmp(argv[aPos],"-SIS2IBY")==0)
						{
							iOptions |= MODE_SIS2IBY;
						}
						else
							throw ImageReaderUsageException("Usage Error", argv[aPos]);
					}
					else
						iOptions |= DUMP_DIR_ENTRIES_FLAG;
				}
				break;
			case 't':
			case 'T':
				{
					if((stricmp(argv[aPos],"-TMPDIR")==0))
					{
						if(argv[aPos+1])
						{
							SisUtils::iExtractPath = string(argv[aPos+1]);
						}
						else
							throw ImageReaderUsageException("Usage Error", argv[aPos]);

						aPos++;
					}
					else
						throw ImageReaderUsageException("Usage Error", argv[aPos]);
				}
				break;
			case 'v':
			case 'V':
				{
					if(argv[aPos][2])
						throw ImageReaderUsageException("Usage Error", argv[aPos]);

					iOptions |= DUMP_VERBOSE_FLAG;
				}
				break;
			case 'l':
			case 'L':
				{
					if(argv[aPos+1])
					{
						ImageReader::iLogFileName = string(argv[aPos+1]);
					}
					else
						throw ImageReaderUsageException("Usage error", argv[aPos]);
					iOptions |= LOG_IMAGE_CONTENTS_FLAG;
					aPos++;
				}
				break;
			case 'x':
			case 'X':
				{
					if(argv[aPos+1] && (!argv[aPos][2]))
					{
						ImageReader::iPattern = string(argv[aPos+1]);
					}
					else
						throw ImageReaderUsageException("Usage error", argv[aPos]);

					iOptions |= EXTRACT_FILE_SET_FLAG;
					aPos++;
				}
				break;
			case 'z':
			case 'Z':
				{
					if(argv[aPos+1])
						ImageReader::iZdrivePath = string(argv[aPos+1]);
					else
						throw ImageReaderUsageException("Usage error", argv[aPos]);
					
					iOptions |= EXTRACT_FILES_FLAG;
					aPos++;
				}
				break;
			default:
				throw ImageReaderUsageException("Invalid command", argv[aPos]);
				break;
			}
		}
		else
		{
			if(!iInputFileName.empty())
			{
				throw ImageReaderUsageException("Invalid command", "Multiple input file not supported");
			}

			SetInputFile(argv[aPos]);
		}
		aPos++;
	}

	if( aOutFileGiven && !(iOptions & MODE_SIS2IBY) )
	{
		ofstream* rdout = new ofstream(iOutFile.c_str(), ios::out | ios::trunc);
		if( !rdout->is_open()){
			delete rdout ;
			rdout = NULL ;
			throw ImageReaderException((char*)iOutFile.c_str(), "Unable to open File");
		}
		out = rdout ;
	}

	// Disable -z option if -x option is passed
	if( (iOptions & EXTRACT_FILE_SET_FLAG) && (iOptions & EXTRACT_FILES_FLAG) )
	{
		iOptions &= ~(EXTRACT_FILES_FLAG);
	}

	// -r option should be used along with -x option
	if( (iOptions & RECURSIVE_FLAG) && !(iOptions & EXTRACT_FILE_SET_FLAG) )
	{
		throw ImageReaderUsageException("Usage error", "-r should be used with -x");
	}
}

EImageType ImageHandler::ReadMagicWord()
{
 
#if defined(__TOOLS2__) || defined(__MSVCDOTNET__)
	ifstream file(iInputFileName.c_str(), ios_base::in | ios_base::binary );
#else
	ifstream file(iInputFileName.c_str(), ios::in | ios::binary | ios::nocreate);
#endif
	
	EImageType retVal = EUNKNOWN_IMAGE;

	if( !file.is_open() )
	{
		throw ImageReaderException((char*)iInputFileName.c_str(), "Cannot open file ");
	}

	TUint8 magicWords[16];
	file.read(reinterpret_cast<char*>(magicWords),16);

	if(0 == memcmp(magicWords,"ROFS",4)) {		 
		retVal = EROFS_IMAGE; 			
	}else if(0 == memcmp(magicWords,"ROFx",4)) {
		retVal = EROFX_IMAGE;
	}
	else if(0 == memcmp(magicWords,"EPOC",4) && 0 == memcmp(&magicWords[8],"ROM",3) ) {		 
		retVal = EROM_IMAGE; 
	}
	else {
		E32ImageFile	aE32;
		TUint32			aSz;
		file.seekg(0,ios::end);
		aSz = file.tellg();
		file.seekg(0,ios::beg);			 
		aE32.Adjust(aSz);
		aE32.iFileSize = aSz;
		file  >> aE32;
	
		if(aE32.iError == KErrNone){
			retVal = EE32_IMAGE;
		}
		else {
			TExtensionRomHeader exRomHeader;
			file.seekg(0, ios::beg);
			file.read(reinterpret_cast<char*>(&exRomHeader), sizeof(TExtensionRomHeader));
			TUint zeroTime = time(0);
			// aExtensionRomHeader.iTime and aExtensionRomHeader.iKernelTime are 
			// in microseconds. So convert them to seconds and see if these are 
			// valid times e.g. a time(in seconds) after midnight Jan 1st, 1970
			TUint imgTime = exRomHeader.iTime / 1000000;
			TUint kernImgTime = exRomHeader.iKernelTime / 1000000;
			if( imgTime >= zeroTime && kernImgTime >= zeroTime) {
				//Check if the padding in the header has value 0xff
				retVal = EROMX_IMAGE;
				for(int i = sizeof(exRomHeader.iPad) - 1 ; i >= 0 ; i--){
					if(0xff != exRomHeader.iPad[i]){
						retVal = EUNKNOWN_IMAGE;
						break ;
					}
				}  
			}
		}		 
	}   
	
	if(retVal == EUNKNOWN_IMAGE){
		file.seekg(0,ios::beg);
        retVal = ReadBareImage(file);
	}

	file.close();

	return retVal;
}


/**
 * @fn ImageHandler::ReadBareImage
 * @brief this function processes image type under the condition of that if an image is given without header which means the image is not self-described
 * @return type of the image.
 * @note this function is introduced for handling issues raised by DEF129908
 */
EImageType ImageHandler::ReadBareImage(ifstream& aIfs)
{
    TRomHeader romHdr ; 
    aIfs.read(reinterpret_cast<char*>(&romHdr),sizeof(TRomHeader)); 

    return ((romHdr.iRomBase >= KRomBase ) && 
		(romHdr.iRomRootDirectoryList > KRomBase ) &&
       (romHdr.iRomBase < KRomBaseMaxLimit ) && 
	   (romHdr.iRomRootDirectoryList < KRomBaseMaxLimit)) ? EBAREROM_IMAGE : EUNKNOWN_IMAGE;
     
}


void ImageHandler::HandleInputFiles()
{
	if(!(iOptions & MODE_SIS2IBY))
	{
		EImageType imgType = ReadMagicWord();
		
		switch(imgType)
		{
		case EROFS_IMAGE:
		case EROFX_IMAGE:
			iReader = new RofsImageReader((char*)iInputFileName.c_str());
			break;
		case EROM_IMAGE:
			iReader = new RomImageReader((char*)iInputFileName.c_str());
			break;
        case EBAREROM_IMAGE:
            iReader = new RomImageReader((char*)iInputFileName.c_str(), EBAREROM_IMAGE);
            break;
		case EROMX_IMAGE:
			iReader = new RomImageReader((char*)iInputFileName.c_str(), EROMX_IMAGE);
			break;
		case EE32_IMAGE:
			iReader = new E32ImageReader((char*)iInputFileName.c_str());
			break;
		default:
			{
            throw ImageReaderException((char*)iInputFileName.c_str(), "Unknown Type of Image file");
			}
			break;
		}

		if(iReader)
		{
			iReader->ReadImage();
			iReader->ProcessImage();
			iReader->Validate();
			iReader->SetDisplayOptions( iOptions );
			iReader->ExtractImageContents();
			iReader->Dump();
		}
	}
	else
	{
		if(iInputFileName.empty())
		{
			throw SisUtilsException("Usage Error", "No SIS file passed");
		}

		iSisUtils = new Sis2Iby((char*)iInputFileName.c_str());

		if(iSisUtils)
		{
			if(iOptions & DUMP_VERBOSE_FLAG)
			{
				iSisUtils->SetVerboseMode();
			}

			iSisUtils->ProcessSisFile();
			iSisUtils->GenerateOutput();
		}
		else
		{
			throw SisUtilsException("Error:", "Cannot create Sis2Iby object");
		}
	}
}

void ImageHandler::PrintVersion()
{
	*out << "\nReadimage - reader for Rom, Rofs and E32 images V";
	out->width(1);
	*out << MajorVersion << ".";
	out->width(2);
	out->fill('0');
	*out << MinorVersion << " (";
	out->width(3);
	*out << Build  << ") " << endl;
	*out << Copyright;
}

void ImageHandler::PrintUsage()
{
	PrintVersion();
	const char aUsage[] = 
		"Usage: readImage [options] [<-sis2iby> [sis-options]] <filename>\n\n"
		"Options: With no options, it prints the files and directories in image\n"
		"       -o      output file name\n"
		"       -d      dump header information(default)\n"
		"       -s      dump the directory structure\n"
		"       -v      dump image headers and directory structure\n"
		"       -e xxx  dump the xxx e32 image within the entire image when used along with -v or -s option\n"
		"       -h      this message\n"
		"       -z xxx  extract all the file(s) from the given image to xxx location\n"
		"       -l xxx  log the image contents on to xxx file\n"
		"       -x xxx  extract single or set of files as given in xxx from the given image\n"
		"       -r      recursively extract files from the sub-directories when used along with -x option\n\n"
		"SIS-options: Option -sis2iby changes the mode to generate IBY from SIS file\n"
		"       -sis2iby      generates iby file for the given SIS file\n"
		"       -tmpdir xxx   extract all sis file contents to xxx location\n"
		"       -outdir xxx   generates the iby file(s) to xxx location\n"
		"       -v            verbose output\n";
	*out << aUsage << endl;
}

int main(int argc, char** argv)
{
	ImageHandler aIh;
	int retVal = EXIT_SUCCESS;
	try
	{
		aIh.ProcessArgs(argc, argv);
		aIh.HandleInputFiles();
	}
	catch(ImageReaderUsageException& aIre)
	{
		if(argc >= 2)
		{
			//This is a usage error and has to be reported
			//Otherwise, it is called just to display the usage
			aIre.Report();
		}
		aIh.PrintUsage();
		retVal = EXIT_FAILURE;
	}
	catch(ImageReaderException& aIre)
	{
		aIre.Report();
		retVal = EXIT_FAILURE;
	}
	catch(SisUtilsException& aSUe)
	{
		aSUe.Report();
		retVal = EXIT_FAILURE;
	}
	
	if(out != &cout){
		ofstream* rdout = static_cast<ofstream*>(out) ;
		rdout->close() ;
		delete rdout ; 
	}

	return retVal;
}