sl@0: /*
sl@0: * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0: * All rights reserved.
sl@0: * This component and the accompanying materials are made available
sl@0: * under the terms of "Eclipse Public License v1.0"
sl@0: * which accompanies this distribution, and is available
sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0: *
sl@0: * Initial Contributors:
sl@0: * Nokia Corporation - initial contribution.
sl@0: *
sl@0: * Contributors:
sl@0: *
sl@0: * Description: 
sl@0: *
sl@0: */
sl@0: 
sl@0: 
sl@0: #include <e32std.h>
sl@0: #include <e32base.h>
sl@0: #include <f32file.h>
sl@0: #include <charconv.h>
sl@0: #include <convdata.h>
sl@0: #include <utf.h>
sl@0: #include <ecom/ecom.h>
sl@0: #include <charactersetconverter.h>
sl@0: #include "chcnvpanic.h"
sl@0: #include "charconv_tls.h"
sl@0: #include "OstTraceDefinitions.h"
sl@0: #ifdef OST_TRACE_COMPILER_IN_USE
sl@0: #include "charconvTraces.h"
sl@0: #endif
sl@0: 
sl@0: 
sl@0: #if defined(_DEBUG)
sl@0: #define NON_DEBUG_INLINE
sl@0: #else
sl@0: #define NON_DEBUG_INLINE inline
sl@0: #endif
sl@0: 
sl@0: GLREF_D const SCnvConversionData codePage1252ConversionData;
sl@0: GLREF_D const SCnvConversionData iso88591ConversionData;
sl@0: GLREF_D const SCnvConversionData asciiConversionData;
sl@0: GLREF_D const SCnvConversionData sms7BitConversionData;
sl@0: GLREF_D const SCnvConversionData unicodeConversionDataLittle;
sl@0: GLREF_D const SCnvConversionData unicodeConversionDataBig;
sl@0: 
sl@0: GLREF_C void IsCharacterSetAscii(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetSMS7Bit(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetISO88591(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetCP1252(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetUTF8(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetUTF7(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetUnicodeLittle(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: GLREF_C void IsCharacterSetUnicodeBig(TInt& aConfidenceLevel, const TDesC8& aSample);
sl@0: 
sl@0: _LIT(KLitWildCard, "*");
sl@0: 
sl@0: _LIT(KLitSystemCharconvDirectory, "\\resource\\charconv\\");
sl@0: _LIT(KLitROMSystemCharconvDirectory, "z:\\resource\\charconv\\");
sl@0: 
sl@0: _LIT(KLitCharacterSetNameUtf7, "UTF-7");
sl@0: _LIT(KLitCharacterSetNameUtf8, "UTF-8");
sl@0: _LIT(KLitCharacterSetNameImapUtf7, "IMAP UTF-7");
sl@0: _LIT(KLitCharacterSetNameJavaConformantUtf8, "Java UTF-8");
sl@0: _LIT(KLitCharacterSetNameCodePage1252, "Code Page 1252");
sl@0: _LIT(KLitCharacterSetNameIso88591, "ISO-8859-1");
sl@0: _LIT(KLitCharacterSetNameAscii, "ASCII");
sl@0: _LIT(KLitCharacterSetNameUnicodeLittle, "Little-Endian UNICODE");
sl@0: _LIT(KLitCharacterSetNameUnicodeBig, "Big-Endian UNICODE");
sl@0: _LIT(KLitCharacterSetNameSms7Bit, "SMS 7-bit");
sl@0: _LIT8(KLit8AsciiSubstituteCharacter, "\x1a");
sl@0: _LIT8(KLit8Sms7BitSubstituteCharacter, "\x3f");
sl@0: 
sl@0: const TUint KNoConversionAvailable=KMaxTUint;
sl@0: 
sl@0: const TUint KCharacterSetIdentifierWin1252=0x101F873B; // same as built-in cp1252, just to be compliance with S60 CP1252
sl@0: 
sl@0: enum
sl@0: 	{
sl@0: 	EConversionDataFilePositionOfName=24,
sl@0: 	EConversionDataFileMaximumLengthOfName=KMaxTUint8
sl@0: 	};
sl@0: 
sl@0: LOCAL_C TBool StandardNamesMatch(const TDesC8& aStandardName1, const TDesC8& aStandardName2)
sl@0: 	{
sl@0: 	return aStandardName1.CompareF(aStandardName2)==0; // "no distinction is made between use of upper and lower case letters" as stated by ftp.isi.edu/in-notes/iana/assignments/character-sets
sl@0: 	}
sl@0: 	
sl@0: LOCAL_C void ResetAndDestroyRImplInfoPtrArray(TAny* aPtr)
sl@0: 	{
sl@0: 	RImplInfoPtrArray* array = reinterpret_cast <RImplInfoPtrArray*> (aPtr);
sl@0: 	array->ResetAndDestroy();
sl@0: 	}
sl@0: 
sl@0: LOCAL_C void CloseECOMSession(TAny*)
sl@0: 	{
sl@0: 	REComSession::FinalClose();
sl@0: 	}
sl@0: 
sl@0: static void IsBuiltInCharacterSet(const TUint& aCharacterSetIdentifier, 
sl@0: 								  TInt& aConfidenceLevel, 
sl@0: 								  const TDesC8& aSample)
sl@0:     {
sl@0: 	switch(aCharacterSetIdentifier)
sl@0: 	    {
sl@0: 		case KCharacterSetIdentifierUtf7:
sl@0: 		    IsCharacterSetUTF7(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUtf8:
sl@0: 			IsCharacterSetUTF8(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierImapUtf7:
sl@0: 		case KCharacterSetIdentifierJavaConformantUtf8:
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierCodePage1252:
sl@0: 		case KCharacterSetIdentifierWin1252:
sl@0: 			IsCharacterSetCP1252(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierIso88591:
sl@0: 			IsCharacterSetISO88591(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierAscii:
sl@0: 			IsCharacterSetAscii(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierSms7Bit:
sl@0: 			IsCharacterSetSMS7Bit(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUnicodeLittle:
sl@0: 			IsCharacterSetUnicodeLittle(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUnicodeBig:
sl@0: 			IsCharacterSetUnicodeBig(aConfidenceLevel,aSample);
sl@0: 			break;
sl@0: #if defined(_DEBUG)
sl@0: 		default:
sl@0: 		    OstTraceExt3( TRACE_DUMP, _ISBUILTINCHARACTERSET, "::IsBuiltInCharacterSet;aCharacterSetIdentifier=%u;aConfidenceLevel=%d;aSample=%x", aCharacterSetIdentifier, aConfidenceLevel, ( TUint )&( aSample ) );	    
sl@0: 			Panic(EPanicCharacterSetNotPresent);
sl@0: 			break;
sl@0: #endif
sl@0: 		}
sl@0:     }
sl@0:     
sl@0: 
sl@0: void TTlsData::CharacterSetConverterIsBeingCreatedL()
sl@0: 	{
sl@0: 	TTlsData* tlsData=STATIC_CAST(TTlsData*, Dll::Tls());
sl@0: 	if (tlsData!=NULL)
sl@0: 		{
sl@0: 		++tlsData->iReferenceCount;
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		tlsData=new(ELeave) TTlsData;
sl@0: 		CleanupStack::PushL(tlsData);
sl@0: 		User::LeaveIfError(Dll::SetTls(tlsData));
sl@0: 		CleanupStack::Pop(); // tlsData
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void TTlsData::CharacterSetConverterIsBeingDestroyed()
sl@0: 	{
sl@0: 	TTlsData* tlsData=STATIC_CAST(TTlsData*, Dll::Tls());
sl@0: 	if (tlsData!=NULL)
sl@0: 		{
sl@0: 		if ( tlsData->iCurrentCharacterSetConverter!=NULL )
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, TTLSDATA_CHARACTERSETCONVERTERISBEINGDESTROYED, "EPanicDestructionDuringConversion" );	    
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(tlsData->iCurrentCharacterSetConverter==NULL, Panic(EPanicDestructionDuringConversion));
sl@0: 		--tlsData->iReferenceCount;
sl@0: 		if ( tlsData->iReferenceCount < 0 )
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP1_TTLSDATA_CHARACTERSETCONVERTERISBEINGDESTROYED, "EPanicBadTlsDataReferenceCount" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(tlsData->iReferenceCount>=0, Panic(EPanicBadTlsDataReferenceCount));
sl@0: 		if (tlsData->iReferenceCount<=0)
sl@0: 			{
sl@0: 			delete tlsData;
sl@0: 			Dll::FreeTls();
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void TTlsData::SetCurrentCharacterSetConverter(const CCnvCharacterSetConverter* aCharacterSetConverter)
sl@0: 	{
sl@0: 	TTlsData* tlsData=STATIC_CAST(TTlsData*, Dll::Tls());
sl@0: 	if ( tlsData==NULL )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_TTLSDATA_SETCURRENTCHARACTERSETCONVERTER, "No Tls Data in TTlsData::SetCurrentCharacterSetConverter" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(tlsData!=NULL, Panic(EPanicNoTlsData));
sl@0:     if ( (tlsData->iCurrentCharacterSetConverter==NULL)==(aCharacterSetConverter==NULL) )
sl@0:         {
sl@0:         OstTrace0( TRACE_FATAL, TTLSDATA_SETCURRENTCHARACTERSETCONVERTER, "Bad Toggle of current characater set converter in TTlsData::SetCurrentCharacterSetConverter" );  
sl@0:         }
sl@0: 	__ASSERT_ALWAYS((tlsData->iCurrentCharacterSetConverter==NULL)!=(aCharacterSetConverter==NULL), Panic(EPanicBadToggleOfCurrentCharacterSetConverter));
sl@0: 	tlsData->iCurrentCharacterSetConverter=aCharacterSetConverter;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const CCnvCharacterSetConverter* TTlsData::CurrentCharacterSetConverter()
sl@0: 	{
sl@0: 	TTlsData* tlsData=STATIC_CAST(TTlsData*, Dll::Tls());
sl@0: 	return (tlsData!=NULL)? tlsData->iCurrentCharacterSetConverter: NULL;
sl@0: 	}
sl@0: 
sl@0: // CDeepDestructingArrayOfCharactersSets
sl@0: 
sl@0: NONSHARABLE_CLASS(CDeepDestructingArrayOfCharactersSets) : public CArrayFixFlat<CCnvCharacterSetConverter::SCharacterSet>
sl@0: 	{
sl@0: public:
sl@0: 	static CDeepDestructingArrayOfCharactersSets* NewLC(TInt aGranularity);
sl@0: 	virtual ~CDeepDestructingArrayOfCharactersSets();
sl@0: private:
sl@0: 	CDeepDestructingArrayOfCharactersSets(TInt aGranularity);
sl@0: 	};
sl@0: 
sl@0: CDeepDestructingArrayOfCharactersSets* CDeepDestructingArrayOfCharactersSets::NewLC(TInt aGranularity)
sl@0: 	{
sl@0: 	CDeepDestructingArrayOfCharactersSets* deepDestructingArrayOfCharactersSets=new(ELeave) CDeepDestructingArrayOfCharactersSets(aGranularity);
sl@0: 	CleanupStack::PushL(deepDestructingArrayOfCharactersSets);
sl@0: 	return deepDestructingArrayOfCharactersSets;
sl@0: 	}
sl@0: 
sl@0: CDeepDestructingArrayOfCharactersSets::~CDeepDestructingArrayOfCharactersSets()
sl@0: 	{
sl@0: 	for (TInt i=Count()-1; i>=0; --i)
sl@0: 		{
sl@0: 		delete (*this)[i].iName;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: CDeepDestructingArrayOfCharactersSets::CDeepDestructingArrayOfCharactersSets(TInt aGranularity)
sl@0: 	:CArrayFixFlat<CCnvCharacterSetConverter::SCharacterSet>(aGranularity)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: // CFileReader
sl@0: 
sl@0: NONSHARABLE_CLASS(CFileReader) : public CBase
sl@0: 	{
sl@0: public:
sl@0: 	static CFileReader* NewLC(RFile& aFile);
sl@0: 	static CFileReader* NewLC(const TUint8* aRomFile, TInt aLengthOfRomFile);
sl@0: 	virtual ~CFileReader();
sl@0: 	void SkipL(TInt aNumberOfBytes);
sl@0: 	TInt ReadUint8L();
sl@0: 	TInt ReadUint16L();
sl@0: 	TUint ReadUint32L();
sl@0: 	TInt ReadPositiveIntegerCompacted15L();
sl@0: 	TInt ReadPositiveIntegerCompacted30L();
sl@0: 	TInt ReadSignedIntegerCompacted29L();
sl@0: 	void ReadBufferL(TDes8& aBuffer, TInt aBufferLength);
sl@0: 	HBufC8* ReadBufferL(TInt aBufferLength);
sl@0: 	HBufC8* ReadBufferLC(TInt aBufferLength);
sl@0: 	inline TBool IsEndOfFile() const {if ( iNextByteToConsume>iOnePastEndOfBuffer ) {OstTrace0( TRACE_DUMP, _NONSHARABLE_CLASS, "EPanicPastEndOfFile" );}__ASSERT_DEBUG(iNextByteToConsume<=iOnePastEndOfBuffer, Panic(EPanicPastEndOfFile)); return iNextByteToConsume>=iOnePastEndOfBuffer;}
sl@0: private:
sl@0: 	enum {ENumberOfBytesToConsumeBetweenEachReAllocation=1000};
sl@0: private:
sl@0: 	CFileReader();
sl@0: 	CFileReader(const TUint8* aRomFile, TInt aLengthOfRomFile);
sl@0: 	void ConstructForNonRomFileL(RFile& aFile);
sl@0: 	NON_DEBUG_INLINE void ReAllocateTheBuffer();
sl@0: #if defined(_DEBUG)
sl@0: 	inline void CheckPointers(TPanic aPanic) {__ASSERT_DEBUG((iNextByteToConsume!=NULL) && (iOnePastEndOfBuffer!=NULL) && (iNextByteToConsume<=iOnePastEndOfBuffer), Panic(aPanic)); if (iBuffer==NULL) {__ASSERT_DEBUG(iFlagPoleForReAllocation==NULL, Panic(aPanic));} else {__ASSERT_DEBUG(iNextByteToConsume<iFlagPoleForReAllocation, Panic(aPanic));}}
sl@0: #else
sl@0: 	inline void CheckPointers(TPanic) {}
sl@0: #endif
sl@0: private:
sl@0: 	TUint8* iBuffer;
sl@0: 	const TUint8* iNextByteToConsume;
sl@0: 	const TUint8* iOnePastEndOfBuffer;
sl@0: 	const TUint8* iFlagPoleForReAllocation;
sl@0: 	};
sl@0: 
sl@0: void CFileReader::ReAllocateTheBuffer() // put this function first so that the compiler does actually inline it for non-DEBUG builds
sl@0: 	{
sl@0: 	if ( (iBuffer==NULL) || (iNextByteToConsume<iFlagPoleForReAllocation ) )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CFILEREADER_REALLOCATETHEBUFFER, "EPanicNotPastFlagPoleForReAllocation" );
sl@0: 	    }
sl@0: 	
sl@0: 	__ASSERT_DEBUG((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation), Panic(EPanicNotPastFlagPoleForReAllocation));
sl@0: 	const TInt lengthOfBuffer=iOnePastEndOfBuffer-iNextByteToConsume;
sl@0: 	Mem::Copy(STATIC_CAST(TAny*, iBuffer), iNextByteToConsume, lengthOfBuffer);
sl@0: 	const TAny* reAllocatedCell=
sl@0: 	        User::ReAlloc(STATIC_CAST(TAny*, iBuffer), lengthOfBuffer);
sl@0: 	if ( reAllocatedCell!=iBuffer )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP1_CFILEREADER_REALLOCATETHEBUFFER, "EPanicReAllocatedCellMoved" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(reAllocatedCell==iBuffer, Panic(EPanicReAllocatedCellMoved));
sl@0: 	iNextByteToConsume=iBuffer;
sl@0: 	iOnePastEndOfBuffer=iBuffer+lengthOfBuffer;
sl@0: 	// iFlagPoleForReAllocation can stay as it is
sl@0: 	}
sl@0: 
sl@0: CFileReader* CFileReader::NewLC(RFile& aFile)
sl@0: 	{
sl@0: 	CFileReader* fileReader=new(ELeave) CFileReader;
sl@0: 	CleanupStack::PushL(fileReader);
sl@0: 	fileReader->ConstructForNonRomFileL(aFile);
sl@0: 	return fileReader;
sl@0: 	}
sl@0: 
sl@0: CFileReader* CFileReader::NewLC(const TUint8* aRomFile, TInt aLengthOfRomFile)
sl@0: 	{
sl@0: 	CFileReader* fileReader=new(ELeave) CFileReader(aRomFile, aLengthOfRomFile);
sl@0: 	CleanupStack::PushL(fileReader);
sl@0: 	return fileReader;
sl@0: 	}
sl@0: 
sl@0: CFileReader::~CFileReader()
sl@0: 	{
sl@0: 	User::Free(iBuffer);
sl@0: 	}
sl@0: 
sl@0: void CFileReader::SkipL(TInt aNumberOfBytes)
sl@0: 	{
sl@0: 	if ( aNumberOfBytes<0 )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CFILEREADER_SKIPL, "EPanicNegativeNumberOfBytes" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aNumberOfBytes>=0, Panic(EPanicNegativeNumberOfBytes));
sl@0: 	CheckPointers(EPanicInconsistentFileReader1);
sl@0: 	const TUint8* newNextByteToConsume=iNextByteToConsume+aNumberOfBytes;
sl@0: 	if (newNextByteToConsume>iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, DUP2_CFILEREADER_SKIPL, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	iNextByteToConsume=newNextByteToConsume;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader2);
sl@0: 	}
sl@0: 
sl@0: TInt CFileReader::ReadUint8L()
sl@0: 	{
sl@0: 	CheckPointers(EPanicInconsistentFileReader3);
sl@0: 	const TUint8* newNextByteToConsume=iNextByteToConsume+sizeof(TUint8);
sl@0: 	if (newNextByteToConsume>iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	const TInt integer=*iNextByteToConsume;
sl@0: 	iNextByteToConsume=newNextByteToConsume;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader4);
sl@0: 	return integer;
sl@0: 	}
sl@0: 
sl@0: TInt CFileReader::ReadUint16L() // little-endian
sl@0: 	{
sl@0: 	CheckPointers(EPanicInconsistentFileReader5);
sl@0: 	const TUint8* newNextByteToConsume=iNextByteToConsume+sizeof(TUint16);
sl@0: 	if (newNextByteToConsume>iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, CFILEREADER_READUINT16L, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	const TInt integer=(*iNextByteToConsume|(*(iNextByteToConsume+1)<<8));
sl@0: 	iNextByteToConsume=newNextByteToConsume;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader6);
sl@0: 	return integer;
sl@0: 	}
sl@0: 
sl@0: TUint CFileReader::ReadUint32L() // little-endian
sl@0: 	{
sl@0: 	CheckPointers(EPanicInconsistentFileReader7);
sl@0: 	const TUint8* newNextByteToConsume=iNextByteToConsume+sizeof(TUint32);
sl@0: 	if (newNextByteToConsume>iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	const TInt integer=(*iNextByteToConsume|(*(iNextByteToConsume+1)<<8)|(*(iNextByteToConsume+2)<<16)|(*(iNextByteToConsume+3)<<24));
sl@0: 	iNextByteToConsume=newNextByteToConsume;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader8);
sl@0: 	return integer;
sl@0: 	}
sl@0: 
sl@0: TInt CFileReader::ReadPositiveIntegerCompacted15L() // big-endian
sl@0: 	{
sl@0: 	CheckPointers(EPanicInconsistentFileReader9);
sl@0: 	const TUint8* bytePointer=iNextByteToConsume;
sl@0: 	if (bytePointer>=iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	TInt integer=*bytePointer;
sl@0: 	if (integer&0x00000080)
sl@0: 		{
sl@0: 		integer&=~0x00000080;
sl@0: 		++bytePointer;
sl@0: 		if (bytePointer>=iOnePastEndOfBuffer)
sl@0: 			{
sl@0: 			User::Leave(KErrCorrupt);
sl@0: 			}
sl@0: 		integer<<=8;
sl@0: 		integer|=*bytePointer;
sl@0: 		}
sl@0: 	++bytePointer;
sl@0: 	iNextByteToConsume=bytePointer;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader10);
sl@0: 	return integer;
sl@0: 	}
sl@0: 
sl@0: TInt CFileReader::ReadPositiveIntegerCompacted30L() // big-endian
sl@0: 	{
sl@0: 	CheckPointers(EPanicInconsistentFileReader11);
sl@0: 	const TUint8* bytePointer=iNextByteToConsume;
sl@0: 	if (bytePointer>=iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, CFILEREADER_READPOSITIVEINTEGERCOMPACTED30L, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	TInt integer=*bytePointer;
sl@0: 	if (integer&0x00000080)
sl@0: 		{
sl@0: 		integer&=~0x00000080;
sl@0: 		++bytePointer;
sl@0: 		if (bytePointer>=iOnePastEndOfBuffer)
sl@0: 			{
sl@0: 			OstTrace0( TRACE_FATAL, DUP1_CFILEREADER_READPOSITIVEINTEGERCOMPACTED30L, "KErrCorrupt" );
sl@0: 			User::Leave(KErrCorrupt);
sl@0: 			}
sl@0: 		integer<<=8;
sl@0: 		integer|=*bytePointer;
sl@0: 		if (integer&0x00004000)
sl@0: 			{
sl@0: 			integer&=~0x00004000;
sl@0: 			if (bytePointer+2>=iOnePastEndOfBuffer)
sl@0: 				{
sl@0: 				OstTrace0( TRACE_FATAL, DUP2_CFILEREADER_READPOSITIVEINTEGERCOMPACTED30L, "KErrCorrupt" );
sl@0: 				User::Leave(KErrCorrupt);
sl@0: 				}
sl@0: 			++bytePointer;
sl@0: 			integer<<=8;
sl@0: 			integer|=*bytePointer;
sl@0: 			++bytePointer;
sl@0: 			integer<<=8;
sl@0: 			integer|=*bytePointer;
sl@0: 			}
sl@0: 		}
sl@0: 	++bytePointer;
sl@0: 	iNextByteToConsume=bytePointer;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader12);
sl@0: 	return integer;
sl@0: 	}
sl@0: 
sl@0: TInt CFileReader::ReadSignedIntegerCompacted29L() // big-endian
sl@0: 	{
sl@0: 	CheckPointers(EPanicInconsistentFileReader13);
sl@0: 	const TUint8* bytePointer=iNextByteToConsume;
sl@0: 	if (bytePointer>=iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, CFILEREADER_READSIGNEDINTEGERCOMPACTED29L, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	TInt integer=*bytePointer;
sl@0: 	const TBool isNegative=(integer&0x00000080);
sl@0: 	integer&=~0x00000080;
sl@0: 	if (integer&0x00000040)
sl@0: 		{
sl@0: 		integer&=~0x00000040;
sl@0: 		++bytePointer;
sl@0: 		if (bytePointer>=iOnePastEndOfBuffer)
sl@0: 			{
sl@0: 			OstTrace0( TRACE_FATAL, DUP1_CFILEREADER_READSIGNEDINTEGERCOMPACTED29L, "KErrCorrupt" );
sl@0: 			User::Leave(KErrCorrupt);
sl@0: 			}
sl@0: 		integer<<=8;
sl@0: 		integer|=*bytePointer;
sl@0: 		if (integer&0x00002000)
sl@0: 			{
sl@0: 			integer&=~0x00002000;
sl@0: 			if (bytePointer+2>=iOnePastEndOfBuffer)
sl@0: 				{
sl@0: 				OstTrace0( TRACE_FATAL, DUP2_CFILEREADER_READSIGNEDINTEGERCOMPACTED29L, "KErrCorrupt" );
sl@0: 				User::Leave(KErrCorrupt);
sl@0: 				}
sl@0: 			++bytePointer;
sl@0: 			integer<<=8;
sl@0: 			integer|=*bytePointer;
sl@0: 			++bytePointer;
sl@0: 			integer<<=8;
sl@0: 			integer|=*bytePointer;
sl@0: 			}
sl@0: 		}
sl@0: 	++bytePointer;
sl@0: 	if (isNegative)
sl@0: 		{
sl@0: 		integer=-integer;
sl@0: 		}
sl@0: 	iNextByteToConsume=bytePointer;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader14);
sl@0: 	return isNegative? -integer: integer;
sl@0: 	}
sl@0: 
sl@0: void CFileReader::ReadBufferL(TDes8& aBuffer, TInt aBufferLength)
sl@0: 	{
sl@0: 	if ( aBufferLength<0 )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CFILEREADER_READBUFFERL, "EPanicNegativeBufferLength1" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aBufferLength>=0, Panic(EPanicNegativeBufferLength1));
sl@0: 	CheckPointers(EPanicInconsistentFileReader15);
sl@0: 	const TUint8* newNextByteToConsume=iNextByteToConsume+aBufferLength;
sl@0: 	if (newNextByteToConsume>iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, DUP1_CFILEREADER_READBUFFERL, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	aBuffer=TPtrC8(iNextByteToConsume, aBufferLength);
sl@0: 	iNextByteToConsume=newNextByteToConsume;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader16);
sl@0: 	}
sl@0: 
sl@0: HBufC8* CFileReader::ReadBufferL(TInt aBufferLength)
sl@0: 	{
sl@0: 	if ( aBufferLength<0 )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP2_CFILEREADER_READBUFFERL, "EPanicNegativeBufferLength2" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aBufferLength>=0, Panic(EPanicNegativeBufferLength2));
sl@0: 	CheckPointers(EPanicInconsistentFileReader17);
sl@0: 	const TUint8* newNextByteToConsume=iNextByteToConsume+aBufferLength;
sl@0: 	if (newNextByteToConsume>iOnePastEndOfBuffer)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, DUP3_CFILEREADER_READBUFFERL, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	HBufC8* buffer=TPtrC8(iNextByteToConsume, aBufferLength).AllocL();
sl@0: 	iNextByteToConsume=newNextByteToConsume;
sl@0: 	if ((iBuffer!=NULL) && (iNextByteToConsume>=iFlagPoleForReAllocation))
sl@0: 		{
sl@0: 		ReAllocateTheBuffer();
sl@0: 		}
sl@0: 	CheckPointers(EPanicInconsistentFileReader18);
sl@0: 	return buffer;
sl@0: 	}
sl@0: 
sl@0: HBufC8* CFileReader::ReadBufferLC(TInt aBufferLength)
sl@0: 	{
sl@0: 	HBufC8* buffer=ReadBufferL(aBufferLength);
sl@0: 	CleanupStack::PushL(buffer);
sl@0: 	return buffer;
sl@0: 	}
sl@0: 
sl@0: CFileReader::CFileReader()
sl@0: 	:iBuffer(NULL),
sl@0: 	 iNextByteToConsume(NULL),
sl@0: 	 iOnePastEndOfBuffer(NULL),
sl@0: 	 iFlagPoleForReAllocation(NULL)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: CFileReader::CFileReader(const TUint8* aRomFile, TInt aLengthOfRomFile)
sl@0: 	:iBuffer(NULL),
sl@0: 	 iNextByteToConsume(aRomFile),
sl@0: 	 iOnePastEndOfBuffer(aRomFile+aLengthOfRomFile),
sl@0: 	 iFlagPoleForReAllocation(NULL)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: void CFileReader::ConstructForNonRomFileL(RFile& aFile)
sl@0: 	{
sl@0: 	TInt lengthOfBuffer;
sl@0: 	if ( aFile.Size(lengthOfBuffer) < 0 )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, DUP1_CFILEREADER_CONSTRUCTFORNONROMFILEL, "aFile.Size(lengthOfBuffer) < 0" );
sl@0: 	    }
sl@0: 	User::LeaveIfError(aFile.Size(lengthOfBuffer));
sl@0: 	iBuffer=STATIC_CAST(TUint8*, User::AllocL(lengthOfBuffer+1));
sl@0: 	TPtr8 buffer(iBuffer, 0, lengthOfBuffer);
sl@0: 	User::LeaveIfError(aFile.Read(buffer));
sl@0: 	if ((buffer.Length()!=lengthOfBuffer) || (lengthOfBuffer<=0))
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, CFILEREADER_CONSTRUCTFORNONROMFILEL, "KErrCorrupt" );
sl@0: 		User::Leave(KErrCorrupt);
sl@0: 		}
sl@0: 	iNextByteToConsume=iBuffer;
sl@0: 	iOnePastEndOfBuffer=iBuffer+lengthOfBuffer;
sl@0: 	iFlagPoleForReAllocation=iBuffer+ENumberOfBytesToConsumeBetweenEachReAllocation;
sl@0: 	}
sl@0: 
sl@0: // CStandardNamesAndMibEnums
sl@0: 
sl@0: NONSHARABLE_CLASS(CStandardNamesAndMibEnums) : public CBase
sl@0: 	{
sl@0: public:
sl@0: 	static CStandardNamesAndMibEnums* NewLC();
sl@0: 	virtual ~CStandardNamesAndMibEnums();
sl@0: 	void AddFromFileL(RFs& aFileServerSession, const TDesC& aFileName);
sl@0: 	TUint Identifier(const TDesC8& aStandardName) const;
sl@0: 	TUint Identifier(TInt aMibEnum) const;
sl@0: 	HBufC8* StandardNameL(TUint aIdentifier) const;
sl@0: 	TInt MibEnum(TUint aIdentifier) const;
sl@0: private:
sl@0: 	/** Stores information about a non-Unicode character set. The information 
sl@0: 	is used to locate the conversion information required by ConvertFromUnicode() 
sl@0: 	and	ConvertToUnicode().
sl@0: 
sl@0: 	An array of these structs, which contains all available character sets, 
sl@0: 	can be generated by CreateArrayOfCharacterSetsAvailableLC() and 
sl@0: 	CreateArrayOfCharacterSetsAvailableL(), 
sl@0: 	and is used by one of the overloads of PrepareToConvertToOrFromL(). */
sl@0: 	struct SCharacterSet
sl@0: 		{
sl@0: 		inline SCharacterSet(TUint aIdentifier, TInt aNumberOfStandardNames, TInt aNumberOfMibEnums) :iIdentifier(aIdentifier), iArrayOfStandardNames(Max(aNumberOfStandardNames, 1)), iArrayOfMibEnums(Max(aNumberOfMibEnums, 1)) {}
sl@0: 		const TUint iIdentifier;
sl@0: 		RPointerArray<HBufC8> iArrayOfStandardNames;
sl@0: 		RArray<TInt> iArrayOfMibEnums;
sl@0: 		};
sl@0: private:
sl@0: 	CStandardNamesAndMibEnums();
sl@0: 	TBool CharacterSetExists(TUint aIdentifier, TInt& aIndex) const;
sl@0: 	static TInt CompareFunction(const SCharacterSet& aCharacterSet1, const SCharacterSet& aCharacterSet2);
sl@0: private:
sl@0: 	RArray<SCharacterSet> iArrayOfCharacterSets;
sl@0: 	};
sl@0: 
sl@0: CStandardNamesAndMibEnums* CStandardNamesAndMibEnums::NewLC()
sl@0: 	{
sl@0: 	CStandardNamesAndMibEnums* standardNamesAndMibEnums=new(ELeave) CStandardNamesAndMibEnums;
sl@0: 	CleanupStack::PushL(standardNamesAndMibEnums);
sl@0: 	return standardNamesAndMibEnums;
sl@0: 	}
sl@0: 
sl@0: CStandardNamesAndMibEnums::~CStandardNamesAndMibEnums()
sl@0: 	{
sl@0: 	for (TInt i=iArrayOfCharacterSets.Count()-1; i>=0; --i)
sl@0: 		{
sl@0: 		SCharacterSet& characterSet=iArrayOfCharacterSets[i];
sl@0: 		characterSet.iArrayOfStandardNames.ResetAndDestroy();
sl@0: 		characterSet.iArrayOfStandardNames.Close();
sl@0: 		characterSet.iArrayOfMibEnums.Close();
sl@0: 		}
sl@0: 	iArrayOfCharacterSets.Close();
sl@0: 	}
sl@0: 
sl@0: void CStandardNamesAndMibEnums::AddFromFileL(RFs& aFileServerSession, const TDesC& aFileName)
sl@0: 	{
sl@0: 	const TUint8* const romFile=aFileServerSession.IsFileInRom(aFileName);
sl@0: 	RFile file;
sl@0: 	CFileReader* fileReader=NULL;
sl@0: 	if (romFile!=NULL)
sl@0: 		{
sl@0: 		TEntry entry;
sl@0: 		User::LeaveIfError(aFileServerSession.Entry(aFileName, entry));
sl@0: 		fileReader=CFileReader::NewLC(romFile, entry.iSize);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		CleanupClosePushL(file);
sl@0: 		User::LeaveIfError(file.Open(aFileServerSession, aFileName, EFileShareReadersOnly|EFileStream|EFileRead));
sl@0: 		fileReader=CFileReader::NewLC(file);
sl@0: 		}
sl@0: 	fileReader->SkipL(16); // skip the UIDs
sl@0: 	while (!fileReader->IsEndOfFile())
sl@0: 		{
sl@0: 		const TUint identifier=fileReader->ReadUint32L();
sl@0: 		const TInt numberOfStandardNames=fileReader->ReadPositiveIntegerCompacted15L();
sl@0: 		const TInt numberOfMibEnums=fileReader->ReadPositiveIntegerCompacted15L();
sl@0: 		SCharacterSet* characterSet=NULL;
sl@0: 		TInt indexOfCharacterSet;
sl@0: 		if (CharacterSetExists(identifier, indexOfCharacterSet))
sl@0: 			{
sl@0: 			characterSet=&iArrayOfCharacterSets[indexOfCharacterSet];
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			User::LeaveIfError(iArrayOfCharacterSets.Insert(SCharacterSet(identifier, numberOfStandardNames, numberOfMibEnums), indexOfCharacterSet));
sl@0: 			characterSet=&iArrayOfCharacterSets[indexOfCharacterSet];
sl@0: 			}
sl@0: 		TInt i;
sl@0: 		for (i=0; i<numberOfStandardNames; ++i)
sl@0: 			{
sl@0: 			const TInt lengthOfStandardName=fileReader->ReadPositiveIntegerCompacted15L();
sl@0: 			User::LeaveIfError(characterSet->iArrayOfStandardNames.Append(fileReader->ReadBufferLC(lengthOfStandardName)));
sl@0: 			CleanupStack::Pop(); // fileReader->ReadBufferLC(lengthOfStandardName)
sl@0: 			}
sl@0: 		for (i=0; i<numberOfMibEnums; ++i)
sl@0: 			{
sl@0: 			User::LeaveIfError(characterSet->iArrayOfMibEnums.Append(fileReader->ReadPositiveIntegerCompacted30L()));
sl@0: 			}
sl@0: 		}
sl@0: 	CleanupStack::PopAndDestroy((romFile!=NULL)? 1: 2); // fileReader and (possibly) file
sl@0: 	}
sl@0: 
sl@0: 
sl@0: TUint CStandardNamesAndMibEnums::Identifier(const TDesC8& aStandardName) const
sl@0: 	{
sl@0: 	for (TInt i=iArrayOfCharacterSets.Count()-1; i>=0; --i)
sl@0: 		{
sl@0: 		const SCharacterSet& characterSet=iArrayOfCharacterSets[i];
sl@0: 		for (TInt j=characterSet.iArrayOfStandardNames.Count()-1; j>=0; --j)
sl@0: 			{
sl@0: 			if (StandardNamesMatch(*characterSet.iArrayOfStandardNames[j], aStandardName))
sl@0: 				{
sl@0: 				return characterSet.iIdentifier;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: TUint CStandardNamesAndMibEnums::Identifier(TInt aMibEnum) const
sl@0: 	{
sl@0: 	for (TInt i=iArrayOfCharacterSets.Count()-1; i>=0; --i)
sl@0: 		{
sl@0: 		const SCharacterSet& characterSet=iArrayOfCharacterSets[i];
sl@0: 		for (TInt j=characterSet.iArrayOfMibEnums.Count()-1; j>=0; --j)
sl@0: 			{
sl@0: 			if (characterSet.iArrayOfMibEnums[j]==aMibEnum)
sl@0: 				{
sl@0: 				return characterSet.iIdentifier;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: HBufC8* CStandardNamesAndMibEnums::StandardNameL(TUint aIdentifier) const
sl@0: 	{
sl@0: 	TInt indexOfCharacterSet;
sl@0: 	if (CharacterSetExists(aIdentifier, indexOfCharacterSet))
sl@0: 		{
sl@0: 		const RPointerArray<HBufC8>& arrayOfStandardNames=iArrayOfCharacterSets[indexOfCharacterSet].iArrayOfStandardNames;
sl@0: 		if (arrayOfStandardNames.Count()>0)
sl@0: 			{
sl@0: 			return arrayOfStandardNames[0]->AllocL();
sl@0: 			}
sl@0: 		}
sl@0: 	return NULL;
sl@0: 	}
sl@0: 
sl@0: TInt CStandardNamesAndMibEnums::MibEnum(TUint aIdentifier) const
sl@0: 	{
sl@0: 	TInt indexOfCharacterSet;
sl@0: 	if (CharacterSetExists(aIdentifier, indexOfCharacterSet))
sl@0: 		{
sl@0: 		const RArray<TInt>& arrayOfMibEnums=iArrayOfCharacterSets[indexOfCharacterSet].iArrayOfMibEnums;
sl@0: 		if (arrayOfMibEnums.Count()>0)
sl@0: 			{
sl@0: 			return arrayOfMibEnums[0];
sl@0: 			}
sl@0: 		}
sl@0: 	return 0;
sl@0: 	}
sl@0: 
sl@0: CStandardNamesAndMibEnums::CStandardNamesAndMibEnums()
sl@0: 	:iArrayOfCharacterSets(5)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: TBool CStandardNamesAndMibEnums::CharacterSetExists(TUint aIdentifier, TInt& aIndex) const
sl@0: 	{
sl@0: 	TUint characterSet[sizeof(SCharacterSet)/sizeof(TUint)]; // use this as a pretend SCharacterSet object (the only field of it that will be used is iIdentifier)
sl@0: 	characterSet[_FOFF(SCharacterSet, iIdentifier)/sizeof(TUint)]=aIdentifier;
sl@0: #if defined(_DEBUG)
sl@0: 	for (TInt i=iArrayOfCharacterSets.Count()-1; i>0; --i) // i>0 (rather than i>=0) is correct as we are comparing the character set identifier at [i] with the one at [i-1]
sl@0: 		{
sl@0: 		__ASSERT_DEBUG(CompareFunction(iArrayOfCharacterSets[i-1], iArrayOfCharacterSets[i])<0, Panic(EPanicCharacterSetsNotSorted));
sl@0: 		}
sl@0: #endif
sl@0: 	return iArrayOfCharacterSets.FindInOrder(*REINTERPRET_CAST(const SCharacterSet*, characterSet), aIndex, TLinearOrder<SCharacterSet>(CompareFunction))==KErrNone;
sl@0: 	}
sl@0: 
sl@0: TInt CStandardNamesAndMibEnums::CompareFunction(const SCharacterSet& aCharacterSet1, const SCharacterSet& aCharacterSet2)
sl@0: 	{
sl@0: 	return aCharacterSet2.iIdentifier-aCharacterSet1.iIdentifier;
sl@0: 	}
sl@0: 
sl@0: ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
sl@0: // class CCharsetCnvCache
sl@0: 
sl@0: /**
sl@0: CCharsetCnvCache is used to accelerate the access to character set converter implementations.
sl@0: On a client request the CCharsetCnvCache instance will load the required character set converter 
sl@0: implementation if it is not loaded yet and give it to the client. If the requested 
sl@0: character set converter is in the cache, it will be used and no time will be spend for loading it.
sl@0: The type of the used caching algorithm is LRU.
sl@0: The implementation UID of the converter is used as a key, uniquely identifying cache entries.
sl@0: GetConverterL()/Converter() return results should not be stored across the calls. The cache
sl@0: has limited max size. It will remove the last entries if it reaches its max limit - that may
sl@0: make stored GetConverterL()/Converter() return results invalid.
sl@0: @internalComponent
sl@0: */
sl@0: NONSHARABLE_CLASS(CCharsetCnvCache) : public CBase
sl@0: 	{
sl@0: public:
sl@0: 	enum 
sl@0: 		{
sl@0: 		/** Default cache size*/
sl@0: 		KDefaultMaxCacheSize = 32
sl@0: 		};
sl@0: 	enum
sl@0: 		{
sl@0: 		/** Min allowed cache size*/
sl@0: 		KMinCacheSize = 4
sl@0: 		};
sl@0: 		
sl@0: public:
sl@0: 	static CCharsetCnvCache* NewL();
sl@0: 	virtual ~CCharsetCnvCache();
sl@0: 
sl@0: 	CCharacterSetConverterPluginInterface* GetConverterL(TUid aImplUid);
sl@0: 	CCharacterSetConverterPluginInterface* Converter(TUid aImplUid);
sl@0: 	void SetMaxSize(TInt aSize);
sl@0: 
sl@0: private:
sl@0: 	/**
sl@0: 	The class represents an entry in CCharsetCnvCache cache.
sl@0: 	@internalComponent
sl@0: 	*/
sl@0: 	NONSHARABLE_CLASS(TCharsetCnvEntry)
sl@0: 		{
sl@0: 	public:
sl@0: 		static TInt Offset();
sl@0: 	public:
sl@0: 		TUid									iImplUid;
sl@0: 		CCharacterSetConverterPluginInterface*	iCharsetCnv;
sl@0: 		TSglQueLink								iLink;
sl@0: 		};
sl@0: 	TInt						iMaxCacheSize;
sl@0: 	TInt						iCacheSize;
sl@0: 	TSglQue<TCharsetCnvEntry>	iCache;
sl@0: 
sl@0: private:
sl@0: 	CCharsetCnvCache();
sl@0: 	TCharsetCnvEntry* Find(TUid aImplUid);
sl@0: 	TCharsetCnvEntry* CreateNewL(TUid aImplUid);
sl@0: 	void RemoveLast();
sl@0:     
sl@0: 	};
sl@0: 
sl@0: /**
sl@0: @return The offset of iLink data member from the beginning of CCharsetCnvCache::TCharsetCnvEntry
sl@0: object. The method is used internally - the character set converter cache implementation 
sl@0: uses TSglQue class.
sl@0: Note: Static method.
sl@0: */
sl@0: TInt CCharsetCnvCache::TCharsetCnvEntry::Offset()
sl@0: 	{
sl@0: 	return (_FOFF(TCharsetCnvEntry, iLink));
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Standard factory method for CCharsetCnvCache objects creation.
sl@0: Note: Static method.
sl@0: @return A pointer to the created CCharsetCnvCache instance.
sl@0: @leave KErrNoMemory
sl@0: */
sl@0: CCharsetCnvCache* CCharsetCnvCache::NewL()
sl@0: 	{
sl@0: 	CCharsetCnvCache* self = new (ELeave) CCharsetCnvCache;
sl@0: 	return self;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: */
sl@0: CCharsetCnvCache::~CCharsetCnvCache()
sl@0: 	{
sl@0: 	//Destroy all cache entries - destroy the implementation, delete the entry.
sl@0: 	TSglQueIter<TCharsetCnvEntry> it(iCache);
sl@0:     it.SetToFirst();
sl@0: 	TCharsetCnvEntry* entry;
sl@0: 	while((entry = it++) != NULL)
sl@0: 		{
sl@0: 		delete entry->iCharsetCnv;
sl@0: 		delete entry;
sl@0: 		--iCacheSize;
sl@0: 		}
sl@0: 	//If iCacheSize is not 0, then there is something wrong with adding/removing cache entry functionality
sl@0: 	if ( iCacheSize != 0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CCHARSETCNVCACHE_CCHARSETCNVCACHE, "iCacheSize not zero in CCharsetCnvCache::~CCharsetCnvCache" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(iCacheSize == 0, User::Invariant());
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: The method searches the cache for a character set converter, which implementation UID matches 
sl@0: aImplUid argument. If such converter does not exist in the cache - its implementaion will 
sl@0: be loaded and cached. If the cache has more than iMaxCacheSize entries, the last cache entry 
sl@0: will be removed. The found/loaded library will be moved to be the first entry in the cache.
sl@0: The implementation UID of the converter is used as a key, uniquely identifying the cache entries.
sl@0: @param aImplUid Implementation UID of the required character set converter.
sl@0: @return A pointer to CCharacterSetConverterPluginInterface instance.
sl@0: @leave KErrNoMemory
sl@0: @leave System-wide error codes as well - loading converter implementation related problems.
sl@0: @panic User::Invariant() The returned cache entry is NULL.
sl@0: */
sl@0: CCharacterSetConverterPluginInterface* CCharsetCnvCache::GetConverterL(TUid aImplUid)
sl@0: 	{
sl@0: 	TCharsetCnvEntry* entry = Find(aImplUid);
sl@0: 	if(entry)
sl@0: 		{//The requested entry exists in the cache.
sl@0: 		 //1) Remove the entry (iCache object maintains a list of pointers).
sl@0: 		 //2) Add it as a first entry in the cache. It guarantees that if a cache overflow 
sl@0: 		 //happens, the last used/loaded cache entry won't be removed and destroyed.
sl@0: 		iCache.Remove(*entry);
sl@0: 		iCache.AddFirst(*entry);
sl@0: 		}
sl@0: 	else
sl@0: 		{//The requested entry is not in the cache - load it.
sl@0: 		 //If the cache gets too big - remove and destroy the last cache entry.
sl@0: 		TCharsetCnvEntry* newEntry = CreateNewL(aImplUid);
sl@0: 		iCache.AddFirst(*newEntry);
sl@0: 		entry = iCache.First();
sl@0: 		if(++iCacheSize > iMaxCacheSize)
sl@0: 			{
sl@0: 			RemoveLast();
sl@0: 			--iCacheSize;
sl@0: 			}
sl@0: 		}
sl@0: 	if ( !entry )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCHARSETCNVCACHE_GETCONVERTERL, "entry NULL in CCharsetCnvCache::GetConverterL" );   
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(entry, User::Invariant());
sl@0: 	return entry->iCharsetCnv;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: The method searches the cache for a character set converter, which implementation UID matches 
sl@0: the supplied UID argument. If such converter does not exist in the cache - the method panics.
sl@0: The implementation UID of the converter is used as a key, uniquely identifying the cache entries.
sl@0: @param aImplUid Implementation UID of the required character set converter.
sl@0: @return A pointer to CCharacterSetConverterPluginInterface instance.
sl@0: @panic EPanicCharacterSetConverterNotLoaded There is no converter implementation in the cache, which 
sl@0: 											implementation UID is equal to aImplUid.
sl@0: */
sl@0: CCharacterSetConverterPluginInterface* CCharsetCnvCache::Converter(TUid aImplUid)
sl@0: 	{
sl@0: 	TCharsetCnvEntry* entry = Find(aImplUid);
sl@0: 	if ( entry == NULL || entry->iCharsetCnv == NULL )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCHARSETCNVCACHE_CONVERTER, "entry or entry->iCharsetCnv NULL in CCharsetCnvCache::Converter" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(entry != NULL && entry->iCharsetCnv != NULL, Panic(EPanicCharacterSetConverterNotLoaded));
sl@0: 	iCache.Remove(*entry);
sl@0: 	iCache.AddFirst(*entry);
sl@0: 	return entry->iCharsetCnv;	
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: The method sets the max size of the character set converter cache.
sl@0: By default (if SetMaxSize() is never called) the max cache size is limited to 
sl@0: KDefaultMaxCacheSize entries.
sl@0: Note: Setting very small cache size will impact the overall performance of CHARCONV functions.
sl@0: @param aSize The new max cache size. It must be bigger or equal to KMinCacheSize.
sl@0: @panic User::Invariant() if the new max cache size is less than KMinCacheSize.
sl@0: @see KDefaultMaxCacheSize
sl@0: @see KMinCacheSize
sl@0: */
sl@0: void CCharsetCnvCache::SetMaxSize(TInt aSize)
sl@0: 	{
sl@0: 	if ( aSize < KMinCacheSize )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCHARSETCNVCACHE_SETMAXSIZE, "aSize < KMinCacheSize in CCharsetCnvCache::SetMaxSize" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aSize >= KMinCacheSize, User::Invariant());
sl@0: 	//Remove and destroy the last cache entries, if iCacheSize > aSize.
sl@0: 	for(;iCacheSize>aSize;--iCacheSize)
sl@0: 		{
sl@0: 		RemoveLast();
sl@0: 		}
sl@0: 	iMaxCacheSize = aSize;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: */
sl@0: CCharsetCnvCache::CCharsetCnvCache() :
sl@0: 	iMaxCacheSize(KDefaultMaxCacheSize),
sl@0: 	iCacheSize(0),
sl@0: 	iCache(TCharsetCnvEntry::Offset())
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: The method searches the cache for a converter which implementation UID matches aImplUid argument.
sl@0: If such entry exists, a pointer to it will be returned.
sl@0: @param aImplUid Implementation UID of the searched character set converter.
sl@0: @return A pointer to the found cache entry or NULL if there is no such entry.
sl@0: */
sl@0: CCharsetCnvCache::TCharsetCnvEntry* CCharsetCnvCache::Find(TUid aImplUid)
sl@0: 	{
sl@0: 	TSglQueIter<TCharsetCnvEntry> it(iCache);
sl@0:     it.SetToFirst();
sl@0: 	TCharsetCnvEntry* entry = NULL;
sl@0: 	while((entry = it++) != NULL && entry->iImplUid != aImplUid)
sl@0: 		{
sl@0: 		}
sl@0: 	return entry;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: The method creates a new CCharsetCnvCache::TCharsetCnvEntry instance in the heap. It will load
sl@0: the required character set converter plugin.
sl@0: @param aImplUid Implementation UID of the character set converter to be loaded.
sl@0: @return A pointer to the created CCharsetCnvCache::TCharsetCnvEntry instance.
sl@0: @leave KErrNoMemory
sl@0: @leave System-wide error codes as well - loading converter plugin related problems.
sl@0: @panic User::Invariant(), if the loaded library does not export all expected functions.
sl@0: */
sl@0: CCharsetCnvCache::TCharsetCnvEntry* CCharsetCnvCache::CreateNewL(TUid aImplUid)
sl@0: 	{
sl@0: 	CCharsetCnvCache::TCharsetCnvEntry* newEntry = new (ELeave) CCharsetCnvCache::TCharsetCnvEntry;
sl@0: 	CleanupStack::PushL(newEntry);
sl@0: 
sl@0: 	newEntry->iCharsetCnv = CCharacterSetConverterPluginInterface::NewL(aImplUid);
sl@0: 	newEntry->iImplUid = aImplUid;
sl@0: 
sl@0: 	CleanupStack::Pop(newEntry);
sl@0: 	return newEntry;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: The method removes and destroys the last cache entry.
sl@0: The related converter implementation will be destroyed, the entry - deleted.
sl@0: @panic User::Invariant() If the last cache entry is NULL.
sl@0: */
sl@0: void CCharsetCnvCache::RemoveLast()
sl@0: 	{
sl@0: 	TCharsetCnvEntry* lastEntry = iCache.Last();
sl@0: 	if ( !lastEntry )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCHARSETCNVCACHE_REMOVELAST, "lastEntry NULL in CCharsetCnvCache::RemoveLast" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(lastEntry, User::Invariant());
sl@0: 	iCache.Remove(*lastEntry);
sl@0: 	delete lastEntry->iCharsetCnv;
sl@0: 	delete lastEntry;
sl@0: 	}
sl@0: 	
sl@0: // CCnvCharacterSetConverter
sl@0: 
sl@0: /** Allocates and constructs a CCnvCharacterSetConverter object. If there is 
sl@0: insufficient memory to create the object, the function leaves.
sl@0: 
sl@0: Since the memory is allocated on the heap, objects of this type should be 
sl@0: destroyed using the delete operator when the required conversions are complete.
sl@0: 
sl@0: @return The newly created object. */
sl@0: EXPORT_C CCnvCharacterSetConverter* CCnvCharacterSetConverter::NewL()
sl@0: 	{
sl@0: 	CCnvCharacterSetConverter* characterSetConverter=NewLC();
sl@0: 	CleanupStack::Pop(); // characterSetConverter
sl@0: 	return characterSetConverter;
sl@0: 	}
sl@0: 
sl@0: /** Allocates and constructs a CCnvCharacterSetConverter object, and leaves the 
sl@0: object on the cleanup stack. If there is insufficient memory to create the 
sl@0: object, the function leaves.
sl@0: 
sl@0: Since the memory is allocated on the heap, objects of this type should be 
sl@0: destroyed using either the CleanupStack::Pop() function and then the delete 
sl@0: operator, or the CleanupStack::PopAndDestroy() function.
sl@0: 
sl@0: @return The newly created object. */
sl@0: EXPORT_C CCnvCharacterSetConverter* CCnvCharacterSetConverter::NewLC()
sl@0: 	{
sl@0: 	CCnvCharacterSetConverter* characterSetConverter=new(ELeave) CCnvCharacterSetConverter;
sl@0: 	characterSetConverter->iTlsDataConstructed=EFalse;
sl@0: 	CleanupStack::PushL(characterSetConverter);
sl@0: 	characterSetConverter->ConstructL();
sl@0: 	return characterSetConverter;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** The destructor frees all resources owned by the object, prior to its 
sl@0: destruction. */
sl@0: EXPORT_C CCnvCharacterSetConverter::~CCnvCharacterSetConverter()
sl@0: 	{
sl@0: 	delete iStandardNamesAndMibEnums;
sl@0: 	if (iTlsDataConstructed)
sl@0: 		{
sl@0: 		TTlsData::CharacterSetConverterIsBeingDestroyed();		
sl@0: 		}
sl@0: 	delete iCharsetCnvCache;
sl@0: 	REComSession::FinalClose();
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Creates an array identifying all the character sets for which conversion is 
sl@0: available. These can be character sets for which conversion is built into 
sl@0: Symbian OS, or they may be character sets for which conversion is implemented 
sl@0: by a plug-in DLL.
sl@0: 
sl@0: The array returned can be used by one of the PrepareToConvertToOrFromL() 
sl@0: overloads to provide a list of all the character sets available for conversion. 
sl@0: The caller of this function is responsible for deleting the array, and should 
sl@0: not modify it.
sl@0: 
sl@0: Not all encoders returned will be suitable for conversion from Unicode. 
sl@0: Such encoders have no name and no MIB enum and so will generally not be understood by 
sl@0: a receiving process. The function ConvertCharacterSetIdentifierToMibEnumL can be used 
sl@0: to determine whether this is the case or not.
sl@0: 
sl@0: @param aFileServerSession A file server session. This is no longer used, but is kept for Binary Compatibility.
sl@0: @return An array identifying all supported character sets. */
sl@0: EXPORT_C CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* 
sl@0: CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL(RFs& aFileServerSession)
sl@0: 	{
sl@0: 	
sl@0: 	CArrayFix<SCharacterSet>* arrayOfCharacterSetsAvailable=CreateArrayOfCharacterSetsAvailableLC(aFileServerSession);
sl@0: 	CleanupStack::Pop(); // arrayOfCharacterSetsAvailable
sl@0: 	return arrayOfCharacterSetsAvailable;
sl@0: 	
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Creates an array identifying all the character sets for which conversion is 
sl@0: available and pushes a pointer to it onto the cleanup stack. These can be 
sl@0: character sets for which conversion is built into Symbian OS, or they may 
sl@0: be character sets for which conversion is implemented by a plug-in DLL.
sl@0: 
sl@0: The array returned can be used by one of the PrepareToConvertToOrFromL() 
sl@0: overloads to provide a list of all the character sets available for conversion. 
sl@0: The caller of this function is responsible for deleting the array, and should 
sl@0: not modify it.
sl@0: 
sl@0: Not all encoders returned will be suitable for conversion from Unicode. 
sl@0: Such encoders have no name and no MIB enum and so will generally not be understood by 
sl@0: a receiving process. The function ConvertCharacterSetIdentifierToMibEnumL can be used 
sl@0: to determine whether this is the case or not.
sl@0: 
sl@0: This is a static function which uses ECOM functionality. It cleans up ECOM by calling FinalClose()
sl@0: 
sl@0: @param aFileServerSession A file server session. This is no longer required, kept for Binary Compatibilty.
sl@0: @return An array of references to all supported character sets. */
sl@0: EXPORT_C CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* 
sl@0: CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableLC(RFs& aFileServerSession)
sl@0: 	{
sl@0: 	
sl@0: 	CleanupStack::PushL(TCleanupItem(CloseECOMSession, NULL));
sl@0: 
sl@0: 	CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* result = 
sl@0: 		DoCreateArrayOfCharacterSetsAvailableLC(aFileServerSession, 0);
sl@0: 
sl@0: 	CleanupStack::Pop();//CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* result
sl@0: 	CleanupStack::PopAndDestroy(); //CloseECOMSession
sl@0: 	CleanupStack::PushL(result);
sl@0: 
sl@0: 	return result;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Gets the UID of a character set identified by its Internet-standard name 
sl@0: (the matching is case-insensitive).
sl@0: 
sl@0: If the character set specified is not one for which Symbian OS provides 
sl@0: built-in conversion, the function searches the file system for plug-ins 
sl@0: which implement the conversion and which provide the name-to-UID mapping 
sl@0: information.
sl@0: 
sl@0: @param aStandardNameOfCharacterSet Internet-standard name of a character set.
sl@0: @param aFileServerSession Connection to a file server session.
sl@0: @return The UID for the character set if the character set with a Internet-standard name
sl@0: 		has a known name and MIB enum.Otherwise zero is returned. */ 
sl@0: EXPORT_C TUint 
sl@0: CCnvCharacterSetConverter::ConvertStandardNameOfCharacterSetToIdentifierL(
sl@0: 								const TDesC8& aStandardNameOfCharacterSet, 
sl@0: 								RFs& aFileServerSession)
sl@0: 	{
sl@0: 	if (iStandardNamesAndMibEnums==NULL)
sl@0: 		{
sl@0: 		ScanForStandardNamesAndMibEnumsROMOnlyL(aFileServerSession);
sl@0: 		}
sl@0: 	TUint result=iStandardNamesAndMibEnums->Identifier(aStandardNameOfCharacterSet);
sl@0: 	if(result)
sl@0: 		{
sl@0: 		return result;
sl@0: 		}
sl@0: 	if(!iIsSystemStandardNamesAndMibEnumsScanned)
sl@0: 		{
sl@0: 		//If SNM files in system haven't been scan yet, scan them
sl@0: 		ScanForStandardNamesAndMibEnumsL(aFileServerSession);
sl@0: 		iIsSystemStandardNamesAndMibEnumsScanned = ETrue;
sl@0: 		return iStandardNamesAndMibEnums->Identifier(aStandardNameOfCharacterSet);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		//iStandardNamesAndMibEnums has included those snm files in system
sl@0: 		return 0;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Returns the Internet-standard name of a character set identified in Symbian 
sl@0: OS by a UID.
sl@0: 
sl@0: If the character set specified is not one for which Symbian OS provides 
sl@0: built-in conversion, the file system is searched for plug-ins which implement 
sl@0: the conversion, hence the need for a file server session.
sl@0: 
sl@0: @param aCharacterSetIdentifier The UID of the character set.
sl@0: @param aFileServerSession A file server session.
sl@0: @return The Internet-standard name for the character set if the character set with an identifier
sl@0: 		has a known name and MIB enum.Otherwise NULL is returned. */ 
sl@0: EXPORT_C HBufC8* 
sl@0: CCnvCharacterSetConverter::ConvertCharacterSetIdentifierToStandardNameL(
sl@0: 								TUint aCharacterSetIdentifier, 
sl@0: 								RFs& aFileServerSession)
sl@0: 	{
sl@0: 	if (iStandardNamesAndMibEnums==NULL)
sl@0: 		{
sl@0: 		ScanForStandardNamesAndMibEnumsROMOnlyL(aFileServerSession);
sl@0: 		}
sl@0: 	HBufC8* result = iStandardNamesAndMibEnums->StandardNameL(aCharacterSetIdentifier);
sl@0: 	if (result!=NULL)
sl@0: 		{
sl@0: 		return result;
sl@0: 		}
sl@0: 	if(!iIsSystemStandardNamesAndMibEnumsScanned)
sl@0: 		{
sl@0: 		//If SNM files in system haven't been scan yet, scan them
sl@0: 		ScanForStandardNamesAndMibEnumsL(aFileServerSession);
sl@0: 		iIsSystemStandardNamesAndMibEnumsScanned = ETrue;
sl@0: 		return iStandardNamesAndMibEnums->StandardNameL(aCharacterSetIdentifier);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		//iStandardNamesAndMibEnums has included those snm files in system
sl@0: 		return NULL;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Converts a MIB enum value to the UID value of the character set.
sl@0: 
sl@0: If the character set identified is not one for which Symbian OS provides 
sl@0: built-in conversion, the function searches the file system for plug-ins 
sl@0: which implement the conversion and which provide the MIB enum-to-UID mapping 
sl@0: information.
sl@0: 
sl@0: @param aMibEnumOfCharacterSet The MIB enum value of the character set.
sl@0: @param aFileServerSession Connection to a file server session.
sl@0: @return TThe UID of the character set if the character set with a Mib enum 
sl@0: 		has a known name and MIB enum.Otherwise zero is returned. */ 
sl@0: EXPORT_C TUint 
sl@0: CCnvCharacterSetConverter::ConvertMibEnumOfCharacterSetToIdentifierL(
sl@0: 								TInt aMibEnumOfCharacterSet, 
sl@0: 								RFs& aFileServerSession)
sl@0: 	{
sl@0: 	if (iStandardNamesAndMibEnums==NULL)
sl@0: 		{
sl@0: 		ScanForStandardNamesAndMibEnumsROMOnlyL(aFileServerSession);
sl@0: 		}
sl@0: 	TUint result = iStandardNamesAndMibEnums->Identifier(aMibEnumOfCharacterSet);
sl@0: 	if (result)
sl@0: 		{
sl@0: 		return result;
sl@0: 		}
sl@0: 	if(!iIsSystemStandardNamesAndMibEnumsScanned)
sl@0: 		{
sl@0: 		//If SNM files in system haven't been scan yet, scan them
sl@0: 		ScanForStandardNamesAndMibEnumsL(aFileServerSession);
sl@0: 		iIsSystemStandardNamesAndMibEnumsScanned = ETrue;
sl@0: 		return iStandardNamesAndMibEnums->Identifier(aMibEnumOfCharacterSet);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		//iStandardNamesAndMibEnums has included those snm files in system
sl@0: 		return 0;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Converts the UID of a character set to its MIB enum value.
sl@0: 
sl@0: If the character set identified is not one for which Symbian OS provides 
sl@0: built-in conversion, the function searches the file system for plug-ins 
sl@0: which implement the conversion and which provide the UID-to-MIB enum mapping 
sl@0: information.
sl@0: 
sl@0: @param aCharacterSetIdentifier The UID of the character set.
sl@0: @param aFileServerSession Connection to a file server session.
sl@0: @return The MIB enum value of the character set if the character set with Identifier 
sl@0: 		has a known name and MIB enum.Otherwise zero is returned. */ 
sl@0: EXPORT_C TInt 
sl@0: CCnvCharacterSetConverter::ConvertCharacterSetIdentifierToMibEnumL(
sl@0: 								TUint aCharacterSetIdentifier, 
sl@0: 								RFs& aFileServerSession)
sl@0: 	{
sl@0: 	if (iStandardNamesAndMibEnums==NULL)
sl@0: 		{
sl@0: 		ScanForStandardNamesAndMibEnumsROMOnlyL(aFileServerSession);
sl@0: 		}
sl@0: 	TInt result = iStandardNamesAndMibEnums->MibEnum(aCharacterSetIdentifier);
sl@0: 	if (result)
sl@0: 		{
sl@0: 		return result;
sl@0: 		}
sl@0: 	if(!iIsSystemStandardNamesAndMibEnumsScanned)
sl@0: 		{
sl@0: 		//If SNM files in system haven't been scan yet, scan them
sl@0: 		ScanForStandardNamesAndMibEnumsL(aFileServerSession);
sl@0: 		iIsSystemStandardNamesAndMibEnumsScanned = ETrue;
sl@0: 		return iStandardNamesAndMibEnums->MibEnum(aCharacterSetIdentifier);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		//iStandardNamesAndMibEnums has included those snm files in system
sl@0: 		return 0;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** Specifies the character set to convert to or from. aCharacterSetIdentifier 
sl@0: is a UID which identifies a character set. It can be one of the character 
sl@0: sets for which conversion is built into Symbian OS, or it may be a character 
sl@0: set for which the conversion is implemented by a plug-in DLL.
sl@0: 
sl@0: The function searches the character set array specified 
sl@0: (aArrayOfCharacterSetsAvailable). This is an array containing all of the 
sl@0: character sets for which conversion is available. It is created by calling 
sl@0: CreateArrayOfCharacterSetsAvailableL() or 
sl@0: CreateArrayOfCharacterSetsAvailableLC(). You should be sure that conversion 
sl@0: is available for aCharacterSetIdentifier, because if not, a panic occurs. 
sl@0: Otherwise, use the other overload of this function.
sl@0: 
sl@0: Either this function or its overload, must be called before using the conversion 
sl@0: functions ConvertFromUnicode() or ConvertToUnicode().
sl@0: 
sl@0: Unlike the other overload, this function does not search the file system for 
sl@0: plug-in conversion DLLs, (unless aArrayOfCharacterSetsAvailable is NULL). 
sl@0: This function should be used if conversions are to be performed often, or 
sl@0: if the conversion character set is to be selected by the user. Generating 
sl@0: the array of all the available character sets once and searching though it 
sl@0: is more efficient than the method used by the other overload, in which the 
sl@0: file system may be searched every time it is invoked.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: The file server session argument is used to open the required character set 
sl@0: conversion data file.
sl@0: 
sl@0: The array passed to this function can also be used to provide a list from 
sl@0: which a user can select the desired conversion character set.
sl@0: 
sl@0: @param aCharacterSetIdentifier The UID of the non-Unicode character set from 
sl@0: or to which to convert. Must not be zero, or a panic occurs.
sl@0: @param aArrayOfCharacterSetsAvailable Array of all character sets for which 
sl@0: conversion is available, created by either 
sl@0: CreateArrayOfCharacterSetsAvailableLC() or 
sl@0: CreateArrayOfCharacterSetsAvailableL().
sl@0: @param aFileServerSession A file server session. No longer used, kept for Binary Compatibility */
sl@0: EXPORT_C void 
sl@0: CCnvCharacterSetConverter::PrepareToConvertToOrFromL(
sl@0: 				TUint aCharacterSetIdentifier, 
sl@0: 				const CArrayFix<SCharacterSet>& aArrayOfCharacterSetsAvailable, 
sl@0: 				RFs& aFileServerSession)
sl@0: 	{
sl@0: 	const TAvailability availability=DoPrepareToConvertToOrFromL(aCharacterSetIdentifier, 
sl@0: 																 &aArrayOfCharacterSetsAvailable, 
sl@0: 																 aFileServerSession);
sl@0: 	if (availability!=EAvailable)
sl@0: 		{
sl@0: 		OstTrace0( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_PREPARETOCONVERTTOORFROML, "Conversion Not found in CCnvCharacterSetConverter::PrepareToConvertToOrFromL" );
sl@0: 		User::Leave(KErrNotFound);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: /** Specifies the character set to convert to or from. aCharacterSetIdentifier 
sl@0: is a UID which identifies a character set. It can be one of the character 
sl@0: sets for which conversion is built into Symbian OS, or it may be a character 
sl@0: set for which conversion is implemented by a plug-in DLL. In the latter case, 
sl@0: the function searches through the file system for the DLL which implements 
sl@0: the character conversion.
sl@0: 
sl@0: Either this function or its overload must be called before using the conversion 
sl@0: functions ConvertFromUnicode() or ConvertToUnicode().
sl@0: 
sl@0: This overload of the function is simpler to use than the other and does not 
sl@0: panic if the character set with the specified UID is not available at run 
sl@0: timeÂ, it simply returns ENotAvailable. It should be used when the conversion 
sl@0: character set is specified within the text object being converted, e.g. an 
sl@0: email message, or an HTML document. If the character set is not specified, 
sl@0: the user must be presented with a list of all available sets, so it makes 
sl@0: sense to use the other overload.
sl@0: 
sl@0: The function may need to search the file system each time it is called. If 
sl@0: conversion takes place repeatedly over a short period, it may be more efficient 
sl@0: to use the other overload.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: Although the other overload of this function is more efficient, if the 
sl@0: character set is one for which conversion is built into Symbian OS, the 
sl@0: difference in speed is negligible.
sl@0: 
sl@0: @param aCharacterSetIdentifier The UID of the non-Unicode character set from 
sl@0: or to which to convert. Must not be zero, or a panic occurs.
sl@0: @param aFileServerSession A file server session. No longer used, kept for Binary Compatibility
sl@0: @return The availability of the specified character set. If EAvailable is 
sl@0: returned, then the conversion functions ConvertToUnicode() and 
sl@0: ConvertFromUnicode() will use aCharacterSetIdentifier as the foreign character 
sl@0: set. If ENotAvailable is returned, then the foreign character set will either 
sl@0: be undefined (and trying to use the conversion functions will cause a panic), 
sl@0: or if it has previously been set, it will remain unchanged. */
sl@0: EXPORT_C CCnvCharacterSetConverter::TAvailability 
sl@0: CCnvCharacterSetConverter::PrepareToConvertToOrFromL(TUint aCharacterSetIdentifier, 
sl@0: 													 RFs& aFileServerSession)
sl@0: 	{
sl@0: 	return DoPrepareToConvertToOrFromL(aCharacterSetIdentifier, NULL, aFileServerSession);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Sets the default endian-ness used by the ConvertFromUnicode() and 
sl@0: ConvertToUnicode() functions to convert between Unicode and non-Unicode 
sl@0: character sets.
sl@0: 
sl@0: The endian-ness of a multi-byte character set may be defined in the character 
sl@0: set definition or, as in the case of UCS-2, be operating system dependent. 
sl@0: If the endian-ness of the current character set is defined by the character 
sl@0: set itself, then the default endian-ness specified by this function is ignored.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: The issue of endian-ness does not apply to single byte character sets 
sl@0: as there is no byte order.
sl@0: 
sl@0: This function should be called (if at all) after calling 
sl@0: PrepareToConvertToOrFromL() and before calling ConvertFromUnicode() and/or 
sl@0: ConvertToUnicode().
sl@0: 
sl@0: @param aEndianness The default endian-ness of the current character set. */
sl@0: EXPORT_C void 
sl@0: CCnvCharacterSetConverter::SetDefaultEndiannessOfForeignCharacters(
sl@0: 											TEndianness aDefaultEndiannessOfForeignCharacters)
sl@0:     {
sl@0:     if ( (aDefaultEndiannessOfForeignCharacters!=ELittleEndian) && (aDefaultEndiannessOfForeignCharacters!=EBigEndian) )
sl@0:         {
sl@0:         OstTrace0( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_SETDEFAULTENDIANNESSOFFOREIGNCHARACTERS, "Bad Default Endianness Of Foreign Characters in CCnvCharacterSetConverter::SetDefaultEndiannessOfForeignCharacters" );        
sl@0:         }
sl@0: 	__ASSERT_ALWAYS((aDefaultEndiannessOfForeignCharacters==ELittleEndian) || (aDefaultEndiannessOfForeignCharacters==EBigEndian), Panic(EPanicBadDefaultEndiannessOfForeignCharacters));
sl@0: 	iDefaultEndiannessOfForeignCharacters=aDefaultEndiannessOfForeignCharacters;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Sets whether the Unicode 'line separator' and 'paragraph separator' 
sl@0: characters (0x2028 and 0x2029 respectively) should be converted into a 
sl@0: carriage return / line feed pair, or into a line feed only when converting 
sl@0: from Unicode into a foreign character set. This applies to all foreign 
sl@0: character sets that do not contain a direct equivalent of these Unicode 
sl@0: character codes.
sl@0: 
sl@0: By default, line and paragraph separators are converted into a CR/LF pair. 
sl@0: This function should be called (if at all) after calling 
sl@0: PrepareToConvertToOrFromL() and before calling ConvertFromUnicode() and/or 
sl@0: ConvertToUnicode().
sl@0: 
sl@0: @param aDowngradeForExoticLineTerminatingCharacters Specify 
sl@0: EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed if 
sl@0: line/paragraph separators should be converted into a carriage return and 
sl@0: line feed combination and 
sl@0: EDowngradeExoticLineTerminatingCharactersToJustLineFeed if they should be 
sl@0: converted into line feeds only. Any other value causes the function to panic. */
sl@0: EXPORT_C void 
sl@0: CCnvCharacterSetConverter::SetDowngradeForExoticLineTerminatingCharacters(
sl@0: 	TDowngradeForExoticLineTerminatingCharacters aDowngradeForExoticLineTerminatingCharacters)
sl@0: 	{
sl@0:     if ( (aDowngradeForExoticLineTerminatingCharacters!=EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed) && (aDowngradeForExoticLineTerminatingCharacters!=EDowngradeExoticLineTerminatingCharactersToJustLineFeed) )
sl@0:     {
sl@0:     OstTrace0( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_SETDOWNGRADEFOREXOTICLINETERMINATINGCHARACTERS, "Bad Downgrade For Exotic Line Terminating Characters1 in CCnvCharacterSetConverter::SetDowngradeForExoticLineTerminatingCharacters" );
sl@0:     }
sl@0: 	__ASSERT_ALWAYS((aDowngradeForExoticLineTerminatingCharacters==EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed) || (aDowngradeForExoticLineTerminatingCharacters==EDowngradeExoticLineTerminatingCharactersToJustLineFeed), Panic(EPanicBadDowngradeForExoticLineTerminatingCharacters1));
sl@0: 	iDowngradeForExoticLineTerminatingCharacters=aDowngradeForExoticLineTerminatingCharacters;
sl@0: 	}
sl@0: 
sl@0: /** Sets the character used to replace unconvertible characters in the output 
sl@0: descriptor, when converting from Unicode into another character set.
sl@0: 
sl@0: The default replacement for unconvertible Unicode characters is specified 
sl@0: in the conversion data for the character set. The replacement text which is 
sl@0: set using this function overrides the default value.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: If the replacement character is multi-byte, and its endian-ness is undefined 
sl@0: in the character set, then its byte order is taken by default to be 
sl@0: little-endian.
sl@0: 
sl@0: PrepareToConvertToOrFromL() undoes the effect of any previous calls to this 
sl@0: function. So, to have any effect, this function should be called between the 
sl@0: PrepareToConvertToOrFromL() call and the subsequent ConvertFromUnicode() call 
sl@0: or calls.
sl@0: 
sl@0: The value only applies when converting from Unicode to another character set. 
sl@0: In Unicode, the code for  'unknown character'is always 0xFFFD.
sl@0: 
sl@0: @param aReplacementForUnconvertibleUnicodeCharacters The single character 
sl@0: which is to be used to replace unconvertible characters. */
sl@0: EXPORT_C void 
sl@0: CCnvCharacterSetConverter::SetReplacementForUnconvertibleUnicodeCharactersL(
sl@0: 								const TDesC8& aReplacementForUnconvertibleUnicodeCharacters)
sl@0: 	{
sl@0: 	iReplacementForUnconvertibleUnicodeCharacters=aReplacementForUnconvertibleUnicodeCharacters;
sl@0: 	}
sl@0: 
sl@0: /** Converts text encoded in the Unicode character set (UCS-2) into other
sl@0: character sets.
sl@0: 
sl@0: The first overload of the function simply performs the conversion. The
sl@0: second overload converts the text and gets the number of characters
sl@0: that could not be converted. The third overload converts the text,
sl@0: gets the number of characters that could not be converted, and also
sl@0: gets the index of the first character that could not be converted. A
sl@0: fourth overload was introduced in v6.0 see below.All overloads cause a
sl@0: panic if no target character set has been selected to convert to (i.e.
sl@0: either overload of PrepareToConvertToOrFromL() must have
sl@0: been successfully called beforehand). You may also need to call
sl@0: SetDefaultEndiannessOfForeignCharacters() to define the
sl@0: endian-ness of the output descriptor.Notes:A sixteen-bit descriptor is
sl@0: used to hold the source Unicode encoded text, and an eight-bit
sl@0: descriptor is used to hold the converted non-Unicode text. Eight-bit
sl@0: descriptors are used because non-Unicode character sets may use a
sl@0: single byte per character (e.g. Code Page 1252) or more than one byte
sl@0: per character (e.g. GB 2312-80) or even a variable number of bytes per
sl@0: character (e.g. Shift-JIS).The function will fail to convert all the
sl@0: input descriptor if the output descriptor is not long enough to hold
sl@0: all the text.Unicode characters cannot be converted if there is no
sl@0: equivalent for them in the target character set. This does not stop
sl@0: the conversion, the missing character is simply replaced by the
sl@0: character in the target character set which represents unknown
sl@0: characters. This default unknown character can be changed using
sl@0: SetReplacementForUnconvertibleUnicodeCharactersL().
sl@0: 
sl@0: @param aForeign  On return, contains the converted text in a non-Unicode 
sl@0: character set.
sl@0: @param aUnicode The source Unicode text to be converted.
sl@0: @param aNumberOfUnconvertibleCharacters On return contains the number of 
sl@0: characters which could not be converted.
sl@0: @param aIndexOfFirstUnconvertibleCharacter On return, contains the index 
sl@0: of the first character in the input text that could not be converted. The
sl@0: value is negative if all characters were converted.
sl@0: @return The number of unconverted characters left at the end of the input 
sl@0: descriptor (e.g. because the output descriptor is not long enough to hold 
sl@0: all the text), or one of the error values defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertFromUnicode(TDes8& aForeign,
sl@0: 															const TDesC16& aUnicode) const
sl@0:  	{
sl@0: 	TArrayOfAscendingIndices notUsed;
sl@0: 	return ConvertFromUnicode(aForeign, aUnicode, notUsed);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertFromUnicode(TDes8& aForeign, const TDesC16& aUnicode, TInt& aNumberOfUnconvertibleCharacters) const
sl@0: 	{
sl@0: 	TArrayOfAscendingIndices indicesOfUnconvertibleCharacters;
sl@0: 	const TInt returnValue=ConvertFromUnicode(aForeign, aUnicode, indicesOfUnconvertibleCharacters);
sl@0: 	aNumberOfUnconvertibleCharacters=indicesOfUnconvertibleCharacters.NumberOfIndices();
sl@0: 	return returnValue;
sl@0: 	}
sl@0: 
sl@0: /** Converts text encoded in the Unicode character set (UCS-2) into other 
sl@0: character sets.
sl@0: 
sl@0: The first overload of the function simply performs the conversion. The second 
sl@0: overload converts the text and gets the number of characters that could not 
sl@0: be converted. The third overload converts the text, gets the number of 
sl@0: characters that could not be converted, and also gets the index of the first 
sl@0: character that could not be converted. A fourth overload was introduced in v6,
sl@0: see below.
sl@0: 
sl@0: All overloads cause a panic if no target character set has been selected to 
sl@0: convert to (i.e. either overload of PrepareToConvertToOrFromL() must have 
sl@0: been successfully called beforehand). You may also need to call 
sl@0: SetDefaultEndiannessOfForeignCharacters() to define the endian-ness of the 
sl@0: output descriptor.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: A sixteen-bit descriptor is used to hold the source Unicode encoded text, 
sl@0: and an eight-bit descriptor is used to hold the converted non-Unicode text. 
sl@0: Eight-bit descriptors are used because non-Unicode character sets may use 
sl@0: a single byte per character (e.g. Code Page 1252) or more than one byte per 
sl@0: character (e.g. GB 2312-80) or even a variable number of bytes per character 
sl@0: (e.g. Shift-JIS).
sl@0: 
sl@0: The function will fail to convert all the input descriptor if the output 
sl@0: descriptor is not long enough to hold all the text.
sl@0: 
sl@0: Unicode characters cannot be converted if there is no equivalent for them 
sl@0: in the target character set. This does not stop the conversion, the missing 
sl@0: character is simply replaced by the character in the target character set 
sl@0: which represents unknown characters. This default unknown character can be 
sl@0: changed using SetReplacementForUnconvertibleUnicodeCharactersL().
sl@0: 
sl@0: @param aForeign On return, contains the converted text in a non-Unicode 
sl@0: character set.
sl@0: @param aUnicode The source Unicode text to be converted.
sl@0: @param aNumberOfUnconvertibleCharacters On return contains the number of 
sl@0: characters which could not be converted.
sl@0: @param aIndexOfFirstUnconvertibleCharacter On return, contains the index of 
sl@0: the first character in the input text that could not be converted. The value 
sl@0: is negative if all characters were converted.
sl@0: @return The number of unconverted characters left at the end of the input 
sl@0: descriptor (e.g. because the output descriptor is not long enough to hold all 
sl@0: the text), or one of the error values defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertFromUnicode(
sl@0: 												TDes8& aForeign,
sl@0: 												const TDesC16& aUnicode,
sl@0: 												TInt& aNumberOfUnconvertibleCharacters, 
sl@0: 												TInt& aIndexOfFirstUnconvertibleCharacter) const
sl@0: 	{
sl@0: 	TArrayOfAscendingIndices indicesOfUnconvertibleCharacters;
sl@0: 	const TInt returnValue=ConvertFromUnicode(aForeign, aUnicode, indicesOfUnconvertibleCharacters);
sl@0: 	aNumberOfUnconvertibleCharacters=indicesOfUnconvertibleCharacters.NumberOfIndices();
sl@0: 	aIndexOfFirstUnconvertibleCharacter=(aNumberOfUnconvertibleCharacters==0)? -1: indicesOfUnconvertibleCharacters[0];
sl@0: 	return returnValue;
sl@0: 	}
sl@0: 
sl@0: /** Converts Unicode text into another character set.
sl@0: 
sl@0: Differs from the other overloads of this function by returning the indices 
sl@0: of all of the characters in the source Unicode text which could not be converted.
sl@0: 
sl@0: @param aForeign On return, contains the converted text in a non-Unicode 
sl@0: character set.
sl@0: @param aUnicode The source Unicode text to be converted.
sl@0: @param aIndicesOfUnconvertibleCharacters On return, holds the indices of each 
sl@0: Unicode character in the source text which could not be converted.
sl@0: @return The number of unconverted characters left at the end of the input 
sl@0: descriptor (e.g. because the output descriptor is not long enough to hold all 
sl@0: the text), or one of the error values defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertFromUnicode(
sl@0: 						TDes8& aForeign, 
sl@0: 						const TDesC16& aUnicode, 
sl@0: 						TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters) const
sl@0: 	{
sl@0: 	if ( iCharacterSetIdentifierOfLoadedConversionData==0 )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_CONVERTFROMUNICODE, "NullCharacterSetIdentifier1 in CCnvCharacterSetConverter::ConvertFromUnicode" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(iCharacterSetIdentifierOfLoadedConversionData!=0, Panic(EPanicNullCharacterSetIdentifier1));
sl@0: 	if (aUnicode.Length()==0)
sl@0: 		{
sl@0: 		aForeign.SetLength(0);
sl@0: 		return 0;
sl@0: 		}
sl@0: 	if (aForeign.MaxLength()==0)
sl@0: 		{
sl@0: 		return aUnicode.Length();
sl@0: 		}
sl@0: 	TTlsData::SetCurrentCharacterSetConverter(this);
sl@0: 	TInt returnValue;
sl@0: 	if (iStoredFlags&EStoredFlagConversionPlugInLibraryIsLoaded)
sl@0: 		{
sl@0: 		
sl@0: 		TUid implUid;
sl@0: 		implUid.iUid = iCharacterSetIdentifierOfLoadedConversionData;
sl@0: 		returnValue = (iCharsetCnvCache->Converter(implUid))->ConvertFromUnicode(
sl@0: 														iDefaultEndiannessOfForeignCharacters, 
sl@0: 														iReplacementForUnconvertibleUnicodeCharacters, 
sl@0: 														aForeign, 
sl@0: 														aUnicode, 
sl@0: 														aIndicesOfUnconvertibleCharacters);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		switch (iCharacterSetIdentifierOfLoadedConversionData)
sl@0: 			{
sl@0: 		case KCharacterSetIdentifierUtf7:
sl@0: 			returnValue=CnvUtfConverter::ConvertFromUnicodeToUtf7(aForeign, aUnicode, ETrue);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUtf8:
sl@0: 			returnValue=CnvUtfConverter::ConvertFromUnicodeToUtf8(aForeign, aUnicode);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierImapUtf7:
sl@0: 			returnValue=CnvUtfConverter::ConvertFromUnicodeToUtf7(aForeign, aUnicode, ETrue, EFalse);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierJavaConformantUtf8:
sl@0: 			returnValue=CnvUtfConverter::ConvertFromUnicodeToUtf8(aForeign, aUnicode, ETrue);
sl@0: 			break;
sl@0: 		default:
sl@0: 			__ASSERT_ALWAYS(iConversionData!=NULL, Panic(EPanicNoConversionData1));
sl@0: 			returnValue=DoConvertFromUnicode(*iConversionData, iDefaultEndiannessOfForeignCharacters, iReplacementForUnconvertibleUnicodeCharacters, aForeign, aUnicode, aIndicesOfUnconvertibleCharacters);
sl@0: 			break;
sl@0: 			}
sl@0: 		}
sl@0: 	TTlsData::SetCurrentCharacterSetConverter(NULL);
sl@0: 	return returnValue;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: 
sl@0: /**  Converts text encoded in a non-Unicode character set into the Unicode
sl@0: character set (UCS-2).
sl@0: 
sl@0: The first overload of the function simply performs the conversion. The
sl@0: second overload converts the text and gets the number of bytes in the
sl@0: input string that could not be converted. The third overload converts
sl@0: the text, gets the number of bytes that could not be converted, and
sl@0: also gets the index of the first byte that could not be converted.All
sl@0: overloads cause a panic if no source character set has been selected
sl@0: to convert from (i.e. either overload of PrepareToConvertToOrFromL() 
sl@0: must have been successfully called beforehand). You may also need to call
sl@0: SetDefaultEndiannessOfForeignCharacters() to define the
sl@0: endian-ness of the input descriptor.Notes: Since Unicode is intended to
sl@0: be the superset of all character sets, the function should usually
sl@0: report zero unconverted characters. Unconvertible characters will
sl@0: exist if the input descriptor contains illegal characters, i.e. values
sl@0: not in the selected non-Unicode character set.The presence of illegal
sl@0: characters does not stop the conversion. The missing character is
sl@0: simply replaced by the Unicode character which represents unknown
sl@0: characters (0xFFFD).If the source text consists solely of a
sl@0: character that is not complete, the function returns
sl@0: EErrorIllFormedInput. The reason for this is to prevent
sl@0: the possibility of the calling code getting into a infinite loop.
sl@0: 
sl@0: @param aUnicode  On return, contains the converted text in the Unicode
sl@0: character aForeign The non-Unicode source text to be converted.
sl@0: @param aState This is used to save state information across multiple
sl@0: calls to ConvertToUnicode(). You should initialise the value 
sl@0: to KStateDefault, and then do not change it in a series of 
sl@0: related calls.
sl@0: @param aNumberOfUnconvertibleCharacters  On return, contains the number of 
sl@0: bytes which were not converted.
sl@0: @param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
sl@0: of the first byte of the first unconvertible character. For instance if 
sl@0: the first character in the input descriptor (aForeign) could 
sl@0: not be converted, then this parameter is set to the first byte of that
sl@0: character, i.e. zero. A negative value is returned if  all the characters 
sl@0: were converted.
sl@0: @return The number of unconverted bytes left at the end of the  input 
sl@0: descriptor (e.g. because the output descriptor is not long enough to hold 
sl@0: all the text), or one of the error values defined in TError.*/
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertToUnicode(TDes16& aUnicode, 
sl@0: 														  const TDesC8& aForeign, 
sl@0: 														  TInt& aState) const
sl@0:  	{
sl@0: 	TInt notUsed1;
sl@0: 	TInt notUsed2;
sl@0: 	return ConvertToUnicode(aUnicode, aForeign, aState, notUsed1, notUsed2);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertToUnicode(TDes16& aUnicode, const TDesC8& aForeign, TInt& aState, TInt& aNumberOfUnconvertibleCharacters) const
sl@0: 	{
sl@0: 	TInt notUsed;
sl@0: 	return ConvertToUnicode(aUnicode, aForeign, aState, aNumberOfUnconvertibleCharacters, notUsed);
sl@0: 	}
sl@0: 
sl@0: /** Converts text encoded in a non-Unicode character set into the Unicode 
sl@0: character set (UCS-2).
sl@0: 
sl@0: The first overload of the function simply performs the conversion. The second 
sl@0: overload converts the text and gets the number of bytes in the input string 
sl@0: that could not be converted. The third overload converts the text, gets the 
sl@0: number of bytes that could not be converted, and also gets the index of the 
sl@0: first byte that could not be converted.
sl@0: 
sl@0: All overloads cause a panic if no source character set has been selected to 
sl@0: convert from (i.e. either overload of PrepareToConvertToOrFromL() must have 
sl@0: been successfully called beforehand). You may also need to call 
sl@0: SetDefaultEndiannessOfForeignCharacters() to define the endian-ness of the 
sl@0: input descriptor.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: Since Unicode is intended to be the superset of all character sets, the function 
sl@0: should usually report zero unconverted characters. Unconvertible characters 
sl@0: will exist if the input descriptor contains illegal characters, i.e. values 
sl@0: not in the selected non-Unicode character set.
sl@0: 
sl@0: The presence of illegal characters does not stop the conversion. The missing 
sl@0: character is simply replaced by the Unicode character which represents unknown 
sl@0: characters (0xFFFD).
sl@0: 
sl@0: If the source text consists solely of a character that is not complete, the function 
sl@0: returns EErrorIllFormedInput. The reason for this is to prevent the possibility 
sl@0: of the calling code getting into a infinite loop.
sl@0: 
sl@0: @param aUnicode On return, contains the converted text in the Unicode character 
sl@0: set.
sl@0: @param aForeign The non-Unicode source text to be converted.
sl@0: @param aState This is used to save state information across multiple calls 
sl@0: to ConvertToUnicode(). You should initialise the value to KStateDefault, and 
sl@0: then do not change it in a series of related calls.
sl@0: @param aNumberOfUnconvertibleCharacters On return, contains the number of bytes 
sl@0: which were not converted.
sl@0: @param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
sl@0: of the first byte of the first unconvertible character. For instance if the 
sl@0: first character in the input descriptor (aForeign) could not be converted, 
sl@0: then this parameter is set to the first byte of that character, i.e. zero. 
sl@0: A negative value is returned if all the characters were converted.
sl@0: @return The number of unconverted bytes left at the end of the input descriptor 
sl@0: (e.g. because the output descriptor is not long enough to hold all the text), 
sl@0: or one of the error values defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::ConvertToUnicode(
sl@0: 								TDes16& aUnicode, 
sl@0: 								const TDesC8& aForeign, 
sl@0: 								TInt& aState, 
sl@0: 								TInt& aNumberOfUnconvertibleCharacters, 
sl@0: 								TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter) const
sl@0: 	{
sl@0: 	if ( iCharacterSetIdentifierOfLoadedConversionData==0 )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_CONVERTTOUNICODE, "Null CharacterSetIdentifier2 in CCnvCharacterSetConverter::ConvertToUnicode" );    
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(iCharacterSetIdentifierOfLoadedConversionData!=0, Panic(EPanicNullCharacterSetIdentifier2));
sl@0: 	aNumberOfUnconvertibleCharacters=0;
sl@0: 	aIndexOfFirstByteOfFirstUnconvertibleCharacter=-1;
sl@0: 	if (aForeign.Length()==0)
sl@0: 		{
sl@0: 		aUnicode.SetLength(0);
sl@0: 		return 0;
sl@0: 		}
sl@0: 	if (aUnicode.MaxLength()==0)
sl@0: 		{
sl@0: 		return aForeign.Length();
sl@0: 		}
sl@0: 	TTlsData::SetCurrentCharacterSetConverter(this);
sl@0: 	TInt returnValue;
sl@0: 	if (iStoredFlags&EStoredFlagConversionPlugInLibraryIsLoaded)
sl@0: 		{
sl@0: 		TUid implUid;
sl@0: 		implUid.iUid = iCharacterSetIdentifierOfLoadedConversionData;
sl@0: 		returnValue = (iCharsetCnvCache->Converter(implUid))->ConvertToUnicode(
sl@0: 														iDefaultEndiannessOfForeignCharacters,  
sl@0: 														aUnicode, 
sl@0: 							  							aForeign, 
sl@0: 							  							aState, 
sl@0: 							  							aNumberOfUnconvertibleCharacters, 
sl@0: 							  							aIndexOfFirstByteOfFirstUnconvertibleCharacter);
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		switch (iCharacterSetIdentifierOfLoadedConversionData)
sl@0: 			{
sl@0: 		case KCharacterSetIdentifierUtf7:
sl@0: 			returnValue=CnvUtfConverter::ConvertToUnicodeFromUtf7(aUnicode, aForeign, aState);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUtf8:
sl@0: 			returnValue=CnvUtfConverter::ConvertToUnicodeFromUtf8(aUnicode, aForeign, EFalse, aNumberOfUnconvertibleCharacters, aIndexOfFirstByteOfFirstUnconvertibleCharacter);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierJavaConformantUtf8:
sl@0: 			returnValue=CnvUtfConverter::ConvertToUnicodeFromUtf8(aUnicode, aForeign, ETrue, aNumberOfUnconvertibleCharacters, aIndexOfFirstByteOfFirstUnconvertibleCharacter);
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierImapUtf7:
sl@0: 			returnValue=CnvUtfConverter::ConvertToUnicodeFromUtf7(aUnicode, aForeign, ETrue, aState);
sl@0: 			break;
sl@0: 		default:
sl@0: 		    if ( iConversionData==NULL )
sl@0: 		        {
sl@0: 		        OstTrace0( TRACE_FATAL, DUP1_CCNVCHARACTERSETCONVERTER_CONVERTTOUNICODE, "No ConversionData2 in CCnvCharacterSetConverter::ConvertToUnicode" );
sl@0: 		        }
sl@0: 			__ASSERT_ALWAYS(iConversionData!=NULL, Panic(EPanicNoConversionData2));
sl@0: 			returnValue=DoConvertToUnicode(*iConversionData, iDefaultEndiannessOfForeignCharacters, aUnicode, aForeign, aNumberOfUnconvertibleCharacters, aIndexOfFirstByteOfFirstUnconvertibleCharacter);
sl@0: 			break;
sl@0: 			}
sl@0: 		}
sl@0: 	TTlsData::SetCurrentCharacterSetConverter(NULL);
sl@0: 	return returnValue;
sl@0: 	}
sl@0: 
sl@0: /**
sl@0: Deprecated
sl@0: 
sl@0: @see			AutoDetectCharSetL
sl@0: @since			8.1
sl@0: @pre 			
sl@0: @post			
sl@0: */
sl@0: EXPORT_C void CCnvCharacterSetConverter::AutoDetectCharacterSetL(
sl@0: 					TInt& aConfidenceLevel, 
sl@0: 					TUint& aCharacterSetIdentifier, 
sl@0: 					const CArrayFix<SCharacterSet>& aArrayOfCharacterSetsAvailable, 
sl@0: 					const TDesC8& aSample)
sl@0: 	{
sl@0: 	CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC();
sl@0:     converter->AutoDetectCharSetL(aConfidenceLevel,
sl@0:                                         aCharacterSetIdentifier,
sl@0:                                         aArrayOfCharacterSetsAvailable,
sl@0:                                         aSample);
sl@0:     CleanupStack::Pop(converter);
sl@0: 	delete converter;
sl@0: 	converter = NULL;                                       
sl@0: 	}
sl@0: 
sl@0: /** Attempts to determine the character set of the sample text from 
sl@0: those supported on the phone.
sl@0: 
sl@0: For each of the available character sets, its implementation of 
sl@0: IsInThisCharacterSetL() is called. The character set which returns the highest 
sl@0: confidence level (i.e. which generates the fewest 0xFFFD Unicode replacement 
sl@0: characters) is returned in aCharacterSetIdentifier.
sl@0: 
sl@0: This function merely determines if the sample text is convertible with this 
sl@0: converter: it does no textual analysis on the result. Therefore, this function 
sl@0: is not capable of differentiating between very similar encodings (for example 
sl@0: the different ISO 8859 variants).
sl@0: 
sl@0: Any code making use of this function should provide a way for the user to 
sl@0: override the selection that this function makes.
sl@0: 
sl@0: Please note that the operation of this function is slow.It takes no account of the usual 
sl@0: ontext that would be used in guessing a character set (for example, the language that 
sl@0: is expected to be encoded or the transport used). For situations where such context is known, 
sl@0: a faster, more accurate solution is advisable.  
sl@0: 
sl@0: To improve a performance of autodetection, a size (default is one) of interface proxy cache 
sl@0: should be increased (see SetCharacterSetCacheSize()).However a boost of performance 
sl@0: will not be visible within a first funtion call because during this first call character sets 
sl@0: are loaded to a cache. Once created it will be preserved until CCnvCharacterSetConverter 
sl@0: object is destroyed.
sl@0: 
sl@0: 
sl@0: This is a static function which uses ECOM functionality. 
sl@0: It cleans up ECOM by calling FinalClose()
sl@0: 
sl@0: @param aConfidenceLevel Set by the function to a value between 0 and 100. 
sl@0: 0 indicates the function has no idea what character set aSample is encoded 
sl@0: in. In this case, aCharacterSetIdentifier is undefined. 100 indicates total 
sl@0: confidence that aCharacterSetIdentifier is the character set of aSample.
sl@0: @param aCharacterSetIdentifier On return, the UID of the best available 
sl@0: character set for the sample text aSample. Character set UIDs are defined 
sl@0: in charconv.h.
sl@0: @param aArrayOfCharacterSetsAvailable The array of character sets available 
sl@0: on the phone. If this is not already available, it can be created using 
sl@0: CreateArrayOfCharacterSetsAvailableL() or 
sl@0: CreateArrayOfCharacterSetsAvailableLC().
sl@0: @param aSample The non-Unicode sample text string. */
sl@0: EXPORT_C void CCnvCharacterSetConverter::AutoDetectCharSetL(
sl@0: 					TInt& aConfidenceLevel, 
sl@0: 					TUint& aCharacterSetIdentifier, 
sl@0: 					const CArrayFix<SCharacterSet>& aArrayOfCharacterSetsAvailable, 
sl@0: 					const TDesC8& aSample)
sl@0: 	{
sl@0: 	
sl@0: 	CleanupStack::PushL(TCleanupItem(CloseECOMSession, NULL));
sl@0: 	
sl@0: 	aConfidenceLevel=0;
sl@0: 	aCharacterSetIdentifier=0;
sl@0: 	// loop through the aArrayofCharacterSetAvailable 
sl@0: 	TInt previousConfidenceLevel = 0;
sl@0: 	RArray<TUint> chid(25);
sl@0: 	CleanupClosePushL(chid);
sl@0: 	
sl@0: 	for (TInt i=aArrayOfCharacterSetsAvailable.Count()-1; i>=0; --i)
sl@0: 		{
sl@0: 		const CCnvCharacterSetConverter::SCharacterSet& charactersSet=aArrayOfCharacterSetsAvailable[i];
sl@0: 		
sl@0: 		if (charactersSet.Identifier() == KCharacterSetIdentifierWin1252)
sl@0: 			continue; // Win1252 is same as CP1252, so just ignore it 
sl@0: 		
sl@0: 		if (charactersSet.FileIsConversionPlugInLibrary())
sl@0: 			{
sl@0: 		
sl@0: 			TBool plugInImplementsAutoDetect=EFalse;
sl@0: 			
sl@0: 			TUid implUid;
sl@0:  			implUid.iUid = charactersSet.Identifier();
sl@0: 			TBool isInThisCharSet = (iCharsetCnvCache->GetConverterL(implUid))->IsInThisCharacterSetL(
sl@0: 																plugInImplementsAutoDetect, 
sl@0: 																aConfidenceLevel, 
sl@0: 																aSample);
sl@0: 			OstTraceExt3( TRACE_DUMP, CCNVCHARACTERSETCONVERTER_AUTODETECTCHARSETL, "detect identifier 0x%x, return isInThisCharSet=%d, aConfidenceLevel=%d",  implUid.iUid, isInThisCharSet, aConfidenceLevel);
sl@0: 			if ((!plugInImplementsAutoDetect) || !isInThisCharSet)
sl@0: 				{
sl@0: 				continue;
sl@0: 				}
sl@0: 			}
sl@0: 		else if (charactersSet.NameIsFileName())
sl@0: 			{
sl@0: 			continue;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			TUint characterIdentifier = charactersSet.Identifier();
sl@0: 			::IsBuiltInCharacterSet(characterIdentifier,aConfidenceLevel,aSample);
sl@0: 			}
sl@0: 		if (aConfidenceLevel > previousConfidenceLevel)
sl@0: 			{
sl@0: 			previousConfidenceLevel = aConfidenceLevel;
sl@0: 			chid.Reset();
sl@0: 			User::LeaveIfError(chid.Append(charactersSet.Identifier()));
sl@0: 			}
sl@0: 		else if ((aConfidenceLevel == previousConfidenceLevel) && (previousConfidenceLevel != 0))
sl@0: 			{
sl@0: 			User::LeaveIfError(chid.Append(charactersSet.Identifier()));
sl@0: 			}
sl@0: 		} // for 
sl@0: 	TInt result=0;
sl@0: 	TInt min = KMaxTInt;;
sl@0: 	const TInt numberOfCandidateCharacterSets=chid.Count();
sl@0: 	if (numberOfCandidateCharacterSets ==0)
sl@0:  		{
sl@0:         OstTrace0( TRACE_DUMP, DUP2_CCNVCHARACTERSETCONVERTER_AUTODETECTCHARSETL, "We donot find any candidate in first run, so add all plugin as candidate." );
sl@0:  		// all the charcterset returned 0, so take all and find then one with least unconvertible
sl@0:  		// characters
sl@0:  		for (TInt i=aArrayOfCharacterSetsAvailable.Count()-1; i>=0; --i)
sl@0:  			{
sl@0:  			const CCnvCharacterSetConverter::SCharacterSet& charactersSettoAppend=aArrayOfCharacterSetsAvailable[i];
sl@0:  			User::LeaveIfError(chid.Append(charactersSettoAppend.Identifier()));
sl@0:  			}
sl@0:  		}
sl@0: 	if (numberOfCandidateCharacterSets>1) 
sl@0: 		{
sl@0: 		// convert and check for the number of unconvertible characters
sl@0: 		CCnvCharacterSetConverter* const charconverter=NewLC();
sl@0: 		TBuf<256>* const convertedToUnicode=new(ELeave) TBuf<256>;
sl@0: 		CleanupStack::PushL(convertedToUnicode);
sl@0: 		RFs dummyFileServerSession; // PrepareToConvertToOrFromL will not actually use this parameter
sl@0: 		for (TInt i=0; i<numberOfCandidateCharacterSets; ++i)
sl@0: 			{
sl@0: 			charconverter->PrepareToConvertToOrFromL(chid[i], aArrayOfCharacterSetsAvailable, dummyFileServerSession); 
sl@0: 			TInt state=KStateDefault;
sl@0: 			TInt unconvertibleChars;
sl@0: 			charconverter->ConvertToUnicode(*convertedToUnicode,aSample,state,unconvertibleChars);
sl@0: 			OstTraceExt2( TRACE_DUMP, DUP1_CCNVCHARACTERSETCONVERTER_AUTODETECTCHARSETL, "Plugin 0x%x has %d unconvertibleChars", chid[i], unconvertibleChars);
sl@0: 			
sl@0: 			if (unconvertibleChars < min)
sl@0: 				{
sl@0: 				min = unconvertibleChars;
sl@0: 				result = i;
sl@0: 				}
sl@0: 			}
sl@0: 		CleanupStack::PopAndDestroy(2, charconverter);
sl@0: 		}
sl@0: 
sl@0: 	aConfidenceLevel=previousConfidenceLevel;
sl@0: 
sl@0: 	//aConfidenceLevel=another;
sl@0: 	aCharacterSetIdentifier = chid[result];
sl@0: 	OstTrace1( TRACE_DUMP, DUP3_CCNVCHARACTERSETCONVERTER_AUTODETECTCHARSETL, "Use 0x%x as the auto detected plugin", aCharacterSetIdentifier);
sl@0: 	
sl@0: 	if (aConfidenceLevel <= ELowestThreshold) 
sl@0: 		{
sl@0: 		// go through all the charset available again and start converting the sample test
sl@0: 		// the one with the least 0xfffd is the winner !! 
sl@0: 		}
sl@0: 	CleanupStack::PopAndDestroy(&chid);
sl@0: 	CleanupStack::PopAndDestroy(); //CloseECOMSession
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: Deprecated
sl@0: 
sl@0: @see			ConvertibleToCharSetL
sl@0: @since			8.1
sl@0: @pre 			
sl@0: @post			
sl@0: */
sl@0: EXPORT_C void CCnvCharacterSetConverter::ConvertibleToCharacterSetL(
sl@0: 						TInt& aConfidenceLevel, 
sl@0: 						const TUint aCharacterSetIdentifier,
sl@0: 						const CArrayFix<SCharacterSet>& aArrayOfCharacterSetsAvailable, 
sl@0: 						const TDesC8& aSample)
sl@0: 	{
sl@0: 	CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC();
sl@0:     converter->ConvertibleToCharSetL(aConfidenceLevel,
sl@0:                                      aCharacterSetIdentifier,
sl@0:                                      aArrayOfCharacterSetsAvailable,
sl@0:                                      aSample);
sl@0:     CleanupStack::Pop(converter);
sl@0: 	delete converter;
sl@0: 	converter = NULL;    
sl@0: 	}
sl@0: 
sl@0: /**  Given a character set UID aCharacterSetIdentifier, 
sl@0: ConvertibleToCharacterSetL returns the likelihood that aSample 
sl@0: is encoded in that character set. It goes through the array of character sets 
sl@0: aArrayOfCharacterSetsAvailable and searches for the character set
sl@0: matching aCharacterSetIdentifier. The character sets 
sl@0: IsInThisCharacterSetL function is called to determine the probability
sl@0: of it being encoded in that character set. 
sl@0: 
sl@0: This is a static function which uses ECOM functionality. It cleans up ECOM by calling FinalClose()
sl@0: 
sl@0: @since     7.0 
sl@0: @param  aConfidenceLevel  Set by the function to a value between 0 and 100. It
sl@0: indicates the likelihood that aSample is encoded in aCharacterSetIdentifier.
sl@0: @param	 aCharacterSetIdentifier  the likelihood of aSample being 
sl@0: encoded in that character set.
sl@0: @param aArrayOfCharacterSetsAvailable The array of character sets available on 
sl@0: the device. If this is not already available, it can be created using
sl@0: CreateArrayOfCharacterSetsAvailableL() or
sl@0: CreateArrayOfCharacterSetsAvailableLC().
sl@0: @param   aSample   The non-Unicode sample text string. */
sl@0: EXPORT_C void CCnvCharacterSetConverter::ConvertibleToCharSetL(
sl@0: 						TInt& aConfidenceLevel, 
sl@0: 						const TUint aCharacterSetIdentifier,
sl@0: 						const CArrayFix<SCharacterSet>& aArrayOfCharacterSetsAvailable, 
sl@0: 						const TDesC8& aSample)
sl@0: 	{
sl@0: 	CleanupStack::PushL(TCleanupItem(CloseECOMSession, NULL));
sl@0: 
sl@0: 	aConfidenceLevel = 0;
sl@0: 
sl@0: 	// for each charcater set in the array of character set see if it matches 
sl@0: 	// aCharacterSetIdentifier
sl@0: 
sl@0: 	TInt charsetsInArray = aArrayOfCharacterSetsAvailable.Count();
sl@0: 	for (TInt i=0; i<charsetsInArray; ++i)
sl@0: 		{
sl@0: 		const CCnvCharacterSetConverter::SCharacterSet& charactersSet=aArrayOfCharacterSetsAvailable[i];
sl@0: 		if (charactersSet.Identifier()==aCharacterSetIdentifier)
sl@0: 			{
sl@0: 			// found the Charset matching the UID, Use this to find the confidence Level
sl@0: 			if ((charactersSet.FileIsConversionPlugInLibrary()) && (charactersSet.NameIsFileName()))
sl@0: 				{ 
sl@0: 				
sl@0: 				TBool plugInConvertibleTo=EFalse;
sl@0: 				TUid implUid;
sl@0: 				implUid.iUid = charactersSet.Identifier();
sl@0: 				TBool isThisCharSet = (iCharsetCnvCache->GetConverterL(implUid))->IsInThisCharacterSetL(
sl@0: 																		plugInConvertibleTo, 
sl@0: 											  							aConfidenceLevel, 
sl@0: 											  							aSample);
sl@0: 				if ((!plugInConvertibleTo) || !isThisCharSet)
sl@0: 					{
sl@0: 					aConfidenceLevel=0;
sl@0: 					}
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0:                 ::IsBuiltInCharacterSet(aCharacterSetIdentifier,aConfidenceLevel,aSample);
sl@0: 				}
sl@0: 			}
sl@0: 		} 
sl@0: 	CleanupStack::PopAndDestroy(); //CloseECOMSession
sl@0: 	}
sl@0: 	
sl@0: LOCAL_C TUint OutputCharacterCode(TUint aInputCharacterCode, 
sl@0: 								  const SCnvConversionData::SOneDirectionData::SRange& aRange)
sl@0: 	{
sl@0: 	if ( (aInputCharacterCode<aRange.iFirstInputCharacterCodeInRange) || (aInputCharacterCode>aRange.iLastInputCharacterCodeInRange) )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, _OUTPUTCHARACTERCODE, "Input Character Code Not In Range in ::OutputCharacterCode" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG((aInputCharacterCode>=aRange.iFirstInputCharacterCodeInRange) && (aInputCharacterCode<=aRange.iLastInputCharacterCodeInRange), Panic(EPanicInputCharacterCodeNotInRange));
sl@0: 	switch (aRange.iAlgorithm)
sl@0: 		{
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EDirect:
sl@0: 		return aInputCharacterCode;
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EOffset:
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 	    if (aRange.iData.iOffset==0)
sl@0: 	        {
sl@0: 	        OstTrace0( TRACE_DUMP, DUP1__OUTPUTCHARACTERCODE, "EPanicZeroOffset1" );
sl@0: 	        }
sl@0: 		__ASSERT_DEBUG(aRange.iData.iOffset!=0, Panic(EPanicZeroOffset1));
sl@0: 		return aInputCharacterCode+aRange.iData.iOffset;
sl@0: #else
sl@0: 		if (STATIC_CAST(TInt, aRange.iData.iWord1)==0)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP2__OUTPUTCHARACTERCODE, "EPanicZeroOffset2" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(STATIC_CAST(TInt, aRange.iData.iWord1)!=0, Panic(EPanicZeroOffset2));
sl@0: 		return aInputCharacterCode+STATIC_CAST(TInt, aRange.iData.iWord1);
sl@0: #endif
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EIndexedTable16:
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 		return aRange.iData.iIndexedTable16.iEntryArray
sl@0: #else
sl@0: 		return REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SIndexedTable16::SEntry*, aRange.iData.iWord1)
sl@0: #endif
sl@0: 										[aInputCharacterCode-aRange.iFirstInputCharacterCodeInRange].iOutputCharacterCode;
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EKeyedTable1616:
sl@0: 		{
sl@0: 		TInt leftIndex=0;
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 		TInt rightIndex=aRange.iData.iKeyedTable1616.iNumberOfEntries;
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616::SEntry* const entryArray=aRange.iData.iKeyedTable1616.iEntryArray;
sl@0: #else
sl@0: 		TInt rightIndex=STATIC_CAST(TInt, aRange.iData.iWord1);
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616::SEntry* const entryArray=REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616::SEntry*, aRange.iData.iWord2);
sl@0: #endif
sl@0: 		if(rightIndex<=0)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP3__OUTPUTCHARACTERCODE, "EPanicEmptyKeyedTable1616" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(rightIndex>0, Panic(EPanicEmptyKeyedTable1616));
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if (leftIndex>rightIndex)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP4__OUTPUTCHARACTERCODE, "EPanicBadIndices1" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(leftIndex<=rightIndex, Panic(EPanicBadIndices1));
sl@0: 			if (leftIndex==rightIndex)
sl@0: 				{
sl@0: 				return KNoConversionAvailable;
sl@0: 				}
sl@0: 			const TInt middleIndex=(leftIndex+rightIndex)>>1;
sl@0: 			const TUint key=entryArray[middleIndex].iKey;
sl@0: 			if (aInputCharacterCode<key)
sl@0: 				{
sl@0: 				rightIndex=middleIndex;
sl@0: 				}
sl@0: 			else if (aInputCharacterCode>key)
sl@0: 				{
sl@0: 				leftIndex=middleIndex+1;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				return entryArray[middleIndex].iOutputCharacterCode;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EKeyedTable16OfIndexedTables16:
sl@0: 		{
sl@0: 		TInt leftIndex=0;
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 		TInt rightIndex=aRange.iData.iKeyedTable16OfIndexedTables16.iNumberOfKeyedEntries;
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable16OfIndexedTables16::SKeyedEntry* const keyedEntryArray=aRange.iData.iKeyedTable16OfIndexedTables16.iKeyedEntryArray;
sl@0: #else
sl@0: 		TInt rightIndex=STATIC_CAST(TInt, aRange.iData.iWord1);
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable16OfIndexedTables16::SKeyedEntry* const keyedEntryArray=REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable16OfIndexedTables16::SKeyedEntry*, aRange.iData.iWord2);
sl@0: #endif
sl@0: 		if (rightIndex<=0)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP5__OUTPUTCHARACTERCODE, "EPanicEmptyKeyedTable16OfIndexedTables16" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(rightIndex>0, Panic(EPanicEmptyKeyedTable16OfIndexedTables16));
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if (leftIndex>rightIndex)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP6__OUTPUTCHARACTERCODE, "EPanicBadIndices2" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(leftIndex<=rightIndex, Panic(EPanicBadIndices2));
sl@0: 			if (leftIndex==rightIndex)
sl@0: 				{
sl@0: 				return KNoConversionAvailable;
sl@0: 				}
sl@0: 			const TInt middleIndex=(leftIndex+rightIndex)>>1;
sl@0: 			const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable16OfIndexedTables16::SKeyedEntry& keyedEntry=keyedEntryArray[middleIndex];
sl@0: 			if (aInputCharacterCode<keyedEntry.iFirstInputCharacterCodeInIndexedTable)
sl@0: 				{
sl@0: 				rightIndex=middleIndex;
sl@0: 				}
sl@0: 			else if (aInputCharacterCode>keyedEntry.iLastInputCharacterCodeInIndexedTable)
sl@0: 				{
sl@0: 				leftIndex=middleIndex+1;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				return keyedEntry.iIndexedEntryArray[aInputCharacterCode-keyedEntry.iFirstInputCharacterCodeInIndexedTable];
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 		
sl@0: //new 32 bit algorithms start
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EIndexedTable32:
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 		return aRange.iData.iIndexedTable32.iEntryArray
sl@0: #else
sl@0: 		return REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SIndexedTable32::SEntry*, aRange.iData.iWord1)
sl@0: #endif
sl@0: 										[aInputCharacterCode-aRange.iFirstInputCharacterCodeInRange].iOutputCharacterCode;
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EKeyedTable3232:
sl@0: 		{
sl@0: 		TInt leftIndex=0;
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 		TInt rightIndex=aRange.iData.iKeyedTable3232.iNumberOfEntries;
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable3232::SEntry* const entryArray=aRange.iData.iKeyedTable3232.iEntryArray;
sl@0: #else
sl@0: 		TInt rightIndex=STATIC_CAST(TInt, aRange.iData.iWord1);
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable3232::SEntry* const entryArray=REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable3232::SEntry*, aRange.iData.iWord2);
sl@0: #endif
sl@0: 		if (rightIndex<=0)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP7__OUTPUTCHARACTERCODE, "EPanicEmptyKeyedTable3232" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(rightIndex>0, Panic(EPanicEmptyKeyedTable3232));
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if (leftIndex>rightIndex)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP8__OUTPUTCHARACTERCODE, "EPanicBadIndices1" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(leftIndex<=rightIndex, Panic(EPanicBadIndices1));
sl@0: 			if (leftIndex==rightIndex)
sl@0: 				{
sl@0: 				return KNoConversionAvailable;
sl@0: 				}
sl@0: 			const TInt middleIndex=(leftIndex+rightIndex)>>1;
sl@0: 			const TUint key=entryArray[middleIndex].iKey;
sl@0: 			if (aInputCharacterCode<key)
sl@0: 				{
sl@0: 				rightIndex=middleIndex;
sl@0: 				}
sl@0: 			else if (aInputCharacterCode>key)
sl@0: 				{
sl@0: 				leftIndex=middleIndex+1;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				return entryArray[middleIndex].iOutputCharacterCode;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 	case SCnvConversionData::SOneDirectionData::SRange::EKeyedTable32OfIndexedTables32:
sl@0: 		{
sl@0: 		TInt leftIndex=0;
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 		TInt rightIndex=aRange.iData.iKeyedTable32OfIndexedTables32.iNumberOfKeyedEntries;
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable32OfIndexedTables32::SKeyedEntry* const keyedEntryArray=aRange.iData.iKeyedTable32OfIndexedTables32.iKeyedEntryArray;
sl@0: #else
sl@0: 		TInt rightIndex=STATIC_CAST(TInt, aRange.iData.iWord1);
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable32OfIndexedTables32::SKeyedEntry* const keyedEntryArray=REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable32OfIndexedTables32::SKeyedEntry*, aRange.iData.iWord2);
sl@0: #endif
sl@0: 		if (rightIndex<=0)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP9__OUTPUTCHARACTERCODE, "EPanicEmptyKeyedTable32OfIndexedTables32" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(rightIndex>0, Panic(EPanicEmptyKeyedTable32OfIndexedTables32));
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if (leftIndex>rightIndex)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP10__OUTPUTCHARACTERCODE, "EPanicBadIndices2" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(leftIndex<=rightIndex, Panic(EPanicBadIndices2));
sl@0: 			if (leftIndex==rightIndex)
sl@0: 				{
sl@0: 				return KNoConversionAvailable;
sl@0: 				}
sl@0: 			const TInt middleIndex=(leftIndex+rightIndex)>>1;
sl@0: 			const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable32OfIndexedTables32::SKeyedEntry& keyedEntry=keyedEntryArray[middleIndex];
sl@0: 			if (aInputCharacterCode<keyedEntry.iFirstInputCharacterCodeInIndexedTable)
sl@0: 				{
sl@0: 				rightIndex=middleIndex;
sl@0: 				}
sl@0: 			else if (aInputCharacterCode>keyedEntry.iLastInputCharacterCodeInIndexedTable)
sl@0: 				{
sl@0: 				leftIndex=middleIndex+1;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				return keyedEntry.iIndexedEntryArray[aInputCharacterCode-keyedEntry.iFirstInputCharacterCodeInIndexedTable];
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: //new 32 bit algorithms end		
sl@0: 		
sl@0: #if defined(_DEBUG)
sl@0: 	default:
sl@0: 	    OstTrace0( TRACE_DUMP, DUP11__OUTPUTCHARACTERCODE, "EPanicBadAlgorithm1" );
sl@0: 		Panic(EPanicBadAlgorithm1);
sl@0: #endif
sl@0: 		}
sl@0: 	return 0; // dummy return to prevent compiler error
sl@0: 	}
sl@0: 
sl@0: LOCAL_C TBool 
sl@0: ConvertsToForeignCharacterSet(
sl@0: 			TInt& aSizeOfOutputForeignCharacterCodeInBytes, 
sl@0: 			TUint aInputUnicodeCharacterCode, 
sl@0: 			const SCnvConversionData::SOneDirectionData::SRange* aFirstUnicodeToForeignRange, 
sl@0: 			const SCnvConversionData::SOneDirectionData::SRange* aLastUnicodeToForeignRange)
sl@0: 	{
sl@0: 	if (aFirstUnicodeToForeignRange==NULL)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, _CONVERTSTOFOREIGNCHARACTERSET, "EPanicNullPointer1" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aFirstUnicodeToForeignRange!=NULL, Panic(EPanicNullPointer1));
sl@0: 	if (aLastUnicodeToForeignRange==NULL)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP1__CONVERTSTOFOREIGNCHARACTERSET, "EPanicNullPointer2" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aLastUnicodeToForeignRange!=NULL, Panic(EPanicNullPointer2));
sl@0: 	if (aFirstUnicodeToForeignRange>aLastUnicodeToForeignRange)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP2__CONVERTSTOFOREIGNCHARACTERSET, "EPanicCrossedPointers" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aFirstUnicodeToForeignRange<=aLastUnicodeToForeignRange, Panic(EPanicCrossedPointers));
sl@0: 	for (const SCnvConversionData::SOneDirectionData::SRange* currentUnicodeToForeignRange=aFirstUnicodeToForeignRange; ; ++currentUnicodeToForeignRange)
sl@0: 		{
sl@0: 		if ((aInputUnicodeCharacterCode>=currentUnicodeToForeignRange->iFirstInputCharacterCodeInRange) &&
sl@0: 			(aInputUnicodeCharacterCode<=currentUnicodeToForeignRange->iLastInputCharacterCodeInRange))
sl@0: 			{
sl@0: 			if (OutputCharacterCode(aInputUnicodeCharacterCode, *currentUnicodeToForeignRange)!=KNoConversionAvailable)
sl@0: 				{
sl@0: 				aSizeOfOutputForeignCharacterCodeInBytes=currentUnicodeToForeignRange->iSizeOfOutputCharacterCodeInBytesIfForeign;
sl@0: 				return ETrue;
sl@0: 				}
sl@0: 			}
sl@0: 		if (currentUnicodeToForeignRange>aLastUnicodeToForeignRange)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP3__CONVERTSTOFOREIGNCHARACTERSET, "EPanicPointerPastUpperLimit21" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(currentUnicodeToForeignRange<=aLastUnicodeToForeignRange, Panic(EPanicPointerPastUpperLimit21));
sl@0: 		if (currentUnicodeToForeignRange>=aLastUnicodeToForeignRange)
sl@0: 			{
sl@0: 			return EFalse;
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Converts Unicode text into another character set. The Unicode text specified 
sl@0: in aUnicode is converted using the conversion data object (aConversionData) 
sl@0: provided by the plug-in for the foreign character set, and the converted text 
sl@0: is returned in aForeign.
sl@0: 
sl@0: Note
sl@0: 
sl@0: This is a utility function that should only be called from a plug-in conversion 
sl@0: library's implementation of ConvertFromUnicode(). Users of the Character 
sl@0: Conversion API should use one of the overloads of ConvertFromUnicode() instead.
sl@0: 
sl@0: @param aConversionData The conversion data object. Typically, you should specify 
sl@0: conversionData, as declared in convgeneratedcpp.h. This is the 
sl@0: SCnvConversionData object which is created in the cnvtool-generated .cpp file 
sl@0: (although for some complex character sets you may want to pass other 
sl@0: SCnvConversionData objects into this parameter).
sl@0: @param aDefaultEndiannessOfForeignCharacters The default endian-ness to use 
sl@0: when writing the characters in the foreign character set. If an endian-ness 
sl@0: for foreign characters is specified in aConversionData (i.e. not 
sl@0: SCnvConversionData::EUnspecified), then that value is used and the value of 
sl@0: aDefaultEndiannessOfForeignCharacters is ignored.
sl@0: @param aReplacementForUnconvertibleUnicodeCharacters The single character which 
sl@0: is to be used to replace unconvertible characters.
sl@0: @param aForeign On return, contains the converted text in a non-Unicode 
sl@0: character set.
sl@0: @param aUnicode The source Unicode text to be converted.
sl@0: @param aIndicesOfUnconvertibleCharacters On return holds the indices of each 
sl@0: Unicode character in the source text which could not be converted (because 
sl@0: the target character set does not have an equivalent character).
sl@0: @return The number of unconverted characters left at the end of the input 
sl@0: descriptor (e.g. because aForeign was not long enough to hold all the text), 
sl@0: or a negative error value, as defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::DoConvertFromUnicode(
sl@0: 					const SCnvConversionData& aConversionData, 
sl@0: 					TEndianness aDefaultEndiannessOfForeignCharacters, 
sl@0: 					const TDesC8& aReplacementForUnconvertibleUnicodeCharacters, 
sl@0: 					TDes8& aForeign, 
sl@0: 					const TDesC16& aUnicode, 
sl@0: 					TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters)
sl@0: 	{
sl@0: 	TUint notUsed;
sl@0: 	return DoConvertFromUnicode(aConversionData, aDefaultEndiannessOfForeignCharacters, aReplacementForUnconvertibleUnicodeCharacters, aForeign, aUnicode, aIndicesOfUnconvertibleCharacters, notUsed, 0);
sl@0: 	}
sl@0: 
sl@0: /** Converts Unicode text into another character set. The Unicode text specified 
sl@0: in aUnicode is converted using the conversion data object (aConversionData) 
sl@0: provided by the plug-in for the foreign character set, and the converted text 
sl@0: is returned in aForeign.
sl@0: 
sl@0: This overload differs from the previous one in that it allows the caller to 
sl@0: specify flags which give more control over the conversion.
sl@0: 
sl@0: Note
sl@0: 
sl@0: This is a utility function that should only be called from a plug-in conversion 
sl@0: library's implementation of ConvertFromUnicode(). Users of the Character 
sl@0: Conversion API should use one of the overloads of ConvertFromUnicode() instead.
sl@0: 
sl@0: @param aConversionData The conversion data object. Typically, you should specify 
sl@0: conversionData, as declared in convgeneratedcpp.h. This is the 
sl@0: SCnvConversionData object which is created in the cnvtool-generated .cpp file 
sl@0: (although for some complex character sets you may want to pass other 
sl@0: SCnvConversionData objects into this parameter).
sl@0: @param aDefaultEndiannessOfForeignCharacters The default endian-ness to use 
sl@0: when writing the characters in the foreign character set. If an endian-ness 
sl@0: for foreign characters is specified in aConversionData (i.e. not 
sl@0: SCnvConversionData::EUnspecified), then that value is used and the value of 
sl@0: aDefaultEndiannessOfForeignCharacters is ignored.
sl@0: @param aReplacementForUnconvertibleUnicodeCharacters The single character which 
sl@0: is to be used to replace unconvertible characters. If aInputConversionFlags 
sl@0: is set to EInputConversionFlagStopAtFirstUnconvertibleCharacter, this 
sl@0: replacement character is used to replace the first unconvertible character, 
sl@0: then the conversion will stop.
sl@0: @param aForeign On return, contains the converted text in a non-Unicode 
sl@0: character set. This may already contain some text. If it does, and if 
sl@0: aInputConversionFlags specifies EInputConversionFlagAppend, then the converted 
sl@0: text is appended to this descriptor.
sl@0: @param aUnicode The source Unicode text to be converted.
sl@0: @param aIndicesOfUnconvertibleCharacters On return holds the indices of each 
sl@0: Unicode character in the source descriptor aUnicode which could not be converted. 
sl@0: The maximum size of this array is KMaximumNumberOfIndices whose value is 25 now.
sl@0: so only the first 25 unconvertible characters will be recorded.
sl@0: (because the target character set does not have an equivalent character).
sl@0: @param aOutputConversionFlags If the input descriptor ended in a truncated 
sl@0: sequence, e.g. the first half of a Unicode surrogate pair, 
sl@0: aOutputConversionFlags returns with the EOutputConversionFlagInputIsTruncated 
sl@0: flag set.
sl@0: @param aInputConversionFlags Specify EInputConversionFlagAppend to append the 
sl@0: text in aUnicode to aForeign. Specify 
sl@0: EInputConversionFlagStopAtFirstUnconvertibleCharacter to stop converting when 
sl@0: the first unconvertible character is reached. Specify 
sl@0: EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable to prevent 
sl@0: the function from returning the error-code EErrorIllFormedInput when the input 
sl@0: descriptor consists of nothing but a truncated sequence. 
sl@0: @return The number of unconverted characters left at the end of the input 
sl@0: descriptor (e.g. because aForeign was not long enough to hold all the text), 
sl@0: or a negative error value, as defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::DoConvertFromUnicode(
sl@0: 								const SCnvConversionData& aConversionData, 
sl@0: 								TEndianness aDefaultEndiannessOfForeignCharacters, 
sl@0: 								const TDesC8& aReplacementForUnconvertibleUnicodeCharacters, 
sl@0: 								TDes8& aForeign, 
sl@0: 								const TDesC16& aUnicode, 
sl@0: 								TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters, 
sl@0: 								TUint& aOutputConversionFlags, 
sl@0: 								TUint aInputConversionFlags)
sl@0: 	{
sl@0: 	aOutputConversionFlags=0;
sl@0: 	if (aUnicode.Length()==0)
sl@0: 		{
sl@0: 		if (~aInputConversionFlags&EInputConversionFlagAppend)
sl@0: 			{
sl@0: 			aForeign.SetLength(0);
sl@0: 			}
sl@0: 		return 0;
sl@0: 		}
sl@0: 	if (aForeign.MaxLength()==((aInputConversionFlags&EInputConversionFlagAppend)? aForeign.Length(): 0))
sl@0: 		{
sl@0: 		return aUnicode.Length();
sl@0: 		}
sl@0: 	TUint8* pointerToPreviousForeignByte=CONST_CAST(TUint8*, aForeign.Ptr()-1);
sl@0: 	const TUint8* const pointerToLastForeignByte=pointerToPreviousForeignByte+aForeign.MaxLength();
sl@0: 	if (aInputConversionFlags&EInputConversionFlagAppend)
sl@0: 		{
sl@0: 		pointerToPreviousForeignByte+=aForeign.Length();
sl@0: 		}
sl@0: 	const TUint16* pointerToCurrentUnicodeCharacter=aUnicode.Ptr();
sl@0: 	const TUint16* const pointerToLastUnicodeCharacter=pointerToCurrentUnicodeCharacter+(aUnicode.Length()-1);
sl@0: 	if (aConversionData.iUnicodeToForeignData.iNumberOfRanges<=0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadNumberOfRanges1" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aConversionData.iUnicodeToForeignData.iNumberOfRanges>0, Panic(EPanicBadNumberOfRanges1));
sl@0: 	const SCnvConversionData::SOneDirectionData::SRange* const firstRange=aConversionData.iUnicodeToForeignData.iRangeArray;
sl@0: 	const SCnvConversionData::SOneDirectionData::SRange* const lastRange=firstRange+(aConversionData.iUnicodeToForeignData.iNumberOfRanges-1);
sl@0: 	const TEndianness endiannessToWriteForeignCharactersIn=EndiannessOfForeignCharacters(aConversionData, aDefaultEndiannessOfForeignCharacters);
sl@0: 	const TEndianness endiannessOfReplacementForUnconvertibleUnicodeCharacters=EndiannessOfForeignCharacters(aConversionData, ELittleEndian); // this has a hard-coded default
sl@0: 	const CCnvCharacterSetConverter* const currentCharacterSetConverter=TTlsData::CurrentCharacterSetConverter();
sl@0: 	const TBool downgradingPermitted=(currentCharacterSetConverter!=NULL); // downgrading is only permitted if we're not doing VFAT short-name generation
sl@0: 	const TDowngradeForExoticLineTerminatingCharacters downgradeForExoticLineTerminatingCharacters=(currentCharacterSetConverter!=NULL)? currentCharacterSetConverter->iDowngradeForExoticLineTerminatingCharacters: EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed;
sl@0: 	TUint nextInputCharacterCode=KNoConversionAvailable;
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		if (pointerToPreviousForeignByte>pointerToLastForeignByte)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP1_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit6" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToPreviousForeignByte<=pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit6));
sl@0: 		if (pointerToCurrentUnicodeCharacter>pointerToLastUnicodeCharacter)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP2_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit7" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToCurrentUnicodeCharacter<=pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit7));
sl@0: 		TBool stop=EFalse;
sl@0: 		TUint inputCharacterCode;
sl@0: 		if (nextInputCharacterCode==KNoConversionAvailable)
sl@0: 			{
sl@0: 			inputCharacterCode=*pointerToCurrentUnicodeCharacter;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			inputCharacterCode=nextInputCharacterCode;
sl@0: 			nextInputCharacterCode=KNoConversionAvailable;
sl@0: 			}
sl@0: 		if ((inputCharacterCode>=0xd800) && (inputCharacterCode<0xdc00))
sl@0: 			{
sl@0: 			if (pointerToCurrentUnicodeCharacter>pointerToLastUnicodeCharacter)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP3_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit8" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(pointerToCurrentUnicodeCharacter<=pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit8));
sl@0: 			if (pointerToCurrentUnicodeCharacter>=pointerToLastUnicodeCharacter)
sl@0: 				{
sl@0: 				aOutputConversionFlags|=EOutputConversionFlagInputIsTruncated;
sl@0: 				goto end;
sl@0: 				}
sl@0: 			TUint secondHalfOfSurrogatePair=*(pointerToCurrentUnicodeCharacter+1);
sl@0: 			if ((secondHalfOfSurrogatePair<0xdc00) || (secondHalfOfSurrogatePair>=0xe000))
sl@0: 				{
sl@0: 				return EErrorIllFormedInput;
sl@0: 				}
sl@0: 			inputCharacterCode&=~0xd800;
sl@0: 			inputCharacterCode<<=10;
sl@0: 			secondHalfOfSurrogatePair&=~0xdc00;
sl@0: 			inputCharacterCode|=secondHalfOfSurrogatePair;
sl@0: 			inputCharacterCode+=0x00010000; // this must be added - it cannot be bitwise-"or"-ed
sl@0: 			if (!(inputCharacterCode&0xffff0000) || !(inputCharacterCode<0x00110000))
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP4_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadNon16BitCharacterCode1" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG((inputCharacterCode&0xffff0000) && (inputCharacterCode<0x00110000), Panic(EPanicBadNon16BitCharacterCode1));
sl@0: 			}
sl@0: convertInputCharacterCode:
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange* currentRange=firstRange;
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if ((inputCharacterCode>=currentRange->iFirstInputCharacterCodeInRange) &&
sl@0: 				(inputCharacterCode<=currentRange->iLastInputCharacterCodeInRange))
sl@0: 				{
sl@0: 				TUint outputCharacterCode=OutputCharacterCode(inputCharacterCode, *currentRange);
sl@0: 				if (outputCharacterCode!=KNoConversionAvailable)
sl@0: 					{
sl@0: 					TInt temp=currentRange->iSizeOfOutputCharacterCodeInBytesIfForeign; // the meaning of temp changes during it's lifetime (hence the bland variable name)
sl@0: 					if ( (temp<=0) || ((temp>STATIC_CAST(TInt, sizeof(TUint)))) || !((temp==sizeof(TUint)) || (outputCharacterCode<STATIC_CAST(TUint, 1<<(temp*8)))) )
sl@0: 					    {
sl@0: 					    OstTrace0( TRACE_DUMP, DUP5_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadSizeOfForeignOutputCharacterCode" );
sl@0: 					    }
sl@0: 					__ASSERT_DEBUG((temp>0) && (temp<=STATIC_CAST(TInt, sizeof(TUint))) && ((temp==sizeof(TUint)) || (outputCharacterCode<STATIC_CAST(TUint, 1<<(temp*8)))), Panic(EPanicBadSizeOfForeignOutputCharacterCode)); // ?? this second half of this assert needs a corresponding "KErrCorrupt"-check when loading the file
sl@0: 					if (pointerToLastForeignByte-pointerToPreviousForeignByte<temp)
sl@0: 						{
sl@0: 						goto end;
sl@0: 						}
sl@0: 					--temp;
sl@0: 					temp*=8;
sl@0: 					switch (endiannessToWriteForeignCharactersIn)
sl@0: 						{
sl@0: 					case ELittleEndian:
sl@0: 						FOREVER
sl@0: 							{
sl@0: 							if (pointerToPreviousForeignByte>=pointerToLastForeignByte)
sl@0: 							    {
sl@0: 							    OstTrace0( TRACE_DUMP, DUP6_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit9" );
sl@0: 							    }
sl@0: 							__ASSERT_DEBUG(pointerToPreviousForeignByte<pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit9));
sl@0: 							++pointerToPreviousForeignByte;
sl@0: 							*pointerToPreviousForeignByte=STATIC_CAST(TUint8, outputCharacterCode);
sl@0: 							if (temp<0)
sl@0: 							    {
sl@0: 							    OstTrace0( TRACE_DUMP, DUP7_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadNumberOfRemainingForeignBytes1" );
sl@0: 							    }
sl@0: 							__ASSERT_DEBUG(temp>=0, Panic(EPanicBadNumberOfRemainingForeignBytes1));
sl@0: 							if (temp<=0)
sl@0: 								{
sl@0: 								break;
sl@0: 								}
sl@0: 							temp-=8;
sl@0: 							outputCharacterCode>>=8;
sl@0: 							}
sl@0: 						break;
sl@0: 					case EBigEndian:
sl@0: 						FOREVER
sl@0: 							{
sl@0: 							if (pointerToPreviousForeignByte>=pointerToLastForeignByte)
sl@0: 							    {
sl@0: 							    OstTrace0( TRACE_DUMP, DUP8_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit10" );
sl@0: 							    }
sl@0: 							__ASSERT_DEBUG(pointerToPreviousForeignByte<pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit10));
sl@0: 							++pointerToPreviousForeignByte;
sl@0: 							*pointerToPreviousForeignByte=STATIC_CAST(TUint8, outputCharacterCode>>temp);
sl@0: 							if (temp<0)
sl@0: 							    {
sl@0: 							    OstTrace0( TRACE_DUMP, DUP9_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadNumberOfRemainingForeignBytes2" );
sl@0: 							    }
sl@0: 							__ASSERT_DEBUG(temp>=0, Panic(EPanicBadNumberOfRemainingForeignBytes2));
sl@0: 							if (temp<=0)
sl@0: 								{
sl@0: 								break;
sl@0: 								}
sl@0: 							temp-=8;
sl@0: 							}
sl@0: 						break;
sl@0: #if defined(_DEBUG)
sl@0: 					default:
sl@0: 					    OstTrace0( TRACE_DUMP, DUP10_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadEndianness1" );
sl@0: 						Panic(EPanicBadEndianness1);
sl@0: 						break;
sl@0: #endif
sl@0: 						}
sl@0: 					break;
sl@0: 					}
sl@0: 				}
sl@0: 			if (currentRange>lastRange)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP11_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit11" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(currentRange<=lastRange, Panic(EPanicPointerPastUpperLimit11));
sl@0: 			if (currentRange>=lastRange)
sl@0: 				{
sl@0: 				if (downgradingPermitted)
sl@0: 					{
sl@0: 					if ((inputCharacterCode==0x2029) || (inputCharacterCode==0x2028))
sl@0: 						{
sl@0: 						switch (downgradeForExoticLineTerminatingCharacters)
sl@0: 							{
sl@0: 						case EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed:
sl@0: 							{
sl@0: 							// check that there's enough room for the subsequent line-feed character, and check that both the carriage-return and the line-feed convert into the foreign character set
sl@0: 							TInt sizeOfForeignCarriageReturnInBytes;
sl@0: 							TInt sizeOfForeignLineFeedInBytes;
sl@0: 							if (ConvertsToForeignCharacterSet(sizeOfForeignCarriageReturnInBytes, 0x000d, firstRange, lastRange) &&
sl@0: 								ConvertsToForeignCharacterSet(sizeOfForeignLineFeedInBytes, 0x000a, firstRange, lastRange) &&
sl@0: 								(pointerToLastForeignByte-pointerToPreviousForeignByte>=sizeOfForeignCarriageReturnInBytes+sizeOfForeignLineFeedInBytes))
sl@0: 								{
sl@0: 								inputCharacterCode=0x000d;
sl@0: 								nextInputCharacterCode=0x000a;
sl@0: 								goto convertInputCharacterCode;
sl@0: 								}
sl@0: 							}
sl@0: 							break;
sl@0: 						case EDowngradeExoticLineTerminatingCharactersToJustLineFeed:
sl@0: 							inputCharacterCode=0x000a;
sl@0: 							goto convertInputCharacterCode;
sl@0: #if defined(_DEBUG)
sl@0: 						default:
sl@0: 						    OstTrace0( TRACE_DUMP, DUP12_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicBadDowngradeForExoticLineTerminatingCharacters2" );
sl@0: 							Panic(EPanicBadDowngradeForExoticLineTerminatingCharacters2);
sl@0: 							break;
sl@0: #endif
sl@0: 							}
sl@0: 						}
sl@0: 					}
sl@0: 				const TInt lengthOfReplacementForUnconvertibleUnicodeCharacters=aReplacementForUnconvertibleUnicodeCharacters.Length();
sl@0: 				if (lengthOfReplacementForUnconvertibleUnicodeCharacters>0)
sl@0: 					{
sl@0: 					if (pointerToLastForeignByte-pointerToPreviousForeignByte<lengthOfReplacementForUnconvertibleUnicodeCharacters)
sl@0: 						{
sl@0: 						goto end;
sl@0: 						}
sl@0: 					const TUint8* pointerToReadFrom=aReplacementForUnconvertibleUnicodeCharacters.Ptr();
sl@0: 					const TUint8* lastByteToReadFrom=pointerToReadFrom+(lengthOfReplacementForUnconvertibleUnicodeCharacters-1);
sl@0: 					TInt increment=1;
sl@0: 					if (endiannessOfReplacementForUnconvertibleUnicodeCharacters!=endiannessToWriteForeignCharactersIn)
sl@0: 						{
sl@0: 						const TUint8* temp=pointerToReadFrom;
sl@0: 						pointerToReadFrom=lastByteToReadFrom;
sl@0: 						lastByteToReadFrom=temp;
sl@0: 						increment=-1;
sl@0: 						}
sl@0: 					FOREVER
sl@0: 						{
sl@0: 						if (pointerToPreviousForeignByte>=pointerToLastForeignByte)
sl@0: 						    {
sl@0: 						    OstTrace0( TRACE_DUMP, DUP13_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit12" );
sl@0: 						    }
sl@0: 						__ASSERT_DEBUG(pointerToPreviousForeignByte<pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit12));
sl@0: 						++pointerToPreviousForeignByte;
sl@0: 						*pointerToPreviousForeignByte=*pointerToReadFrom;
sl@0: 						if (pointerToReadFrom==lastByteToReadFrom)
sl@0: 							{
sl@0: 							break;
sl@0: 							}
sl@0: 						pointerToReadFrom+=increment;
sl@0: 						}
sl@0: 					}
sl@0: 				if (aInputConversionFlags&EInputConversionFlagStopAtFirstUnconvertibleCharacter)
sl@0: 					{
sl@0: 					stop=ETrue;
sl@0: 					}
sl@0: 				aIndicesOfUnconvertibleCharacters.AppendIndex(pointerToCurrentUnicodeCharacter-aUnicode.Ptr());
sl@0: 				break;
sl@0: 				}
sl@0: 			++currentRange;
sl@0: 			}
sl@0: 		if (inputCharacterCode>=0x00010000)
sl@0: 			{
sl@0: 			if (pointerToCurrentUnicodeCharacter>=pointerToLastUnicodeCharacter)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP14_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit13" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(pointerToCurrentUnicodeCharacter<pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit13));
sl@0: 			if (nextInputCharacterCode==KNoConversionAvailable)
sl@0: 				{
sl@0: 				++pointerToCurrentUnicodeCharacter;
sl@0: 				}
sl@0: 			}
sl@0: 		if (pointerToCurrentUnicodeCharacter>pointerToLastUnicodeCharacter)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP15_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastUpperLimit14" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToCurrentUnicodeCharacter<=pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit14));
sl@0: 		if (nextInputCharacterCode==KNoConversionAvailable)
sl@0: 			{
sl@0: 			if (pointerToCurrentUnicodeCharacter>=pointerToLastUnicodeCharacter)
sl@0: 				{
sl@0: 				++pointerToCurrentUnicodeCharacter; // this increment is done regardless of the test just above, but it's not done before the test as it may make pointerToCurrentUnicodeCharacter greater than pointerToLastUnicodeCharacter, and if pointerToLastUnicodeCharacter just happens to be pointing at 0xffffffff, pointerToCurrentUnicodeCharacter will be pointing at 0x00000000, thus the test (which would now be "if (pointerToCurrentUnicodeCharacter>pointerToLastUnicodeCharacter)") would fail
sl@0: 				goto end;
sl@0: 				}
sl@0: 			++pointerToCurrentUnicodeCharacter;
sl@0: 			}
sl@0: 		if (stop)
sl@0: 			{
sl@0: 			goto end;
sl@0: 			}
sl@0: 		}
sl@0: end:
sl@0:     if (pointerToCurrentUnicodeCharacter<aUnicode.Ptr())
sl@0:         {
sl@0:         OstTrace0( TRACE_DUMP, DUP16_CCNVCHARACTERSETCONVERTER_DOCONVERTFROMUNICODE, "EPanicPointerPastLowerLimit1" );
sl@0:         }
sl@0: 	__ASSERT_DEBUG(pointerToCurrentUnicodeCharacter>=aUnicode.Ptr(), Panic(EPanicPointerPastLowerLimit1));
sl@0: 	if ((pointerToCurrentUnicodeCharacter<=aUnicode.Ptr()) && (aOutputConversionFlags&EOutputConversionFlagInputIsTruncated) && (~aInputConversionFlags&EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable))
sl@0: 		{
sl@0: 		return EErrorIllFormedInput;
sl@0: 		}
sl@0: 	aForeign.SetLength((pointerToPreviousForeignByte+1)-aForeign.Ptr());
sl@0: 	return pointerToLastUnicodeCharacter-(pointerToCurrentUnicodeCharacter-1);
sl@0: 	}
sl@0: 
sl@0: /** Converts non-Unicode text into Unicode. The non-Unicode text specified in 
sl@0: aForeign is converted using the conversion data object (aConversionData) 
sl@0: provided by the plug-in for the foreign character set, and the converted text 
sl@0: is returned in aUnicode.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: This is a utility function that should only be called from a plug-in conversion 
sl@0: library's implementation of ConvertToUnicode(). Ordinary users of the Character 
sl@0: Conversion API should use one of the overloads of ConvertToUnicode() instead.
sl@0: 
sl@0: The last two arguments return information about unconverted characters. Because 
sl@0: Unicode is intended to cover all possible characters, these rarely report 
sl@0: anything other than zero characters. However they report the existence of 
sl@0: unconvertible characters if the input descriptor aForeign contains illegal 
sl@0: characters, i.e. values not in the foreign character set.
sl@0: 
sl@0: @param aConversionData The conversion data object. Typically, you should specify 
sl@0: conversionData, as declared in convgeneratedcpp.h. This is the 
sl@0: SCnvConversionData object which is created in the cnvtool-generated .cpp file 
sl@0: (although for some complex character sets you may want to pass other 
sl@0: SCnvConversionData objects into this parameter).
sl@0: @param aDefaultEndiannessOfForeignCharacters The default endian-ness of the 
sl@0: foreign characters. If an endian-ness for foreign characters is specified 
sl@0: in aConversionData, then that is used instead and the value of 
sl@0: aDefaultEndiannessOfForeignCharacters is ignored.
sl@0: @param aUnicode On return, contains the text converted into Unicode.
sl@0: @param aForeign The non-Unicode source text to be converted.
sl@0: @param aNumberOfUnconvertibleCharacters On return, contains the number of 
sl@0: characters in aForeign which were not converted. Characters which cannot be 
sl@0: converted are output as Unicode replacement characters (0xFFFD).
sl@0: @param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
sl@0: of the first byte of the first unconvertible character. For instance if the 
sl@0: first character in the input descriptor (aForeign) could not be converted, 
sl@0: then this parameter is set to the first byte of that character, i.e. zero. 
sl@0: A negative value is returned if all the characters were converted.
sl@0: @return The number of unconverted bytes left at the end of the input descriptor, 
sl@0: or a negative error value, as defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::DoConvertToUnicode(
sl@0: 									const SCnvConversionData& aConversionData, 
sl@0: 									TEndianness aDefaultEndiannessOfForeignCharacters, 
sl@0: 									TDes16& aUnicode, 
sl@0: 									const TDesC8& aForeign, 
sl@0: 									TInt& aNumberOfUnconvertibleCharacters, 
sl@0: 									TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter)
sl@0: 	{
sl@0: 	TUint notUsed;
sl@0: 	return DoConvertToUnicode(aConversionData, aDefaultEndiannessOfForeignCharacters, aUnicode, aForeign, aNumberOfUnconvertibleCharacters, aIndexOfFirstByteOfFirstUnconvertibleCharacter, notUsed, 0);
sl@0: 	}
sl@0: 
sl@0: /** Converts non-Unicode text into Unicode. The non-Unicode text specified in 
sl@0: aForeign is converted using the conversion data object (aConversionData) 
sl@0: provided by the plug-in for the foreign character set, and the converted text 
sl@0: is returned in aUnicode.
sl@0: 
sl@0: This overload differs from the previous one in that it allows the caller to 
sl@0: specify flags which give more control over the conversion.
sl@0: 
sl@0: Notes:
sl@0: 
sl@0: This is a utility function that should only be called from a plug-in conversion 
sl@0: library's implementation of ConvertToUnicode(). Ordinary users of the Character 
sl@0: Conversion API should use one of the overloads of ConvertToUnicode() instead.
sl@0: 
sl@0: The aNumberOfUnconvertibleCharacters and 
sl@0: aIndexOfFirstByteOfFirstUnconvertibleCharacter arguments return information 
sl@0: about unconverted characters. Because Unicode is intended to cover all 
sl@0: possible characters, these rarely report anything other than zero characters. 
sl@0: However they report the existence of unconvertible characters if the input 
sl@0: descriptor aForeign contains illegal characters, i.e. values not in the 
sl@0: foreign character set.
sl@0: 
sl@0: @param aConversionData The conversion data object. Typically, you should specify 
sl@0: conversionData, as declared in convgeneratedcpp.h. This is the 
sl@0: SCnvConversionData object which is created in the cnvtool-generated .cpp file 
sl@0: (although for some complex character sets you may want to pass other 
sl@0: SCnvConversionData objects into this parameter).
sl@0: @param aDefaultEndiannessOfForeignCharacters The default endian-ness of the 
sl@0: foreign characters. If an endian-ness for foreign characters is specified 
sl@0: in aConversionData, then that is used instead and the value of 
sl@0: aDefaultEndiannessOfForeignCharacters is ignored.
sl@0: @param aUnicode On return, contains the text converted into Unicode.
sl@0: @param aForeign The non-Unicode source text to be converted.
sl@0: @param aNumberOfUnconvertibleCharacters On return, contains the number of 
sl@0: characters in aForeign which were not converted. Characters which cannot be 
sl@0: converted are output as Unicode replacement characters (0xFFFD).
sl@0: @param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
sl@0: of the first byte of the first unconvertible character. For instance if the 
sl@0: first character in the input descriptor (aForeign) could not be converted, 
sl@0: then this parameter is set to the first byte of that character, i.e. zero. 
sl@0: A negative value is returned if all the characters were converted.
sl@0: @param aOutputConversionFlags If the input descriptor ended in a truncated 
sl@0: sequence, e.g. a multi-byte character that is not complete, aOutputConversionFlags 
sl@0: returns with the EOutputConversionFlagInputIsTruncated flag set.
sl@0: @param aInputConversionFlags Specify EInputConversionFlagAppend to append the 
sl@0: converted text to aUnicode, otherwise the contents of aUnicode are overwritten. 
sl@0: Specify EInputConversionFlagStopAtFirstUnconvertibleCharacter to stop converting 
sl@0: when the first unconvertible character is reached. Specify 
sl@0: EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable to prevent the 
sl@0: function from returning the error-code EErrorIllFormedInput when the input 
sl@0: descriptor consists of nothing but a truncated sequence.
sl@0: @return The number of unconverted bytes left at the end of the input descriptor, 
sl@0: or a negative error value defined in TError. */
sl@0: EXPORT_C TInt CCnvCharacterSetConverter::DoConvertToUnicode(
sl@0: 								const SCnvConversionData& aConversionData, 
sl@0: 								TEndianness aDefaultEndiannessOfForeignCharacters, 
sl@0: 								TDes16& aUnicode, 
sl@0: 								const TDesC8& aForeign, 
sl@0: 								TInt& aNumberOfUnconvertibleCharacters, 
sl@0: 								TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
sl@0: 								TUint& aOutputConversionFlags, 
sl@0: 								TUint aInputConversionFlags)
sl@0: 	{
sl@0: 	aNumberOfUnconvertibleCharacters=0;
sl@0: 	aIndexOfFirstByteOfFirstUnconvertibleCharacter=-1;
sl@0: 	aOutputConversionFlags=0;
sl@0: 	if (aForeign.Length()==0)
sl@0: 		{
sl@0: 		if (~aInputConversionFlags&EInputConversionFlagAppend)
sl@0: 			{
sl@0: 			aUnicode.SetLength(0);
sl@0: 			}
sl@0: 		return 0;
sl@0: 		}
sl@0: 	if (aUnicode.MaxLength()==((aInputConversionFlags&EInputConversionFlagAppend)? aUnicode.Length(): 0))
sl@0: 		{
sl@0: 		return aForeign.Length();
sl@0: 		}
sl@0: 	TUint16* pointerToPreviousUnicodeCharacter=CONST_CAST(TUint16*, aUnicode.Ptr()-1);
sl@0: 	const TUint16* const pointerToLastUnicodeCharacter=pointerToPreviousUnicodeCharacter+aUnicode.MaxLength();
sl@0: 	if (aInputConversionFlags&EInputConversionFlagAppend)
sl@0: 		{
sl@0: 		pointerToPreviousUnicodeCharacter+=aUnicode.Length();
sl@0: 		}
sl@0: 	const TUint8* pointerToCurrentForeignByte=aForeign.Ptr();
sl@0: 	const TUint8* const pointerToLastForeignByte=pointerToCurrentForeignByte+(aForeign.Length()-1);
sl@0: 	if (aConversionData.iForeignVariableByteData.iNumberOfRanges<=0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicBadNumberOfRanges2" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aConversionData.iForeignVariableByteData.iNumberOfRanges>0, Panic(EPanicBadNumberOfRanges2));
sl@0: 	const SCnvConversionData::SVariableByteData::SRange* const foreignVariableByteData_firstRange=aConversionData.iForeignVariableByteData.iRangeArray;
sl@0: 	const SCnvConversionData::SVariableByteData::SRange* const foreignVariableByteData_lastRange=foreignVariableByteData_firstRange+(aConversionData.iForeignVariableByteData.iNumberOfRanges-1);
sl@0: 	if (aConversionData.iForeignToUnicodeData.iNumberOfRanges<=0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, DUP1_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicBadNumberOfRanges3" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG(aConversionData.iForeignToUnicodeData.iNumberOfRanges>0, Panic(EPanicBadNumberOfRanges3));
sl@0: 	const SCnvConversionData::SOneDirectionData::SRange* const oneDirectionData_firstRange=aConversionData.iForeignToUnicodeData.iRangeArray;
sl@0: 	const SCnvConversionData::SOneDirectionData::SRange* const oneDirectionData_lastRange=oneDirectionData_firstRange+(aConversionData.iForeignToUnicodeData.iNumberOfRanges-1);
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		if (pointerToPreviousUnicodeCharacter>pointerToLastUnicodeCharacter)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP2_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit15" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToPreviousUnicodeCharacter<=pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit15));
sl@0: 		if (pointerToCurrentForeignByte>pointerToLastForeignByte)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP3_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit16" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToCurrentForeignByte<=pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit16));
sl@0: 		TBool stop=EFalse;
sl@0: 		TUint inputCharacterCode=*pointerToCurrentForeignByte;
sl@0: 		const SCnvConversionData::SVariableByteData::SRange* foreignVariableByteData_currentRange=foreignVariableByteData_firstRange;
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if (foreignVariableByteData_currentRange->iNumberOfSubsequentBytes>=sizeof(TUint))
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP4_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicBadNumberOfSubsequentBytes" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(foreignVariableByteData_currentRange->iNumberOfSubsequentBytes<sizeof(TUint), Panic(EPanicBadNumberOfSubsequentBytes));
sl@0: 			if ((inputCharacterCode>=foreignVariableByteData_currentRange->iFirstInitialByteValueInRange) && (inputCharacterCode<=foreignVariableByteData_currentRange->iLastInitialByteValueInRange))
sl@0: 				{
sl@0: 				const TInt numberOfSubsequentBytes=foreignVariableByteData_currentRange->iNumberOfSubsequentBytes;
sl@0: 				if (pointerToCurrentForeignByte>pointerToLastForeignByte)
sl@0: 				    {
sl@0: 				    OstTrace0( TRACE_DUMP, DUP5_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit17" );
sl@0: 				    }
sl@0: 				__ASSERT_DEBUG(pointerToCurrentForeignByte<=pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit17));
sl@0: 				if (pointerToLastForeignByte-pointerToCurrentForeignByte<numberOfSubsequentBytes)
sl@0: 					{
sl@0: 					aOutputConversionFlags|=EOutputConversionFlagInputIsTruncated;
sl@0: 					goto end;
sl@0: 					}
sl@0: 				switch (EndiannessOfForeignCharacters(aConversionData, aDefaultEndiannessOfForeignCharacters))
sl@0: 					{
sl@0: 				case ELittleEndian:
sl@0: 					{
sl@0: 					for (TInt i=1; i<=numberOfSubsequentBytes; ++i)
sl@0: 						{
sl@0: 						if (pointerToCurrentForeignByte>=pointerToLastForeignByte)
sl@0: 						    {
sl@0: 						    OstTrace0( TRACE_DUMP, DUP6_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit18" );
sl@0: 						    }
sl@0: 						__ASSERT_DEBUG(pointerToCurrentForeignByte<pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit18));
sl@0: 						++pointerToCurrentForeignByte;
sl@0: 						TUint currentForeignByte=*pointerToCurrentForeignByte;
sl@0: 						currentForeignByte<<=(i*8);
sl@0: 						inputCharacterCode|=currentForeignByte;
sl@0: 						}
sl@0: 					}
sl@0: 					break;
sl@0: 				case EBigEndian:
sl@0: 					{
sl@0: 					for (TInt i=numberOfSubsequentBytes; i>0; --i)
sl@0: 						{
sl@0: 						if (pointerToCurrentForeignByte>=pointerToLastForeignByte)
sl@0: 						    {
sl@0: 						    OstTrace0( TRACE_DUMP, DUP7_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit19" );
sl@0: 						    }
sl@0: 						__ASSERT_DEBUG(pointerToCurrentForeignByte<pointerToLastForeignByte, Panic(EPanicPointerPastUpperLimit19));
sl@0: 						++pointerToCurrentForeignByte;
sl@0: 						inputCharacterCode<<=8;
sl@0: 						inputCharacterCode|=*pointerToCurrentForeignByte;
sl@0: 						}
sl@0: 					}
sl@0: 					break;
sl@0: #if defined(_DEBUG)
sl@0: 				default:
sl@0: 				    OstTrace0( TRACE_DUMP, DUP8_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicBadEndianness2" );
sl@0: 					Panic(EPanicBadEndianness2);
sl@0: 					break;
sl@0: #endif
sl@0: 					}
sl@0: 				pointerToCurrentForeignByte-=numberOfSubsequentBytes; // resets pointerToCurrentForeignByte to its value before the loop above
sl@0: 				break;
sl@0: 				}
sl@0: 			if (foreignVariableByteData_currentRange>foreignVariableByteData_lastRange)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP9_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit20" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(foreignVariableByteData_currentRange<=foreignVariableByteData_lastRange, Panic(EPanicPointerPastUpperLimit20));
sl@0: 			if (foreignVariableByteData_currentRange>=foreignVariableByteData_lastRange)
sl@0: 				{
sl@0: 				return EErrorIllFormedInput;
sl@0: 				}
sl@0: 			++foreignVariableByteData_currentRange;
sl@0: 			}
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange* oneDirectionData_currentRange=oneDirectionData_firstRange;
sl@0: 		TUint outputCharacterCode=KNoConversionAvailable;
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			if ((inputCharacterCode>=oneDirectionData_currentRange->iFirstInputCharacterCodeInRange) &&
sl@0: 				(inputCharacterCode<=oneDirectionData_currentRange->iLastInputCharacterCodeInRange))
sl@0: 				{
sl@0: 				outputCharacterCode=OutputCharacterCode(inputCharacterCode, *oneDirectionData_currentRange);
sl@0: 				if (outputCharacterCode!=KNoConversionAvailable)
sl@0: 					{
sl@0: 					break;
sl@0: 					}
sl@0: 				}
sl@0: 			if (oneDirectionData_currentRange>oneDirectionData_lastRange)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP10_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit21" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(oneDirectionData_currentRange<=oneDirectionData_lastRange, Panic(EPanicPointerPastUpperLimit21));
sl@0: 			if (oneDirectionData_currentRange>=oneDirectionData_lastRange)
sl@0: 				{
sl@0: 				break;
sl@0: 				}
sl@0: 			++oneDirectionData_currentRange;
sl@0: 			}
sl@0: 		if (pointerToPreviousUnicodeCharacter>pointerToLastUnicodeCharacter)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP11_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit22" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToPreviousUnicodeCharacter<=pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit22));
sl@0: 		if (pointerToPreviousUnicodeCharacter==pointerToLastUnicodeCharacter)
sl@0: 			{
sl@0: 			goto end;
sl@0: 			}
sl@0: 		if (outputCharacterCode==KNoConversionAvailable)
sl@0: 			{
sl@0: 			outputCharacterCode=0xfffd; // Unicode's "REPLACEMENT CHARACTER"
sl@0: 			if (aNumberOfUnconvertibleCharacters<0)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_FATAL, DUP13_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicBadNumberOfUnconvertibleCharacters" );
sl@0: 			    }
sl@0: 			__ASSERT_ALWAYS(aNumberOfUnconvertibleCharacters>=0, Panic(EPanicBadNumberOfUnconvertibleCharacters));
sl@0: 			if (aNumberOfUnconvertibleCharacters<=0)
sl@0: 				{
sl@0: 				aIndexOfFirstByteOfFirstUnconvertibleCharacter=pointerToCurrentForeignByte-aForeign.Ptr();
sl@0: 				}
sl@0: 			++aNumberOfUnconvertibleCharacters;
sl@0: 			if (aInputConversionFlags&EInputConversionFlagStopAtFirstUnconvertibleCharacter)
sl@0: 				{
sl@0: 				stop=ETrue;
sl@0: 				}
sl@0: 			}
sl@0: 		if (outputCharacterCode<0x00010000)
sl@0: 			{
sl@0: 			++pointerToPreviousUnicodeCharacter;
sl@0: 			*pointerToPreviousUnicodeCharacter=STATIC_CAST(TUint16, outputCharacterCode);
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			if (outputCharacterCode>=0x00110000)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP12_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicBadNon16BitCharacterCode2" );
sl@0: 				}
sl@0: 			__ASSERT_DEBUG(outputCharacterCode<0x00110000, Panic(EPanicBadNon16BitCharacterCode2));
sl@0: 			if (pointerToPreviousUnicodeCharacter>pointerToLastUnicodeCharacter)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP14_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit23" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(pointerToPreviousUnicodeCharacter<=pointerToLastUnicodeCharacter, Panic(EPanicPointerPastUpperLimit23));
sl@0: 			if (pointerToLastUnicodeCharacter-pointerToPreviousUnicodeCharacter<2)
sl@0: 				{
sl@0: 				goto end;
sl@0: 				}
sl@0: 			outputCharacterCode-=0x00010000;
sl@0: 			++pointerToPreviousUnicodeCharacter;
sl@0: 			*pointerToPreviousUnicodeCharacter=STATIC_CAST(TUint16, (outputCharacterCode>>10)|0xd800);
sl@0: 			++pointerToPreviousUnicodeCharacter;
sl@0: 			*pointerToPreviousUnicodeCharacter=STATIC_CAST(TUint16, (outputCharacterCode&0x000003ff)|0xdc00);
sl@0: 			}
sl@0: 		if (pointerToLastForeignByte-pointerToCurrentForeignByte<foreignVariableByteData_currentRange->iNumberOfSubsequentBytes)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP15_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastUpperLimit24" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(pointerToLastForeignByte-pointerToCurrentForeignByte>=foreignVariableByteData_currentRange->iNumberOfSubsequentBytes, Panic(EPanicPointerPastUpperLimit24));
sl@0: 		pointerToCurrentForeignByte+=foreignVariableByteData_currentRange->iNumberOfSubsequentBytes;
sl@0: 		if (pointerToCurrentForeignByte==pointerToLastForeignByte)
sl@0: 			{
sl@0: 			++pointerToCurrentForeignByte; // this increment is done regardless of the test just above, but it's not done before the test as it may make pointerToCurrentForeignByte greater than pointerToLastForeignByte, and if pointerToLastForeignByte just happens to be pointing at 0xffffffff, will pointerToCurrentForeignByte will be pointing at 0x00000000, thus the test (which would now be "if (pointerToCurrentForeignByte>pointerToLastForeignByte)") would fail
sl@0: 			goto end;
sl@0: 			}
sl@0: 		++pointerToCurrentForeignByte;
sl@0: 		if (stop)
sl@0: 			{
sl@0: 			goto end;
sl@0: 			}
sl@0: 		}
sl@0: end:
sl@0:     if (pointerToCurrentForeignByte<aForeign.Ptr())
sl@0:         {
sl@0:         OstTrace0( TRACE_DUMP, DUP16_CCNVCHARACTERSETCONVERTER_DOCONVERTTOUNICODE, "EPanicPointerPastLowerLimit2" );
sl@0:         }
sl@0: 	__ASSERT_DEBUG(pointerToCurrentForeignByte>=aForeign.Ptr(), Panic(EPanicPointerPastLowerLimit2));
sl@0: 	if ((pointerToCurrentForeignByte<=aForeign.Ptr()) && (aOutputConversionFlags&EOutputConversionFlagInputIsTruncated) && (~aInputConversionFlags&EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable))
sl@0: 		{
sl@0: 		return EErrorIllFormedInput;
sl@0: 		}
sl@0: 	aUnicode.SetLength((pointerToPreviousUnicodeCharacter+1)-aUnicode.Ptr());
sl@0: 	return pointerToLastForeignByte-(pointerToCurrentForeignByte-1);
sl@0: 	}
sl@0: 
sl@0: 
sl@0: /** Returns a ready-made SCnvConversionData object for converting between 
sl@0: Unicode and ASCII. This can be passed into the aConversionData parameter to 
sl@0: DoConvertFromUnicode() or DoConvertToUnicode().
sl@0: 
sl@0: Note: This utility function should only be called by a plug-in conversion 
sl@0: library.
sl@0: 
sl@0: @return ASCII conversion data object. */
sl@0: EXPORT_C const SCnvConversionData& CCnvCharacterSetConverter::AsciiConversionData()
sl@0: 	{
sl@0: 	return asciiConversionData;
sl@0: 	}
sl@0: 
sl@0: CCnvCharacterSetConverter::CCnvCharacterSetConverter()
sl@0: 	:iStoredFlags(0),
sl@0: 	 iCharacterSetIdentifierOfLoadedConversionData(0),
sl@0: 	 iConversionData(NULL),
sl@0: 	 iDefaultEndiannessOfForeignCharacters(ELittleEndian),
sl@0: 	 iDowngradeForExoticLineTerminatingCharacters(EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed),
sl@0: 	 iReplacementForUnconvertibleUnicodeCharacters(KNullDesC8),
sl@0: 	 iStandardNamesAndMibEnums(NULL),
sl@0: 	 iIsSystemStandardNamesAndMibEnumsScanned(EFalse)
sl@0: 	{
sl@0: 	}
sl@0: 
sl@0: void CCnvCharacterSetConverter::ConstructL()
sl@0: 	{
sl@0: 	iCharsetCnvCache = CCharsetCnvCache::NewL();
sl@0: 	TTlsData::CharacterSetConverterIsBeingCreatedL();
sl@0: 	iTlsDataConstructed = ETrue;
sl@0: 	}
sl@0: 
sl@0: // set aIdentifierOfOnlyCharacterSetOfInterest to 0 if all character sets are of interest
sl@0: //RFs& aFileServerSession function parameter is not used anymore.ECom plugin framework used.
sl@0: CArrayFix<CCnvCharacterSetConverter::SCharacterSet>* 
sl@0: CCnvCharacterSetConverter::DoCreateArrayOfCharacterSetsAvailableLC(
sl@0: 								RFs& /*aFileServerSession*/, 
sl@0: 								TUint aIdentifierOfOnlyCharacterSetOfInterest) 
sl@0: 	{
sl@0: 	CArrayFix<SCharacterSet>* arrayOfCharacterSetsAvailable=CDeepDestructingArrayOfCharactersSets::NewLC(12);
sl@0: 	if ((AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierUtf7,               KLitCharacterSetNameUtf7				)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierUtf8,               KLitCharacterSetNameUtf8				)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierImapUtf7,           KLitCharacterSetNameImapUtf7			)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierJavaConformantUtf8, KLitCharacterSetNameJavaConformantUtf8	)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierCodePage1252,       KLitCharacterSetNameCodePage1252		)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierWin1252,       		KLitCharacterSetNameCodePage1252		)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierIso88591,           KLitCharacterSetNameIso88591			)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierAscii,              KLitCharacterSetNameAscii				)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierUnicodeLittle,		KLitCharacterSetNameUnicodeLittle		)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierUnicodeBig,			KLitCharacterSetNameUnicodeBig			)==EStopCharacterSetSearch) ||
sl@0: 		(AppendHardCodedCharacterSetIfRequiredL(*arrayOfCharacterSetsAvailable, aIdentifierOfOnlyCharacterSetOfInterest, KCharacterSetIdentifierSms7Bit,            KLitCharacterSetNameSms7Bit				)==EStopCharacterSetSearch))
sl@0: 		{
sl@0: 		return arrayOfCharacterSetsAvailable;
sl@0: 		}
sl@0: 	
sl@0: 	//Look for ECOM Character Set Convertors...
sl@0:  	RImplInfoPtrArray convertorsImplArray;
sl@0:  	REComSession::ListImplementationsL(KCharacterSetConvertorInterfaceUid, convertorsImplArray);
sl@0:  	CleanupStack::PushL(TCleanupItem(ResetAndDestroyRImplInfoPtrArray, &convertorsImplArray));
sl@0:  	TBool fileIsDll = ETrue;
sl@0: 	
sl@0: 	for(TInt i = 0; i < convertorsImplArray.Count(); i++)
sl@0: 		{
sl@0: 		CImplementationInformation* implInfo = convertorsImplArray[i];
sl@0: 		const TUint characterSetIdentifier = (implInfo->ImplementationUid()).iUid;
sl@0: 
sl@0: 		if(aIdentifierOfOnlyCharacterSetOfInterest == 0) 
sl@0: 		// only if we're interested in all character sets do we need to make sure we've not already added this one to the array
sl@0: 			{
sl@0: 			for(TInt j = arrayOfCharacterSetsAvailable->Count() - 1; j >= 0; --j)
sl@0: 				{
sl@0: 				if((*arrayOfCharacterSetsAvailable)[j].Identifier() == characterSetIdentifier)
sl@0: 					{
sl@0: 					goto afterAddingNewCharacterSet;
sl@0: 					}
sl@0: 				}
sl@0: 			}
sl@0: 
sl@0: #if defined(_DEBUG)
sl@0: 			{
sl@0: 			for(TInt j = arrayOfCharacterSetsAvailable->Count() - 1; j >= 0; --j)
sl@0: 				{
sl@0: 				if ((*arrayOfCharacterSetsAvailable)[j].Identifier() == characterSetIdentifier)
sl@0: 				    {
sl@0: 				    OstTrace0( TRACE_DUMP, DUP1_CCNVCHARACTERSETCONVERTER_DOCREATEARRAYOFCHARACTERSETSAVAILABLELC, "EPanicCharacterSetAlreadyAdded" );
sl@0: 				    }
sl@0: 				__ASSERT_DEBUG((*arrayOfCharacterSetsAvailable)[j].Identifier() != characterSetIdentifier, Panic(EPanicCharacterSetAlreadyAdded));
sl@0: 				}
sl@0: 			}
sl@0: #endif
sl@0: 
sl@0: 		if((aIdentifierOfOnlyCharacterSetOfInterest == 0) || (aIdentifierOfOnlyCharacterSetOfInterest == characterSetIdentifier))
sl@0: 			{
sl@0: 			SCharacterSet characterSet;
sl@0: 			characterSet.iIdentifier = characterSetIdentifier;
sl@0: 			characterSet.iFlags = SCharacterSet::EFlagNameIsFileName;
sl@0: 
sl@0: 			if(fileIsDll)
sl@0: 				{
sl@0: 				characterSet.iFlags |= SCharacterSet::EFlagFileIsConversionPlugInLibrary;
sl@0: 				}
sl@0: 
sl@0: 			characterSet.iName = implInfo->DisplayName().AllocLC();
sl@0: 
sl@0: 			arrayOfCharacterSetsAvailable->AppendL(characterSet);
sl@0: 			
sl@0: 			OstTraceDefExt1( OST_TRACE_CATEGORY_PRODUCTION | OST_TRACE_CATEGORY_RND, TRACE_INTERNALS, 
sl@0: 			            CCNVCHARACTERSETCONVERTER_DOCREATEARRAYOFCHARACTERSETSAVAILABLELC, 
sl@0: 			             "%S Appended to Character Set Array",  *(characterSet.iName) );
sl@0: 
sl@0: 			CleanupStack::Pop(characterSet.iName); //characterSet.iName
sl@0: 			}
sl@0: 
sl@0: 			if(aIdentifierOfOnlyCharacterSetOfInterest == characterSetIdentifier)
sl@0: 				{
sl@0: 					CleanupStack::PopAndDestroy(&convertorsImplArray); //convertorsImplArray
sl@0: 					return arrayOfCharacterSetsAvailable;
sl@0: 				}
sl@0: 
sl@0: afterAddingNewCharacterSet:
sl@0: 				; //dummy statement after label to prevent compiler warning
sl@0: 
sl@0: 		}//end of for(TInt i = 0; i < convertorsImplArray.Count(); i++)
sl@0: 
sl@0: 	CleanupStack::PopAndDestroy(&convertorsImplArray); //convertorsImplArray
sl@0: 
sl@0: 	return arrayOfCharacterSetsAvailable;
sl@0: 	}
sl@0: 
sl@0: CCnvCharacterSetConverter::TCharacterSetSearch 
sl@0: CCnvCharacterSetConverter::AppendHardCodedCharacterSetIfRequiredL(
sl@0: 										CArrayFix<SCharacterSet>& aArrayOfCharacterSets, 
sl@0: 										TUint aIdentifierOfOnlyCharacterSetOfInterest, 
sl@0: 										TUint aIdentifierOfHardCodedCharacterSet, 
sl@0: 										const TDesC& aNameOfHardCodedCharacterSet)
sl@0: 	{
sl@0: 	if ((aIdentifierOfOnlyCharacterSetOfInterest==0) || (aIdentifierOfOnlyCharacterSetOfInterest==aIdentifierOfHardCodedCharacterSet))
sl@0: 		{
sl@0: 		SCharacterSet characterSet;
sl@0: 		characterSet.iIdentifier=aIdentifierOfHardCodedCharacterSet;
sl@0: 		characterSet.iFlags=0;
sl@0: 		characterSet.iName=aNameOfHardCodedCharacterSet.AllocLC();
sl@0: 		aArrayOfCharacterSets.AppendL(characterSet);
sl@0: 		CleanupStack::Pop(); // characterSet.iName
sl@0: 		if (aIdentifierOfOnlyCharacterSetOfInterest==aIdentifierOfHardCodedCharacterSet)
sl@0: 			{
sl@0: 			return EStopCharacterSetSearch;
sl@0: 			}
sl@0: 		}
sl@0: 	return EContinueCharacterSetSearch;
sl@0: 	}
sl@0: 
sl@0: void 
sl@0: CCnvCharacterSetConverter::ScanForStandardNamesAndMibEnumsROMOnlyL(RFs& aFileServerSession)
sl@0: 	{
sl@0: 	CStandardNamesAndMibEnums* standardNamesAndMibEnums=CStandardNamesAndMibEnums::NewLC();
sl@0: 	TFindFile* findFile=new(ELeave) TFindFile(aFileServerSession);
sl@0: 	CleanupStack::PushL(findFile);
sl@0: 	TParse* fileNameParser=new(ELeave) TParse;
sl@0: 	CleanupStack::PushL(fileNameParser);
sl@0: 	CDir* directory=NULL;
sl@0: 	TInt findResult=findFile->FindWildByDir(KLitWildCard, KLitROMSystemCharconvDirectory, directory);
sl@0: 	if (findResult==KErrNone)
sl@0: 		{
sl@0: 		CleanupStack::PushL(directory);
sl@0: 		for (TInt i=directory->Count()-1; i>=0; --i)
sl@0: 			{
sl@0: 			const TEntry& entry=(*directory)[i];
sl@0: 			if (entry.iType[0].iUid==0x1000589b)
sl@0: 				{
sl@0: 				fileNameParser->SetNoWild(entry.iName, &findFile->File(), NULL);
sl@0: 				standardNamesAndMibEnums->AddFromFileL(aFileServerSession, fileNameParser->FullName());
sl@0: 				}
sl@0: 			}
sl@0: 		CleanupStack::PopAndDestroy(); // directory
sl@0: 		directory=NULL;
sl@0: 		}
sl@0: 	delete directory;
sl@0: 	CleanupStack::PopAndDestroy(2); // fileNameParser and findFile
sl@0: 	delete iStandardNamesAndMibEnums;
sl@0: 	iStandardNamesAndMibEnums=standardNamesAndMibEnums;
sl@0: 	CleanupStack::Pop(); // standardNamesAndMibEnums
sl@0: 		}
sl@0: 
sl@0: 
sl@0: void CCnvCharacterSetConverter::ScanForStandardNamesAndMibEnumsL(RFs& aFileServerSession)
sl@0: 	{
sl@0: 	CStandardNamesAndMibEnums* standardNamesAndMibEnums=CStandardNamesAndMibEnums::NewLC();
sl@0: 	TFindFile* findFile=new(ELeave) TFindFile(aFileServerSession);
sl@0: 	CleanupStack::PushL(findFile);
sl@0: 	TParse* fileNameParser=new(ELeave) TParse;
sl@0: 	CleanupStack::PushL(fileNameParser);
sl@0: 	CDir* directory=NULL;
sl@0: 	for (TInt findResult=findFile->FindWildByDir(KLitWildCard, KLitSystemCharconvDirectory, directory); findResult!=KErrNotFound; findResult=findFile->FindWild(directory))
sl@0: 		{
sl@0: 		CleanupStack::PushL(directory);
sl@0: 		User::LeaveIfError(findResult);
sl@0: 		for (TInt i=directory->Count()-1; i>=0; --i)
sl@0: 			{
sl@0: 			const TEntry& entry=(*directory)[i];
sl@0: 			if (entry.iType[0].iUid==0x1000589b)
sl@0: 				{
sl@0: 				fileNameParser->SetNoWild(entry.iName, &findFile->File(), NULL);
sl@0: 				standardNamesAndMibEnums->AddFromFileL(aFileServerSession, fileNameParser->FullName());
sl@0: 				}
sl@0: 			}
sl@0: 		CleanupStack::PopAndDestroy(); // directory
sl@0: 		directory=NULL;
sl@0: 		}
sl@0: 	delete directory;
sl@0: 	CleanupStack::PopAndDestroy(2); // fileNameParser and findFile
sl@0: 	delete iStandardNamesAndMibEnums;
sl@0: 	iStandardNamesAndMibEnums=standardNamesAndMibEnums;
sl@0: 	CleanupStack::Pop(); // standardNamesAndMibEnums
sl@0: 	}
sl@0: 
sl@0: 
sl@0: CCnvCharacterSetConverter::TAvailability 
sl@0: CCnvCharacterSetConverter::DoPrepareToConvertToOrFromL(
sl@0: 								TUint aCharacterSetIdentifier, 
sl@0: 								const CArrayFix<SCharacterSet>* aArrayOfCharacterSetsAvailable, 
sl@0: 								RFs& aFileServerSession)
sl@0: 	{
sl@0:     OstTraceExt2( TRACE_DUMP, DUP3_CCNVCHARACTERSETCONVERTER_DOPREPARETOCONVERTTOORFROML, "Prepare to convert aCharacterSetIdentifier(0x%x) in aArrayOfCharacterSetsAvailable(0x%x)", aCharacterSetIdentifier, (unsigned int)aArrayOfCharacterSetsAvailable);
sl@0:     
sl@0: 	//AutoDetectCharacterSetL relies on the fact that this function does not use 
sl@0: 	//aFileServerSession if aArrayOfCharacterSetsAvailable is *not* NULL and 
sl@0: 	//if aCharacterSetIdentifier is *not* a data file
sl@0: 	// aFileServerSession is no longer used load Plugin libraries. ECom framework used instead
sl@0: 	if (aCharacterSetIdentifier==0)
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_DOPREPARETOCONVERTTOORFROML, "EPanicNullCharacterSetIdentifier3" );
sl@0: 	    }
sl@0: 	__ASSERT_ALWAYS(aCharacterSetIdentifier!=0, Panic(EPanicNullCharacterSetIdentifier3));
sl@0: 	if (iCharacterSetIdentifierOfLoadedConversionData!=aCharacterSetIdentifier)
sl@0: 		{
sl@0: 
sl@0: 		TUint newStoredFlags=0;
sl@0: 		const SCnvConversionData* newConversionData=NULL;
sl@0: 		TBuf8<KMaximumLengthOfReplacementForUnconvertibleUnicodeCharacters> replacementForUnconvertibleUnicodeCharacters(KNullDesC8);
sl@0: 		switch (aCharacterSetIdentifier)
sl@0: 			{
sl@0: 		case KCharacterSetIdentifierUtf7:
sl@0: 		case KCharacterSetIdentifierUtf8:
sl@0: 		case KCharacterSetIdentifierImapUtf7:
sl@0: 		case KCharacterSetIdentifierJavaConformantUtf8:
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierCodePage1252:
sl@0: 		case KCharacterSetIdentifierWin1252:
sl@0: 			{
sl@0: 			newConversionData=&codePage1252ConversionData;
sl@0: 			replacementForUnconvertibleUnicodeCharacters=KLit8AsciiSubstituteCharacter;
sl@0: 			}
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierIso88591:
sl@0: 			{
sl@0: 			newConversionData=&iso88591ConversionData;
sl@0: 			replacementForUnconvertibleUnicodeCharacters=KLit8AsciiSubstituteCharacter;
sl@0: 			}
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierAscii:
sl@0: 			{
sl@0: 			newConversionData=&asciiConversionData;
sl@0: 			replacementForUnconvertibleUnicodeCharacters=KLit8AsciiSubstituteCharacter;
sl@0: 			}
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierSms7Bit:
sl@0: 			{
sl@0: 			newConversionData=&sms7BitConversionData;
sl@0: 			replacementForUnconvertibleUnicodeCharacters=KLit8Sms7BitSubstituteCharacter;
sl@0: 			}
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUnicodeLittle:
sl@0: 			{
sl@0: 			newConversionData=&unicodeConversionDataLittle;
sl@0: 			}
sl@0: 			break;
sl@0: 		case KCharacterSetIdentifierUnicodeBig:
sl@0: 			{
sl@0: 			newConversionData=&unicodeConversionDataBig;
sl@0: 			}
sl@0: 			break;
sl@0: 		default:
sl@0: 			if (aArrayOfCharacterSetsAvailable==NULL)
sl@0: 				{
sl@0: 				aArrayOfCharacterSetsAvailable=DoCreateArrayOfCharacterSetsAvailableLC(aFileServerSession, aCharacterSetIdentifier);
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				CleanupStack::PushL(STATIC_CAST(TAny*, NULL)); // dummy item on the cleanup-stack so that we can simply CleanupStack::PopAndDestroy() on ending the loop below
sl@0: 				}
sl@0: 
sl@0: 			for (TInt i=aArrayOfCharacterSetsAvailable->Count()-1; ; --i)
sl@0: 				{
sl@0: 				if (i<0)
sl@0: 					{
sl@0: 					CleanupStack::PopAndDestroy(); // aArrayOfCharacterSetsAvailable or dummy NULL pointer
sl@0: 					return ENotAvailable;
sl@0: 					}
sl@0: 				const SCharacterSet& characterSet=(*aArrayOfCharacterSetsAvailable)[i];
sl@0: 				if (characterSet.Identifier()==aCharacterSetIdentifier)
sl@0: 					{
sl@0: 					if (!characterSet.NameIsFileName())
sl@0: 					    {
sl@0: 					    OstTrace0( TRACE_DUMP, DUP1_CCNVCHARACTERSETCONVERTER_DOPREPARETOCONVERTTOORFROML, "EPanicNameIsNotFileName" );
sl@0: 					    }
sl@0: 					__ASSERT_DEBUG(characterSet.NameIsFileName(), Panic(EPanicNameIsNotFileName));
sl@0: 					if (characterSet.FileIsConversionPlugInLibrary())
sl@0: 						{
sl@0: 						newStoredFlags|=EStoredFlagConversionPlugInLibraryIsLoaded;
sl@0: 						
sl@0: 						TUid implUid;
sl@0:  						implUid.iUid = aCharacterSetIdentifier;
sl@0:  						replacementForUnconvertibleUnicodeCharacters = (iCharsetCnvCache->GetConverterL(implUid))->ReplacementForUnconvertibleUnicodeCharacters();
sl@0: 						}
sl@0: 					else
sl@0: 						{
sl@0: 						//You are here?! This should never happen! Source code here was related to
sl@0: 						//old type character set converter data!
sl@0: 						OstTrace0( TRACE_FATAL, DUP2_CCNVCHARACTERSETCONVERTER_DOPREPARETOCONVERTTOORFROML, "EPanicCharacterSetNotPresent" );
sl@0:  						__ASSERT_ALWAYS(EFalse, Panic(EPanicCharacterSetNotPresent));
sl@0: 						}
sl@0: 					break;
sl@0: 					}
sl@0: 				}
sl@0: 			CleanupStack::PopAndDestroy(); // aArrayOfCharacterSetsAvailable or dummy NULL pointer
sl@0: 			break;
sl@0: 			}
sl@0: 		iStoredFlags&=~EStoredFlagConversionPlugInLibraryIsLoaded;
sl@0: 		iCharacterSetIdentifierOfLoadedConversionData=aCharacterSetIdentifier;
sl@0: 		iStoredFlags|=newStoredFlags;
sl@0: 		iConversionData=newConversionData;
sl@0: 		iDefaultEndiannessOfForeignCharacters=ELittleEndian;
sl@0: 		iDowngradeForExoticLineTerminatingCharacters=EDowngradeExoticLineTerminatingCharactersToCarriageReturnLineFeed;
sl@0: 		iReplacementForUnconvertibleUnicodeCharacters=replacementForUnconvertibleUnicodeCharacters;
sl@0: 		}
sl@0: 	return EAvailable;
sl@0: 	}
sl@0: 
sl@0: LOCAL_C void DeleteOneDirectionData(
sl@0: 								TInt aNumberOfRanges, 
sl@0: 								const SCnvConversionData::SOneDirectionData::SRange* aRange)
sl@0: 	{
sl@0: 	if ( !((aRange!=NULL) || (aNumberOfRanges==0)) )
sl@0: 	    {
sl@0: 	    OstTrace0( TRACE_DUMP, _DELETEONEDIRECTIONDATA, "EPanicBadNumberOfRanges4" );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG((aRange!=NULL) || (aNumberOfRanges==0), Panic(EPanicBadNumberOfRanges4));
sl@0: 	if (aRange!=NULL)
sl@0: 		{
sl@0: 		if (aNumberOfRanges<=0)
sl@0: 		    {
sl@0: 		    OstTrace0( TRACE_DUMP, DUP1__DELETEONEDIRECTIONDATA, "EPanicBadNumberOfRanges5" );
sl@0: 		    }
sl@0: 		__ASSERT_DEBUG(aNumberOfRanges>0, Panic(EPanicBadNumberOfRanges5));
sl@0: 		SCnvConversionData::SOneDirectionData::SRange* currentRange=CONST_CAST(SCnvConversionData::SOneDirectionData::SRange*, aRange);
sl@0: 		const SCnvConversionData::SOneDirectionData::SRange* const lastRange=currentRange+(aNumberOfRanges-1);
sl@0: 		FOREVER
sl@0: 			{
sl@0: 			switch (currentRange->iAlgorithm)
sl@0: 				{
sl@0: 			case SCnvConversionData::SOneDirectionData::SRange::EDirect:
sl@0: 			case SCnvConversionData::SOneDirectionData::SRange::EOffset:
sl@0: 				break;
sl@0: 			case SCnvConversionData::SOneDirectionData::SRange::EIndexedTable16:
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 				delete [] CONST_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SIndexedTable16*, currentRange->iData.iIndexedTable16.iEntryArray);
sl@0: #else
sl@0: 				delete [] REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SIndexedTable16*, currentRange->iData.iWord1);
sl@0: #endif
sl@0: 				break;
sl@0: 			case SCnvConversionData::SOneDirectionData::SRange::EKeyedTable1616:
sl@0: #if defined(CONST_STATIC_UNIONS_ARE_POSSIBLE)
sl@0: 				delete [] CONST_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616*, currentRange->iData.iKeyedTable1616.iEntryArray);
sl@0: #else
sl@0: 				delete [] REINTERPRET_CAST(SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616*, currentRange->iData.iWord2);
sl@0: #endif
sl@0: 				break;
sl@0: 			case SCnvConversionData::SOneDirectionData::SRange::EKeyedTable16OfIndexedTables16:
sl@0: 				// fall through
sl@0: #if defined(_DEBUG)
sl@0: 			default:
sl@0: 			    OstTrace0( TRACE_FATAL, DUP2__DELETEONEDIRECTIONDATA, "EPanicBadAlgorithm2" );
sl@0: 				Panic(EPanicBadAlgorithm2);
sl@0: #endif
sl@0: 				break;
sl@0: 				}
sl@0: 			if (currentRange>lastRange)
sl@0: 			    {
sl@0: 			    OstTrace0( TRACE_DUMP, DUP3__DELETEONEDIRECTIONDATA, "EPanicPointerPastUpperLimit25" );
sl@0: 			    }
sl@0: 			__ASSERT_DEBUG(currentRange<=lastRange, Panic(EPanicPointerPastUpperLimit25));
sl@0: 			if (currentRange==lastRange)
sl@0: 				{
sl@0: 				break;
sl@0: 				}
sl@0: 			++currentRange;
sl@0: 			}
sl@0: 		delete [] CONST_CAST(SCnvConversionData::SOneDirectionData::SRange*, aRange);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CCnvCharacterSetConverter::DeleteConversionData(const SCnvConversionData* aConversionData)
sl@0: 	{
sl@0: 	if (aConversionData!=NULL)
sl@0: 		{
sl@0: 		delete [] CONST_CAST(SCnvConversionData::SVariableByteData::SRange*, aConversionData->iForeignVariableByteData.iRangeArray);
sl@0: 		DeleteOneDirectionData(aConversionData->iForeignToUnicodeData.iNumberOfRanges, aConversionData->iForeignToUnicodeData.iRangeArray);
sl@0: 		DeleteOneDirectionData(aConversionData->iUnicodeToForeignData.iNumberOfRanges, aConversionData->iUnicodeToForeignData.iRangeArray);
sl@0: 		delete CONST_CAST(SCnvConversionData*, aConversionData);
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: void CCnvCharacterSetConverter::DeleteConversionData(TAny* aConversionData)
sl@0: 	{
sl@0: 	DeleteConversionData(STATIC_CAST(SCnvConversionData*, aConversionData));
sl@0: 	}
sl@0: 
sl@0: CCnvCharacterSetConverter::TEndianness 
sl@0: CCnvCharacterSetConverter::EndiannessOfForeignCharacters(
sl@0: 											const SCnvConversionData& aConversionData, 
sl@0: 											TEndianness aDefaultEndiannessOfForeignCharacters)
sl@0: 	{
sl@0: 	switch (aConversionData.iEndiannessOfForeignCharacters)
sl@0: 		{
sl@0: 	case SCnvConversionData::EUnspecified:
sl@0: 		return aDefaultEndiannessOfForeignCharacters;
sl@0: 	case SCnvConversionData::EFixedLittleEndian:
sl@0: 		return ELittleEndian;
sl@0: 	case SCnvConversionData::EFixedBigEndian:
sl@0: 		return EBigEndian;
sl@0: 		}
sl@0: #if defined(_DEBUG)
sl@0: 	OstTrace0( TRACE_DUMP, CCNVCHARACTERSETCONVERTER_ENDIANNESSOFFOREIGNCHARACTERS, "EPanicBadEndianness3" );
sl@0: 	Panic(EPanicBadEndianness3);
sl@0: #endif
sl@0: 	return ELittleEndian; // dummy return to prevent compiler error
sl@0: 	}
sl@0: 
sl@0: // CCnvCharacterSetConverter::TArrayOfAscendingIndices
sl@0: 
sl@0: /** Appends an index to the array of indices.
sl@0: 
sl@0: The value of aIndex should be greater than that of the
sl@0: last index in the array, to maintain an ascending array. The return
sl@0: value should be tested to see whether the function succeeded or not.
sl@0: 
sl@0: @param aIndex The index to append to the array.
sl@0: @return EAppendFailed if the append failed, or
sl@0: EAppendSuccessful if it succeeded. */
sl@0: EXPORT_C CCnvCharacterSetConverter::TArrayOfAscendingIndices::TAppendResult 
sl@0: CCnvCharacterSetConverter::TArrayOfAscendingIndices::AppendIndex(TInt aIndex)
sl@0:  	{
sl@0:  	if ( aIndex<0 )
sl@0:  	    {
sl@0:  	    OstTrace1( TRACE_DUMP, DUP2_TARRAYOFASCENDINGINDICES_APPENDINDEX, "Bad index in TArrayOfAscendingIndices::AppendIndex;aIndex=%d", aIndex );    
sl@0:  	    }
sl@0: 	__ASSERT_DEBUG(aIndex>=0, Panic(EPanicBadIndex));
sl@0: 	const TInt lengthOfArrayOfIndices=iArrayOfIndices.Length();
sl@0: 	if ((aIndex>STATIC_CAST(TInt, KMaxTUint16)) || (lengthOfArrayOfIndices==iArrayOfIndices.MaxLength()))
sl@0: 		{
sl@0: 		return EAppendFailed;
sl@0: 		}
sl@0: 	if ( (lengthOfArrayOfIndices!=0) && (iArrayOfIndices[lengthOfArrayOfIndices-1]>=aIndex))
sl@0: 	    {
sl@0: 	    OstTrace1( TRACE_DUMP, DUP1_TARRAYOFASCENDINGINDICES_APPENDINDEX, "Duplicate Index Or Not Ascending in TArrayOfAscendingIndices::AppendIndex;aIndex=%d", aIndex );
sl@0: 	    }
sl@0: 	__ASSERT_DEBUG((lengthOfArrayOfIndices==0) || (iArrayOfIndices[lengthOfArrayOfIndices-1]<aIndex), Panic(EPanicDuplicateIndexOrNotAscending));
sl@0: 	iArrayOfIndices.Append(aIndex);
sl@0: 	return EAppendSuccessful;
sl@0: 	}
sl@0: 	
sl@0: /**
sl@0: The method sets the max size of the internal character set converter cache.
sl@0: The cache is used mainly to improve the performance of AutoDetectCharSetL() calls.
sl@0: It caches loaded converter implementations. The next time when a specific implementation is needed,
sl@0: a search will be done in the cache if this implementation is already loaded and if it is there,
sl@0: the cached implementation will be used. SetMaxCacheSize() call
sl@0: is used to limit the max cache size, because the loaded implementatiions may consume a lot of the 
sl@0: system resources (memory for example).
sl@0: By default (if SetMaxCacheSize() is never called) the max cache size is limited to 32 entries.
sl@0: Note: Setting very small cache size will impact the overall performance of CHARCONV functions.
sl@0: 		If the choosen cache size is less than the number of existing character set converter 
sl@0: 		implementations, there will be no performance gain or it will be far beyond client's 
sl@0: 		expectations. For best performance the choosen cache size should be bigger or equal to 
sl@0: 		the number of the existing character set converter implementations.
sl@0: @param aSize The new max cache size. It must be bigger or equal to 4.
sl@0: @panic User::Invariant() if the new max cache size is less than 4.
sl@0: @see CCnvCharacterSetConverter::AutoDetectCharSetL
sl@0: */
sl@0: EXPORT_C void CCnvCharacterSetConverter::SetMaxCacheSize(TInt aSize)
sl@0:     {
sl@0:     if ( aSize < CCharsetCnvCache::KMinCacheSize )
sl@0:         {
sl@0:         OstTrace1( TRACE_FATAL, CCNVCHARACTERSETCONVERTER_SETMAXCACHESIZE, "Parameter aSize < KMinCacheSize in CCnvCharacterSetConverter::SetMaxCacheSize;aSize=%d", aSize );
sl@0:         }
sl@0:     __ASSERT_ALWAYS(aSize >= CCharsetCnvCache::KMinCacheSize, User::Invariant());
sl@0:     iCharsetCnvCache->SetMaxSize(aSize);
sl@0:     }
sl@0: