// 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 "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:
// e32tools/e32image/e32image.cpp
// Basic operations on E32Image files which are used by ROMBUILD.
// These are independent of the original file format from which the
// E32Image file was derived.
// 
//

#include <time.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include "h_utl.h"


#if defined (__MSVCDOTNET__) || defined(__TOOLS2__)
#include <fstream>
#else //!__MSVCDOTNET__
#include <fstream.h>
#endif //__MSVCDOTNET__

#include <assert.h>
#ifndef __LINUX__
  #include <io.h>
#endif
#include "h_ver.h"

// get E32ImageHeader class...
#define INCLUDE_E32IMAGEHEADER_IMPLEMENTATION
#define RETURN_FAILURE(_r) return (fprintf(stderr, "line %d\n", __LINE__),_r)
//#define E32IMAGEHEADER_TRACE(_t) printf _t
#include "e32image.h"
#include "byte_pair.h"

void DeflateCompress(char* bytes, TInt size, ostream& os);
void InflateUnCompress(unsigned char* source, int sourcesize, unsigned char* dest, int destsize);
void CompressPages(TUint8 * bytes, TInt size, ostream &os, CBytePair *aBPE);
int  DecompressPages(TUint8 * bytes, istream& is, CBytePair *aBPE);

// needed by E32ImageHeaderV::ValidateHeader...
void Mem::Crc32(TUint32& aCrc, const TAny* aPtr, TInt aLength)
	{
	HMem::Crc32(aCrc, aPtr, aLength);
	}

//
// E32 Image files
//
E32ImageFile::E32ImageFile()
	: iData(NULL), iSize(0), iOrigHdr(NULL), iHdr(NULL), iFileName(NULL)
#ifndef __LINUX__
	  , iWideFileName(NULL)
#endif
, iError(0), iSource(EE32Image), iOrigHdrOffsetAdj(0), iExportBitMap(0)
	{}

E32ImageFile::~E32ImageFile()
	{

	free(iData);
	delete [] iFileName;
#ifndef __LINUX__
	delete [] iWideFileName;
#endif
	if (iHdr && iHdr != iOrigHdr)
		delete iHdr;
	free(iExportBitMap);
	}

// dummy implementation
TBool E32ImageFile::Translate(const char*, TUint, TBool, TBool)
	{
	return EFalse;
	}

Int64 timeToInt64(TInt aTime)
	{
	aTime-=(30*365*24*60*60+7*24*60*60);	// seconds since midnight Jan 1st, 2000
	Int64 daysTo2000AD=730497;
	Int64 t=daysTo2000AD*24*3600+aTime;	// seconds since 0000
	t=t+3600;								// BST (?)
	return t*1000000;						// milliseconds
	}

class TE32ImageUids : public TCheckedUid
	{
public:
	TE32ImageUids(TUint32 aUid1, TUint32 aUid2, TUint32 aUid3) : TCheckedUid(TUidType(TUid::Uid(aUid1), TUid::Uid(aUid2), TUid::Uid(aUid3))) {}
	TUint Check() { return TCheckedUid::Check(); }
	};

void E32ImageFile::SetDefaultHeader()
	{
	iHdr = (E32ImageHeaderV*)iOrigHdr;
	iHdr->iUid1 = 0;
	iHdr->iUid2 = 0;
	iHdr->iUid3 = 0;
	iHdr->iHeaderCrc = 0;
	iHdr->iSignature = 0x434f5045u;
	iHdr->iModuleVersion = 0x00010000u;
	iHdr->iCompressionType = 0;
	iHdr->iToolsVersion = TVersion(MajorVersion, MinorVersion, Build);
	Int64 time1(timeToInt64(time(0))); 
	iHdr->iTimeLo=(TUint32)time1;
	iHdr->iTimeHi=(TUint32)(time1>>32);
	iHdr->iFlags = KImageHdrFmt_V;
	iHdr->iCodeSize = 0;
	iHdr->iDataSize = 0;
	iHdr->iHeapSizeMin = 0;
	iHdr->iHeapSizeMax = 0;
	iHdr->iStackSize = 0;
	iHdr->iBssSize = 0;
	iHdr->iEntryPoint = 0;
	iHdr->iCodeBase = 0;
	iHdr->iDataBase = 0;
	iHdr->iDllRefTableCount = 0;
	iHdr->iExportDirOffset = 0;
	iHdr->iExportDirCount = 0;
	iHdr->iTextSize = 0;
	iHdr->iCodeOffset = 0;
	iHdr->iDataOffset = 0;
	iHdr->iImportOffset = 0;
	iHdr->iCodeRelocOffset = 0;
	iHdr->iDataRelocOffset = 0;
	iHdr->iProcessPriority = (TUint16)EPriorityForeground;
	iHdr->iUncompressedSize = 0;
	iHdr->iS.iSecureId = 0;
	iHdr->iS.iVendorId = 0;
	iHdr->iExceptionDescriptor = 0;
	iHdr->iSpare2 = 0;

	iHdr->iExportDescSize = 0;
	iHdr->iExportDescType = KImageHdr_ExpD_NoHoles;
	iHdr->iExportDesc[0] = 0;
	}

void E32ImageFile::SetCallEntryPoints(TInt aBool)
	{

	if (aBool)
		iHdr->iFlags&=~KImageNoCallEntryPoint;
	else
		iHdr->iFlags|=KImageNoCallEntryPoint;
	}

void E32ImageFile::SetFixedAddress(TInt aBool)
	{

	if (aBool)
		iHdr->iFlags|=KImageFixedAddressExe;
	else
		iHdr->iFlags&=~KImageFixedAddressExe;
	}

void E32ImageFile::SetPriority(TProcessPriority aPri)
	{

	iHdr->iProcessPriority = (TUint16)aPri;
	}

void E32ImageFile::SetCapability(SCapabilitySet& aCapabilities)
	{
	iHdr->iS.iCaps = aCapabilities;
	}

void E32ImageFile::SetFPU(unsigned int aFPU)
	{
	iHdr->iFlags &=~ KImageHWFloatMask;

	if (aFPU == 1)
		iHdr->iFlags |= KImageHWFloat_VFPv2;
	}

void E32ImageFile::Adjust(TInt aSize, TBool aAllowShrink)
//
// Adjust the size of allocated data and fix the member data
//
	{

	TInt asize = ALIGN4(aSize);
	if (asize == iSize)
		return;
	if (iSize == 0)
		{
		iSize = asize;
		iData = (char*)malloc(iSize);
		memset(iData, 0, iSize);
		}
	else if (aAllowShrink || asize > iSize)
		{
		TInt oldsize = iSize;
		iSize = asize;
		iData = (char*)realloc(iData, iSize);
		if (iSize > oldsize)
			memset(iData+oldsize, 0, iSize-oldsize);
		}
	if (!iData)
		iSize = 0;
	if (iHdr && iHdr == iOrigHdr)
		iHdr = (E32ImageHeaderV*)iData;
	iOrigHdr = (E32ImageHeader*)iData;
	}

TInt E32ImageFile::ReadHeader(ifstream& is)
	{
	Adjust(sizeof(E32ImageHeader), EFalse);
	is.read(iData, sizeof(E32ImageHeader));
	TInt hdrsz = iOrigHdr->TotalSize();
	if (hdrsz > 0x10000 || hdrsz <= 0)
		return KErrCorrupt;	// sanity check
	if (hdrsz > (TInt)sizeof(E32ImageHeader))
		{
		Adjust(hdrsz, EFalse);
		is.read(iData+sizeof(E32ImageHeader), hdrsz-sizeof(E32ImageHeader));
		}
	TUint32 uncompressedSize;
	TInt r = iOrigHdr->ValidateHeader(iFileSize,uncompressedSize);
	if (r != KErrNone)
		{
		fprintf(stderr, "Integrity check failed %d\n", r);
		return r;
		}
	iHdr = (E32ImageHeaderV*)iOrigHdr;
	return KErrNone;
	}

void E32ImageFile::SetStackSize(TInt aSize)
	{
	iHdr->iStackSize=aSize;
	}

void E32ImageFile::SetHeapSizeMin(TInt aSize)
	{
	iHdr->iHeapSizeMin=aSize;
	}

void E32ImageFile::SetHeapSizeMax(TInt aSize)
	{
	iHdr->iHeapSizeMax=aSize;
	}

TUint E32ImageFile::TextOffset()
//
// Return the offset of the text section
//
	{
	return 0;
	}

TUint E32ImageFile::DataOffset()
//
// return the offset of the initialised data
//
	{
	return iHdr->iCodeSize;
	}

TUint E32ImageFile::BssOffset()
//
// return the offset from the start of code where the bss is linked
//
	{
	return DataOffset()+iHdr->iDataSize;
	}


TInt E32ImageFile::IsDll()
//
//
//
	{
	return iHdr->iFlags&KImageDll;
	}


void E32ImageFile::RelocateSection(char* aPtr, char* aRelocs, TUint aCodeDelta, TUint aDataDelta, char* aImagePtr, TLinAddr** aIATRefs, TBool keepIAT)
//
// Relocates the section data at aPtr
//	
	{

	TUint codeStart=iHdr->iCodeBase;
	TUint codeFinish=codeStart+iHdr->iCodeSize;
	TUint iatStart = aIATRefs ? codeStart+iHdr->iTextSize : 0;
	TUint iatFinish = aIATRefs ? iatStart+NumberOfImports()*sizeof(TUint) : 0;
//	Print(ELog,"IAT: %x->%x\n",iatStart,iatFinish);
	char* relocs=aRelocs;
	TUint page=0;
	TInt size=0;
	TInt i=((E32RelocSection *)relocs)->iNumberOfRelocs;
	relocs+=sizeof(E32RelocSection);
	while (i>0)
		{
		if (size>0)
			{
			TUint offset=*(TUint16 *)relocs;
			relocs+=2;
			if (offset!=0)
				{ // its a reloc
				TUint va=page+(offset&0x0fff);
				TUint relocType=offset&0xf000;
				TUint *dataptr=(TUint *)(aPtr+va);
				assert((char *)dataptr < aRelocs);
				TUint data=*dataptr;
//				Print(ELog,"data %x\n",data);
				if (relocType == KTextRelocType) 
					*dataptr=data+aCodeDelta; // points to text/rdata section
				else if (relocType == KDataRelocType)
					*dataptr=data+aDataDelta;
				else 
					{
					if (relocType != KInferredRelocType)
						Print(EError,"Unrecognized relocation type %x\n",relocType);

					if (data>=iatStart && data<iatFinish)
						{

						TUint iatNum = (data-iatStart)/sizeof(TLinAddr);

						// If "keepIAT" is used then the importing instruction must import through the IAT entry,
						// but otherwise we change the IAT entry to point to the bit of code doing the importing
						// and do the real fix-up later on in TRomBuilderEntry::FixupImports.
						// NB: We always want to do this for X86 or data exports dont work.
						if (keepIAT || (iHdr->iCpuIdentifier & 0x1000) /*denotes X86*/) 
							*dataptr=data+aCodeDelta; 
						else 
							{
							if ((TUint)aIATRefs[iatNum]>65535)
								Print(EWarning, "Multiple relocations for IAT entry %d (0x%x, 0x%x)\n",
										iatNum, aIATRefs[iatNum], dataptr);
							else
								aIATRefs[iatNum] = (TLinAddr*)(aImagePtr+va);	// ROM image address of importing pointer					
							}
						}
					else if (data>=codeStart && data<codeFinish)
						*dataptr=data+aCodeDelta; // points to text/rdata section
					else
						*dataptr=data+aDataDelta; // points to data section
					}
				--i;
				}
			size-=2;
			}
		else
			{ // next page of relocs
			page=*(TUint *)relocs;
			relocs+=4;
			size=*(TUint *)relocs;
			relocs+=4;
			size-=8;
			}
		}
	}

void E32ImageFile::SetUids(TUid aUid1, TUid aUid2, TUid aUid3)
	{
	iHdr->iUid1=aUid1.iUid;
	iHdr->iUid2=aUid2.iUid;
	iHdr->iUid3=aUid3.iUid;
	}

void E32ImageFile::SetSecureId(TUint32 aId)
	{
	((E32ImageHeaderV*)iHdr)->iS.iSecureId = aId;
	}

void E32ImageFile::SetVendorId(TUint32 aId)
	{
	((E32ImageHeaderV*)iHdr)->iS.iVendorId = aId;
	}

void E32ImageFile::UpdateHeaderCrc()
	{
	TE32ImageUids u(iHdr->iUid1, iHdr->iUid2, iHdr->iUid3);
	iHdr->iUidChecksum = u.Check();
	TInt hdrsz = iHdr->TotalSize();
	TInt orighdrsz = iOrigHdr->TotalSize();
	iHdr->iUncompressedSize = iSize - orighdrsz;
	iHdr->iHeaderCrc = KImageCrcInitialiser;
	TUint32 crc = 0;
	HMem::Crc32(crc, iHdr, hdrsz);
	iHdr->iHeaderCrc = crc;
	}

TInt E32ImageFile::NumberOfImports()
//
// Return the number of imports made by this image
//
	{

	if (iHdr->iDllRefTableCount==0 || iHdr->iImportOffset==0)
		return 0;

	TUint impfmt = iHdr->ImportFormat();
	const E32ImportSection* isection = (const E32ImportSection*)(iData + iOrigHdr->iImportOffset);
	TInt d;
	TInt nImports = 0;
	const E32ImportBlock* b = (const E32ImportBlock*)(isection+1);
	for (d=0; d<iHdr->iDllRefTableCount; d++)
		{
		nImports += b->iNumberOfImports;
		b = b->NextBlock(impfmt);
		}

	if (impfmt==KImageImpFmt_PE || impfmt==KImageImpFmt_PE2)
		{
		TUint *imports=(TUint *)(iData + iOrigHdr->iCodeOffset + iHdr->iTextSize);
		TInt i=0;
		while (*imports++)
			i++;
		assert(i==nImports);
		}
	
	return nImports;
	}

// Work out which exports are missing from the export directory
void E32ImageFile::CreateExportBitMap()
	{
	TInt nexp = iOrigHdr->iExportDirCount;
	TInt memsz = (nexp + 7) >> 3;
	iExportBitMap = (TUint8*)malloc(memsz);
	memset(iExportBitMap, 0xff, memsz);
	TUint* exports = (TUint*)(iData + iOrigHdr->iExportDirOffset);
	TUint absoluteEntryPoint = iOrigHdr->iEntryPoint + iOrigHdr->iCodeBase;
	TUint impfmt = iOrigHdr->ImportFormat();
	TUint hdrfmt = iOrigHdr->HeaderFormat();
	TUint absentVal = (impfmt == KImageImpFmt_ELF) ? absoluteEntryPoint : iOrigHdr->iEntryPoint;
	TInt i;
	iMissingExports = 0;
	for (i=0; i<nexp; ++i)
		{
		if (exports[i] == absentVal)
			{
			iExportBitMap[i>>3] &= ~(1u << (i & 7));
			++iMissingExports;
			}
		}
	if (hdrfmt < KImageHdrFmt_V && iMissingExports)
		{
		fprintf(stderr, "Bad exports\n");
		exit(999);
		}
	}

// Append an export description to the E32ImageHeader if necessary
void E32ImageFile::AddExportDescription()
	{
	if (iMissingExports == 0)
		return;	// nothing to do
	TInt nexp = iOrigHdr->iExportDirCount;
	TInt memsz = (nexp + 7) >> 3;	// size of complete bitmap
	TInt mbs = (memsz + 7) >> 3;	// size of meta-bitmap
	TInt nbytes = 0;
	TInt i;
	for (i=0; i<memsz; ++i)
		if (iExportBitMap[i] != 0xff)
			++nbytes;				// number of groups of 8
	TUint8 edt = KImageHdr_ExpD_FullBitmap;
	TInt extra_space = memsz - 1;
	if (mbs + nbytes < memsz)
		{
		edt = KImageHdr_ExpD_SparseBitmap8;
		extra_space = mbs + nbytes - 1;
		}
	extra_space = (extra_space + sizeof(TUint) - 1) &~ (sizeof(TUint) - 1);
	TInt hdrsz = sizeof(E32ImageHeaderV) + extra_space;
	iHdr = (E32ImageHeaderV*)malloc(hdrsz);
	memcpy(iHdr, iOrigHdr, sizeof(E32ImageHeaderV));
	iHdr->iExportDescType = edt;
	if (edt == KImageHdr_ExpD_FullBitmap)
		{
		iHdr->iExportDescSize = (TUint16)memsz;
		memcpy(iHdr->iExportDesc, iExportBitMap, memsz);
		}
	else
		{
		iHdr->iExportDescSize = (TUint16)(mbs + nbytes);
		memset(iHdr->iExportDesc, 0, extra_space + 1);
		TUint8* mptr = iHdr->iExportDesc;
		TUint8* gptr = mptr + mbs;
		for (i=0; i<memsz; ++i)
			{
			if (iExportBitMap[i] != 0xff)
				{
				mptr[i>>3] |= (1u << (i&7));
				*gptr++ = iExportBitMap[i];
				}
			}
		}
	iHdr->iCodeOffset += extra_space;
	if (iHdr->iDataOffset)
		iHdr->iDataOffset += extra_space;
	if (iHdr->iCodeRelocOffset)
		iHdr->iCodeRelocOffset += extra_space;
	if (iHdr->iDataRelocOffset)
		iHdr->iDataRelocOffset += extra_space;
	if (iHdr->iImportOffset)
		iHdr->iImportOffset += extra_space;
	if (iHdr->iExportDirOffset)
		iHdr->iExportDirOffset += extra_space;
	}

// Check the export description is consistent with the export directory
TInt E32ImageFile::CheckExportDescription()
	{
	TUint hdrfmt = iOrigHdr->HeaderFormat();
	if (hdrfmt < KImageHdrFmt_V && iMissingExports)
		return KErrCorrupt;
	if (iHdr->iExportDescType == KImageHdr_ExpD_NoHoles)
		{
		return iMissingExports ? KErrCorrupt : KErrNone;
		}
	TInt nexp = iOrigHdr->iExportDirCount;
	TInt memsz = (nexp + 7) >> 3;	// size of complete bitmap
	TInt mbs = (memsz + 7) >> 3;	// size of meta-bitmap
	TInt eds = iHdr->iExportDescSize;
	if (iHdr->iExportDescType == KImageHdr_ExpD_FullBitmap)
		{
		if (eds != memsz)
			return KErrCorrupt;
		if (memcmp(iHdr->iExportDesc, iExportBitMap, eds) == 0)
			return KErrNone;
		return KErrCorrupt;
		}
	if (iHdr->iExportDescType != KImageHdr_ExpD_SparseBitmap8)
		return KErrNotSupported;
	TInt nbytes = 0;
	TInt i;
	for (i=0; i<memsz; ++i)
		if (iExportBitMap[i] != 0xff)
			++nbytes;				// number of groups of 8
	TInt exp_extra = mbs + nbytes;
	if (eds != exp_extra)
		return KErrCorrupt;
	const TUint8* mptr = iHdr->iExportDesc;
	const TUint8* gptr = mptr + mbs;
	for (i=0; i<memsz; ++i)
		{
		TUint mbit = mptr[i>>3] & (1u << (i&7));
		if (iExportBitMap[i] != 0xff)
			{
			if (!mbit || *gptr++ != iExportBitMap[i])
				return KErrCorrupt;
			}
		else if (mbit)
			return KErrCorrupt;
		}
	return KErrNone;
	}


TInt E32ImageFile::Validate()
	{
	TInt orighdrsz = iOrigHdr->TotalSize();
	TInt r = iHdr->ValidateWholeImage(iData+orighdrsz,iSize-orighdrsz);
	if(r!=KErrNone)
		return r;
	return r;
	}


ostream& operator<<(ostream& os, const E32ImageFile& aImage)
//
// Output an E32ImageFile
//
	{
            CBytePair bpe(EFalse);
	E32ImageHeaderV* h = aImage.iHdr;
	TUint hdrfmt = h->HeaderFormat();
	if (hdrfmt != KImageHdrFmt_V)
		return os;	// don't generate old binary formats
	TInt hdrsz = h->TotalSize();
	TInt orighdrsz = aImage.iOrigHdr->TotalSize();

	os.write((const char*)aImage.iHdr, hdrsz);

	TUint compression = h->CompressionType();
	if (compression == KUidCompressionDeflate)
		{
		int srcsize = aImage.iSize - orighdrsz;
		DeflateCompress(aImage.iData + orighdrsz, srcsize, os);
		}
	else if (compression == KUidCompressionBytePair)
		{
		// Compress and write out code part
		int srcStart = orighdrsz;
		CompressPages( (TUint8*)aImage.iData + srcStart, aImage.iOrigHdr->iCodeSize, os, &bpe);
		
		
		// Compress and write out data part
		srcStart += aImage.iOrigHdr->iCodeSize;
		int srcLen = aImage.iSize - srcStart;
		//Print(EWarning," Data part start:0x%08x, len:%d (0x%08x)\n", srcStart, aImage.iOrigHdr->iDataSize, aImage.iOrigHdr->iDataSize);
		//CompressPages((TUint8*)aImage.iData + srcStart, aImage.iOrigHdr->iDataSize, os);		

		CompressPages((TUint8*)aImage.iData + srcStart, srcLen, os, &bpe);		

		}
	else if (compression == KFormatNotCompressed)
		{
		int srcsize = aImage.iSize - orighdrsz;
		os.write(aImage.iData + orighdrsz, srcsize); // image not to be compressed
		}
	return os;
	}

ifstream& operator>>(ifstream& is, E32ImageFile& aImage)
//
// Input an E32ImageFile
//
	{
            CBytePair bpe(EFalse);
	aImage.iError = aImage.ReadHeader(is);
	if (aImage.iError != KErrNone)
		return is;
	E32ImageHeader* oh = aImage.iOrigHdr;
	TInt orighdrsz = oh->TotalSize();
	int remainder = aImage.iSize - orighdrsz;
	TUint compression = oh->CompressionType();
	if (compression == 0)
		{
		is.read(aImage.iData + orighdrsz, remainder);
		}
	else if (compression == KUidCompressionDeflate)
		{ //Uncompress
		aImage.iError = KErrNoMemory;
		unsigned int uncompsize = ((E32ImageHeaderComp*)aImage.iOrigHdr)->iUncompressedSize;
		aImage.Adjust(uncompsize + orighdrsz);
		if (aImage.iData==NULL)
			return is;
		oh = aImage.iOrigHdr;
		unsigned char* compressedData = new unsigned char[remainder];
		if (compressedData==NULL)
			return is;
		is.read(reinterpret_cast<char *>(compressedData), remainder);
		unsigned int destsize = uncompsize;
		InflateUnCompress( compressedData, remainder, (unsigned char*)(aImage.iData + orighdrsz), destsize);
		if (destsize != uncompsize)
			Print(EWarning, "Inconsistent sizes discovered during uncompression.\n");
		delete [] compressedData;
		if ((TUint)orighdrsz > oh->iCodeOffset)
			{
			// need to adjust code offsets in original
			aImage.iOrigHdrOffsetAdj = (TUint)orighdrsz - oh->iCodeOffset;
			aImage.OffsetAdjust(oh->iCodeOffset);
			aImage.OffsetAdjust(oh->iDataOffset);
			aImage.OffsetAdjust(oh->iCodeRelocOffset);
			aImage.OffsetAdjust(oh->iDataRelocOffset);
			aImage.OffsetAdjust(oh->iImportOffset);
			aImage.OffsetAdjust(oh->iExportDirOffset);
			}
		aImage.iError = KErrNone;
		}
	else if(compression == KUidCompressionBytePair)
	{ // Uncompress
		aImage.iError = KErrNoMemory;
		unsigned int uncompsize = ((E32ImageHeaderComp*)aImage.iOrigHdr)->iUncompressedSize;
		aImage.Adjust(uncompsize + orighdrsz);
		if (aImage.iData==NULL)
			return is;
		oh = aImage.iOrigHdr;

		// Read and decompress code part of the image

		unsigned int uncompressedCodeSize = DecompressPages((TUint8 *) (aImage.iData + orighdrsz), is, &bpe);

		
		// Read and decompress data part of the image

		unsigned int uncompressedDataSize = DecompressPages((TUint8 *) (aImage.iData + orighdrsz + uncompressedCodeSize), is, &bpe);

		if (uncompressedCodeSize + uncompressedDataSize != uncompsize)
			Print(EWarning, "Inconsistent sizes discovered during uncompression.\n");

		if ((TUint)orighdrsz > oh->iCodeOffset)
			{
			// need to adjust code offsets in original
			aImage.iOrigHdrOffsetAdj = (TUint)orighdrsz - oh->iCodeOffset;
			aImage.OffsetAdjust(oh->iCodeOffset);
			aImage.OffsetAdjust(oh->iDataOffset);
			aImage.OffsetAdjust(oh->iCodeRelocOffset);
			aImage.OffsetAdjust(oh->iDataRelocOffset);
			aImage.OffsetAdjust(oh->iImportOffset);
			aImage.OffsetAdjust(oh->iExportDirOffset);
			}
		aImage.iError = KErrNone;
	}
	aImage.CreateExportBitMap();
	return is;
	}

TInt E32ImageFile::IsE32ImageFile(char *aFileName)
	{

#ifdef __LINUX__
	E32ImageFile f;
	struct stat buf;
	if (stat(aFileName, &buf) < 0) 
		{
		return FALSE;
		}
	f.iFileSize = buf.st_size;
#else
	_finddata_t fileinfo;
	int ret=_findfirst((char *)aFileName,&fileinfo);
	if (ret==-1) 
		return FALSE;
	E32ImageFile f;
	f.iFileSize = fileinfo.size;
#endif
	ifstream ifile(aFileName, ios::in | ios::binary);
	if(!ifile.is_open())
		return FALSE;
	TInt r = f.ReadHeader(ifile);
	ifile.close();
	return (r == KErrNone);
	}

TInt E32ImageFile::IsValid()
	{
	return (iError == KErrNone);
	}

TInt E32ImageFile::Open(const char* aFileName)
//
// Open an E32 Image file
//
	{
#ifdef __LINUX__
	struct stat buf;
	if (stat(aFileName, &buf) < 0) 
		{
		Print(EError,"Cannot open %s for input.\n",aFileName);
		return 1;
		}
	iFileSize = buf.st_size;
#else
	_finddata_t fileinfo;
	int ret=_findfirst((char *)aFileName,&fileinfo);
	if (ret==-1) 
		{
		Print(EError,"Cannot open %s for input.\n",aFileName);
		return 1;
		}
	iFileSize = fileinfo.size;
#endif
	Adjust(iFileSize);
	ifstream ifile((char *)aFileName, ios::in | ios::binary);
	if(!ifile.is_open())
		{
		Print(EError,"Cannot open %s for input.\n",aFileName);
		return 1;
		}
	ifile >> *this;
	ifile.close();
	if (iError != KErrNone)
		return iError;
	iFileName=strdup((char *)aFileName);
	if (iFileName==NULL)
		return KErrNoMemory;
	return KErrNone;
	}

#ifndef __LINUX__
TInt E32ImageFile::Open(const wchar_t* aFileName)
//
// Open an E32 Image file
//
	{
	_wfinddata_t fileinfo;
	int ret=_wfindfirst(aFileName,&fileinfo);
	if (ret==-1) 
		{
		Print(EError,"Cannot open %ls for input.\n",aFileName);
		return 1;
		}
	iFileSize = fileinfo.size;
	Adjust(iFileSize);

	FILE* file = _wfopen(aFileName, L"rb");

	if(!file)
		{
		Print(EError,"Cannot open %ls for input.\n",aFileName);
		return 1;
		}
	
	#ifdef __TOOLS2__
	char *tmp;  				// Convert wide character name to char *, then open a file.
	wcstombs(tmp,aFileName,100);
	ifstream ifile(tmp, ios::in | ios::binary);
	#else
	ifstream ifile(fileno(file));
	#endif
	
	if(!ifile.is_open())
		{
		Print(EError,"Cannot open %ls for input,\n",aFileName);
		return 1;
		}
		
	ifile >> *this;
	ifile.close();
	fclose(file);
	if (iError != KErrNone)
		return iError;
	iWideFileName=wcsdup(aFileName);
	if (iWideFileName==NULL)
		return KErrNoMemory;
	return KErrNone;
	}
#endif

TUint E32ImageFile::VaOfOrdinal(TUint aOrdinal)
// return the offset of the exported symbol
	{
	TUint* exportdir = (TUint*)(iData + iOrigHdr->iExportDirOffset);
	return exportdir[aOrdinal-KOrdinalBase];
	}

// Determine the type of entry point in this module and set the flags
// in the E32Image header accordingly.
TInt E32ImageFile::DetermineEntryPointType()
	{
	TUint cpu = iHdr->CpuIdentifier();
	if (cpu != ECpuArmV4 && cpu != ECpuArmV5)
		return KErrNone;	// if not ARM, leave EPT as 0
	TUint epOffset = iHdr->iEntryPoint;
	if (epOffset & 3)
		return KErrNone;	// if entry point not 4 byte aligned, must be old style
	TUint fileOffset = epOffset + iHdr->iCodeOffset;
	if (fileOffset+4 > (TUint)iSize)
		return KErrCorrupt;	// entry point is past the end of the file??
	TInt ept = 0;			// old style if first instruction not recognised
	unsigned char* p = (unsigned char*)iData + fileOffset + 4;
	TUint32 x = *--p;
	x<<=8;
	x|=*--p;
	x<<=8;
	x|=*--p;
	x<<=8;
	x|=*--p;
	if ((x & 0xffffff00) == 0xe31f0000)
		{
		// starts with tst pc, #n - new entry point
		ept = (x & 0xff) + 1;
		}
	if (ept>7)
		return KErrNotSupported;
	iHdr->iFlags |= (ept<<KImageEptShift);
	return KErrNone;
	}

