charconvfw/charconv_fw/src/convutils/convutils.cpp
changeset 0 1fb32624e06b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/charconvfw/charconv_fw/src/convutils/convutils.cpp	Tue Feb 02 02:02:46 2010 +0200
@@ -0,0 +1,900 @@
+/*
+* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+#include <e32std.h>
+#include <e32base.h>
+#include <charconv.h>
+#include <convutils.h>
+                   
+const TInt KNoPreviousCharacterSet=-1;
+const TInt KDefaultCharacterSet = 0;
+const TUint KControlCharacterEscape=0x1b;
+
+#if defined(_DEBUG)
+//It will cause performance problem with small KMaximumLengthOfIntermediateBuffer.
+//Please use release version to test performance cases.
+const TInt KMaximumLengthOfIntermediateBuffer=5;
+#else
+const TInt KMaximumLengthOfIntermediateBuffer=150;
+#endif
+
+struct SCnvConversionData;
+
+_LIT(KLitPanicText, "CONVUTILS");
+
+enum TPanic
+	{
+	EPanicBadInputConversionFlags1=1,
+	EPanicBadInputConversionFlags2,
+	EPanicBadInputConversionFlags3,
+	EPanicBadNumberOfUnicodeElementsConsumed,
+	EPanicAppendFlagViolated,
+	EPanicBadNumberOfUnicodeCharactersConverted,
+	EPanicBadNumberOfCharactersThatDroppedOut,
+	EPanicLoopCounterOverRun1,
+	EPanicLoopCounterOverRun2,
+	EPanicDescriptorNotWholeNumberOfCharacters1,
+	EPanicDescriptorNotWholeNumberOfCharacters2,
+	EPanicDescriptorNotWholeNumberOfCharacters3,
+	EPanicDescriptorNotWholeNumberOfCharacters4,
+	EPanicBadStartOfNextEscapeSequence,
+	EPanicInconsistentNumberOfForeignBytesRemaining,
+	EPanicBadLengthOfRunToConvert1,
+	EPanicBadLengthOfRunToConvert2,
+	EPanicBadMethodPointer,
+	EPanicBadMethodData1,
+	EPanicBadMethodData2,
+	EPanicBadMethodData3,
+	EPanicBadMethodData4,
+	EPanicBadNumberOfCharacterSets,
+	EPanicBadConversionDataPointer1,
+	EPanicBadConversionDataPointer2,
+	EPanicBadConversionDataPointer3,
+	EPanicBadFunctionPointer1,
+	EPanicBadFunctionPointer2,
+	EPanicBadFunctionPointer3,
+	EPanicBadEscapeSequencePointer1,
+	EPanicBadEscapeSequencePointer2,
+	EPanicBadNumberOfStates,
+	EPanicBadEscapeSequenceStart,
+	EPanicBadNumberOfMethods,
+	EPanicBadSurrogatePair1,
+	EPanicBadSurrogatePair2,
+	EPanicBadRemainderOfForeign,
+	EPanicOutputDescriptorTooShortEvenToHoldEscapeSequenceToDefaultCharacterSet
+	};
+
+LOCAL_C void Panic(TPanic aPanic)
+	{
+	User::Panic(KLitPanicText, aPanic);
+	}
+
+/** Converts Unicode text into a complex foreign character set encoding. This 
+is an encoding which cannot be converted simply by calling 
+CCnvCharacterSetConverter::DoConvertFromUnicode(). It may be modal (e.g. JIS) 
+or non-modal (e.g. Shift-JIS).
+
+The Unicode text specified in aUnicode is converted using the array of 
+conversion data objects (aArrayOfCharacterSets) provided by the plug-in for 
+the complex character set encoding, and the converted text is returned in 
+aForeign. Any existing contents in aForeign are overwritten.
+
+Unlike CCnvCharacterSetConverter::DoConvertFromUnicode(), multiple character 
+sets can be specified. aUnicode is converted using the first character conversion 
+data object in the array. When a character is found which cannot be converted 
+using that data, each character set in the array is tried in turn. If it cannot 
+be converted using any object in the array, the index of the character is 
+appended to aIndicesOfUnconvertibleCharacters and the character is replaced 
+by aReplacementForUnconvertibleUnicodeCharacters.
+
+If it can be converted using another object in the array, that object is used 
+to convert all subsequent characters until another unconvertible character 
+is found.
+
+@param aDefaultEndiannessOfForeignCharacters The default endian-ness to use 
+when writing the characters in the foreign character set. If an endian-ness 
+for foreign characters is specified in the current conversion data object, 
+then that is used instead and the value of 
+aDefaultEndiannessOfForeignCharacters is ignored. 
+@param aReplacementForUnconvertibleUnicodeCharacters The single character (one 
+or more byte values) which is used to replace unconvertible characters. 
+@param aForeign On return, contains the converted text in the non-Unicode 
+character set. 
+@param aUnicode The source Unicode text to be converted. 
+@param aIndicesOfUnconvertibleCharacters On return, holds an ascending array 
+of the indices of each Unicode character in the source text which could not 
+be converted (because none of the target character sets have an equivalent 
+character). 
+@param aArrayOfCharacterSets Array of character conversion data objects, 
+representing the character sets which comprise a complex character set 
+encoding. These are used in sequence to convert the Unicode text. There must 
+be at least one character set in this array and no character set may have any 
+NULL member data, or a panic occurs. 
+@return The number of unconverted characters left at the end of the input 
+descriptor (e.g. because aForeign was not long enough to hold all the text), 
+or a negative error value, as defined in CCnvCharacterSetConverter::TError. */
+EXPORT_C TInt CnvUtilities::ConvertFromUnicode(
+		CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
+		const TDesC8& aReplacementForUnconvertibleUnicodeCharacters, 
+		TDes8& aForeign, 
+		const TDesC16& aUnicode, 
+		CCnvCharacterSetConverter::TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters, 
+		const TArray<SCharacterSet>& aArrayOfCharacterSets)
+	{
+	TUint notUsed;
+	return ConvertFromUnicode(aDefaultEndiannessOfForeignCharacters, 
+								aReplacementForUnconvertibleUnicodeCharacters, 
+								aForeign, 
+								aUnicode, 
+								aIndicesOfUnconvertibleCharacters, 
+								aArrayOfCharacterSets, 
+								notUsed, 
+								0);
+	}
+
+/** Converts Unicode text into a complex foreign character set encoding. This is 
+an encoding which cannot be converted simply by a call to 
+CCnvCharacterSetConverter::DoConvertFromUnicode(). It may be modal (e.g. JIS) 
+or non-modal (e.g. Shift-JIS).
+
+The Unicode text specified in aUnicode is converted using the array of conversion 
+data objects (aArrayOfCharacterSets) provided by the plug-in for the complex 
+character set encoding and the converted text is returned in aForeign. The 
+function can either append to aForeign or overwrite its contents (if any).
+
+Unlike CCnvCharacterSetConverter::DoConvertFromUnicode(), multiple character 
+sets can be specified. aUnicode is converted using the first character conversion 
+data object in the array. When a character is found which cannot be converted 
+using that data, each character set in the array is tried in turn. If it cannot 
+be converted using any object in the array, the index of the character is 
+appended to aIndicesOfUnconvertibleCharacters and the character is replaced 
+by aReplacementForUnconvertibleUnicodeCharacters.
+
+If it can be converted using another object in the array, that object is used 
+to convert all subsequent characters until another unconvertible character 
+is found.
+
+@param aDefaultEndiannessOfForeignCharacters The default endian-ness to use 
+when writing the characters in the foreign character set. If an endian-ness 
+for foreign characters is specified in the current conversion data object, 
+then that is used instead and the value of 
+aDefaultEndiannessOfForeignCharacters is ignored. 
+@param aReplacementForUnconvertibleUnicodeCharacters The single character (one 
+or more byte values) which is used to replace unconvertible characters. 
+@param aForeign On return, contains the converted text in the non-Unicode 
+character set. This may already contain some text. If it does, and if 
+aInputConversionFlags specifies EInputConversionFlagAppend, then the converted 
+text is appended to this descriptor. 
+@param aUnicode The source Unicode text to be converted. 
+@param aIndicesOfUnconvertibleCharacters On return, holds an ascending array 
+of the indices of each Unicode character in the source text which could not 
+be converted (because none of the target character sets have an equivalent 
+character). 
+@param aArrayOfCharacterSets Array of character set data objects. These are 
+used in sequence to convert the Unicode text. There must be at least one 
+character set in this array and no character set may have any NULL member 
+data, or a panic occurs. 
+@param aOutputConversionFlags If the input descriptor ended in a truncated 
+sequence, e.g. the first half only of a Unicode surrogate pair, this returns 
+with the EOutputConversionFlagInputIsTruncated flag set. 
+@param aInputConversionFlags Specify 
+CCnvCharacterSetConverter::EInputConversionFlagAppend to append the text to 
+aForeign. Specify CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable 
+to prevent the function from returning the error-code EErrorIllFormedInput 
+when the input descriptor consists of nothing but a truncated sequence. The 
+CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter 
+flag must not be set, otherwise a panic occurs. 
+@return The number of unconverted characters left at the end of the input descriptor 
+(e.g. because aForeign was not long enough to hold all the text), or a negative 
+error value, as defined in CCnvCharacterSetConverter::TError. */
+EXPORT_C TInt CnvUtilities::ConvertFromUnicode(
+				CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
+				const TDesC8& aReplacementForUnconvertibleUnicodeCharacters, 
+				TDes8& aForeign, 
+				const TDesC16& aUnicode, 
+				CCnvCharacterSetConverter::TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters, 
+				const TArray<SCharacterSet>& aArrayOfCharacterSets, 
+				TUint& aOutputConversionFlags, 
+				TUint aInputConversionFlags)
+	{
+	__ASSERT_ALWAYS(~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter, Panic(EPanicBadInputConversionFlags1));
+	CheckArrayOfCharacterSets(aArrayOfCharacterSets);
+	aOutputConversionFlags=0;
+	TUint internalInputConversionFlags=aInputConversionFlags;
+	if (~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAppend)
+		{
+		aForeign.SetLength(0);
+		internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagAppend;
+		}
+	if (aUnicode.Length()==0)
+		{
+		return 0;
+		}
+	if (aForeign.MaxLength()==aForeign.Length()) // relies on the fact that aForeign's length has been set to zero if aInputConversionFlags does not have CCnvCharacterSetConverter::EInputConversionFlagAppend set
+		{
+		return aUnicode.Length();
+		}
+	TDes8* foreign=&aForeign;
+	TPtr8 dummyForeign(NULL, 0, 0);
+	if (aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagMustEndInDefaultCharacterSet)
+		{
+		TInt dummyMaximumLength =
+			aForeign.MaxLength() - aArrayOfCharacterSets[KDefaultCharacterSet].iEscapeSequence->Length();
+		__ASSERT_ALWAYS(dummyMaximumLength >= 0, 
+			Panic(EPanicOutputDescriptorTooShortEvenToHoldEscapeSequenceToDefaultCharacterSet));
+		dummyForeign.Set(const_cast <TUint8*> (aForeign.Ptr()),
+						 aForeign.Length(), 
+						 dummyMaximumLength);
+		foreign=&dummyForeign;
+		}
+	const TInt numberOfCharacterSets=aArrayOfCharacterSets.Count();
+	TInt numberOfUnicodeElementsConsumed=0;
+	internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter; // this is not just an optimization - it ensures that "foreign" doesn't get filled up too much each time CCnvCharacterSetConverter::DoConvertFromUnicode is called
+    TInt previousCharacterSet = aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAssumeStartInDefaultCharacterSet?
+        KDefaultCharacterSet : KNoPreviousCharacterSet;
+	FOREVER
+		{
+		for (TInt presentCharacterSet=KDefaultCharacterSet;;)
+			{
+			__ASSERT_DEBUG(numberOfUnicodeElementsConsumed<=aUnicode.Length(), Panic(EPanicBadNumberOfUnicodeElementsConsumed));
+			if (numberOfUnicodeElementsConsumed>=aUnicode.Length())
+				{
+				goto end;
+				}
+			const SCharacterSet& characterSet=aArrayOfCharacterSets[presentCharacterSet];
+			const TInt oldNumberOfBytesInForeign=foreign->Length();
+			if (numberOfUnicodeElementsConsumed>0)
+				{
+				internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable;
+				}
+			CCnvCharacterSetConverter::TArrayOfAscendingIndices indicesOfUnconvertibleCharacters;
+			const TInt returnValue=CCnvCharacterSetConverter::DoConvertFromUnicode(*characterSet.iConversionData, aDefaultEndiannessOfForeignCharacters, KNullDesC8, *foreign, aUnicode.Mid(numberOfUnicodeElementsConsumed), indicesOfUnconvertibleCharacters, aOutputConversionFlags, internalInputConversionFlags);
+			if (returnValue<0)
+				{
+				return returnValue; // this is an error-code
+				}
+			__ASSERT_DEBUG(foreign->Length()>=oldNumberOfBytesInForeign, Panic(EPanicAppendFlagViolated));
+			TInt indexOfFirstUnconvertibleCharacter;
+			if (indicesOfUnconvertibleCharacters.NumberOfIndices()==0)
+				{
+				indexOfFirstUnconvertibleCharacter=-1;
+				numberOfUnicodeElementsConsumed=aUnicode.Length()-returnValue;
+				}
+			else
+				{
+				indexOfFirstUnconvertibleCharacter=indicesOfUnconvertibleCharacters[0];
+				numberOfUnicodeElementsConsumed+=indexOfFirstUnconvertibleCharacter;
+				__ASSERT_DEBUG(numberOfUnicodeElementsConsumed+LengthOfUnicodeCharacter(aUnicode, numberOfUnicodeElementsConsumed)==aUnicode.Length()-returnValue, Panic(EPanicBadNumberOfUnicodeCharactersConverted));
+				}
+			if (indexOfFirstUnconvertibleCharacter!=0) // if at least one Unicode character at the start of CCnvCharacterSetConverter::DoConvertFromUnicode's input descriptor was convertible...
+				{
+				TBool gotoEnd = EFalse;
+				if (foreign->Length()>oldNumberOfBytesInForeign)
+					{
+					TInt numberOfCharactersThatDroppedOut=0;
+                     // Insert an escape sequence if this character set is different from the last one.
+                     if (presentCharacterSet  != previousCharacterSet)
+                        {
+                        // Insert escape sequence (if requred) in front of the last encoded run of text.
+                        // Note that this may cause some characters to drop out at the end.
+                        (*characterSet.iConvertFromIntermediateBufferInPlace)(oldNumberOfBytesInForeign, *foreign, numberOfCharactersThatDroppedOut);
+                        if (oldNumberOfBytesInForeign < foreign->Length())
+                			previousCharacterSet = presentCharacterSet;
+                        }
+					numberOfUnicodeElementsConsumed-=numberOfCharactersThatDroppedOut;
+					if (numberOfCharactersThatDroppedOut>0 )// if "foreign" has been filled to as much as it will hold...
+						{
+						gotoEnd = ETrue;
+						}
+					}
+				if (indexOfFirstUnconvertibleCharacter<0) // if we've successfully converted up to the end of aUnicode (using *characterSet.iConversionData)...
+					{
+					gotoEnd = ETrue;
+					}
+				if (gotoEnd)
+					{
+					if ( aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagMustEndInDefaultCharacterSet
+					    && previousCharacterSet != KDefaultCharacterSet
+					    && previousCharacterSet != KNoPreviousCharacterSet)
+					    {
+					    aForeign.SetLength(foreign->Length());
+    				    aForeign.Append(*aArrayOfCharacterSets[KDefaultCharacterSet].iEscapeSequence);
+    				    foreign=NULL;
+					    }
+					goto end;
+					}
+				break;
+				}
+			__ASSERT_DEBUG(presentCharacterSet<numberOfCharacterSets, Panic(EPanicLoopCounterOverRun1));
+			++presentCharacterSet;
+			if (presentCharacterSet>=numberOfCharacterSets)
+				{
+				if ((foreign->MaxLength()-foreign->Length()<aReplacementForUnconvertibleUnicodeCharacters.Length()) ||
+					(aIndicesOfUnconvertibleCharacters.AppendIndex(numberOfUnicodeElementsConsumed)!=CCnvCharacterSetConverter::TArrayOfAscendingIndices::EAppendSuccessful)) // the tests must be done in this order as AppendIndex must only be called if there is room for aReplacementForUnconvertibleUnicodeCharacters
+					{
+					goto end;
+					}
+				numberOfUnicodeElementsConsumed+=LengthOfUnicodeCharacter(aUnicode, numberOfUnicodeElementsConsumed);
+				foreign->Append(aReplacementForUnconvertibleUnicodeCharacters);
+				break;
+				}
+			}
+		}
+end:
+	if (foreign!=NULL)
+		{
+		aForeign.SetLength(foreign->Length());
+		foreign=NULL;
+		}
+	if ((numberOfUnicodeElementsConsumed==0) && (aOutputConversionFlags&CCnvCharacterSetConverter::EOutputConversionFlagInputIsTruncated) && (~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable))
+		{
+		return CCnvCharacterSetConverter::EErrorIllFormedInput;
+		}
+	return aUnicode.Length()-numberOfUnicodeElementsConsumed;
+	}
+
+
+/** Inserts an escape sequence into the descriptor.
+
+This function is provided to help in the implementation of
+ConvertFromUnicode() for modal character set encodings.
+Each SCharacterSet object in the array passed to
+ConvertFromUnicode() must have its
+iConvertFromIntermediateBufferInPlace member assigned. To
+do this for a modal character set encoding, implement a function whose
+signature matches that of FConvertFromIntermediateBufferInPlace 
+and which calls this function, passing all arguments unchanged, and 
+specifying the character set's escape sequence and the number of bytes per 
+character.
+
+@param aStartPositionInDescriptor The byte position in aDescriptor at which 
+the escape sequence is inserted. If the character set uses more than one byte 
+per character, this position must be the start of a character, otherwise a 
+panic occurs. 
+@param aDescriptor The descriptor into which the escape sequence is inserted. 
+@param aNumberOfCharactersThatDroppedOut The escape sequence is inserted into 
+the start of aDescriptor and any characters that need to drop out to make 
+room for the escape sequence (because the descriptor's maximum length was 
+not long enough) drop out from the end of the buffer. This parameter indicates 
+the number of characters that needed to drop out.
+@param aEscapeSequence The escape sequence for the character set. 
+@param aNumberOfBytesPerCharacter The number of bytes per character. */
+EXPORT_C void CnvUtilities::ConvertFromIntermediateBufferInPlace(
+					TInt aStartPositionInDescriptor, 
+					TDes8& aDescriptor, 
+					TInt& aNumberOfCharactersThatDroppedOut, 
+					const TDesC8& aEscapeSequence, 
+					TInt aNumberOfBytesPerCharacter)
+	{
+	const TInt lengthOfDescriptor=aDescriptor.Length();
+	__ASSERT_ALWAYS((lengthOfDescriptor-aStartPositionInDescriptor)%aNumberOfBytesPerCharacter==0, Panic(EPanicDescriptorNotWholeNumberOfCharacters1));
+	aNumberOfCharactersThatDroppedOut=(Max(0, aEscapeSequence.Length()-(aDescriptor.MaxLength()-lengthOfDescriptor))+(aNumberOfBytesPerCharacter-1))/aNumberOfBytesPerCharacter;
+	const TInt lengthOfRunInCharacters=(lengthOfDescriptor-aStartPositionInDescriptor)/aNumberOfBytesPerCharacter;
+	if (aNumberOfCharactersThatDroppedOut>=lengthOfRunInCharacters) // ">=" is correct (rather than ">") as if there's only room for the escape sequence we don't want to have it in the descriptor
+		{
+		aNumberOfCharactersThatDroppedOut=lengthOfRunInCharacters;
+		aDescriptor.SetLength(aStartPositionInDescriptor);
+		}
+	else
+		{
+		aDescriptor.SetLength(lengthOfDescriptor-(aNumberOfCharactersThatDroppedOut*aNumberOfBytesPerCharacter));
+		aDescriptor.Insert(aStartPositionInDescriptor, aEscapeSequence);
+		}
+	}
+
+
+/**  Converts text from a modal foreign character set encoding into Unicode.
+
+The non-Unicode text specified in aForeign is converted using 
+the array of character set conversion objects (aArrayOfStates) 
+provided by the plug-in, and the converted text is returned in 
+aUnicode. The function can either append to aUnicode 
+or overwrite its contents (if any), depending on the input conversion flags 
+specified. The first element in aArrayOfStates is taken to be 
+the default mode (i.e. the mode to assume by default if there is no preceding 
+escape sequence).
+ 
+@param aDefaultEndiannessOfForeignCharacters The default endian-ness of the 
+foreign characters. If an endian-ness for foreign characters is specified 
+in the conversion data, then that is used instead and the value of 
+aDefaultEndiannessOfForeignCharacters is ignored. 
+@param aUnicode On return, contains the text converted into Unicode. 
+@param aForeign The non-Unicode source text to be converted. 
+@param aState Used to store a modal character set encoding's current mode across 
+multiple calls to ConvertToUnicode() on the same input descriptor. This argument 
+should be passed the same object as passed to the plug-in's ConvertToUnicode() 
+exported function.
+@param aNumberOfUnconvertibleCharacters On return, contains the number of 
+characters in aForeign which were not converted. Characters which cannot be 
+converted are output as Unicode replacement characters (0xfffd). 
+@param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
+of the first byte of the first unconvertible character. For instance if the 
+first character in the input descriptor (aForeign) could not be converted, 
+then this parameter is set to the first byte of that character, i.e. zero. 
+A negative value is returned if all the characters were converted. 
+@param aArrayOfStates Array of character set conversion data objects, and their 
+escape sequences ("modes"). There must be one or more modes in this array, 
+none of the modes can have any NULL member data, and each mode's escape sequence 
+must begin with KControlCharacterEscape (0x1b) or a panic occurs. 
+@return The number of unconverted bytes left at the end of the input descriptor, 
+or a negative error value, as defined in TError. */
+EXPORT_C TInt CnvUtilities::ConvertToUnicodeFromModalForeign(
+					CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
+					TDes16& aUnicode, 
+					const TDesC8& aForeign, 
+					TInt& aState, 
+					TInt& aNumberOfUnconvertibleCharacters, 
+					TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
+					const TArray<SState>& aArrayOfStates)
+	{
+	TUint notUsed;
+	return ConvertToUnicodeFromModalForeign(aDefaultEndiannessOfForeignCharacters, 
+											aUnicode, 
+											aForeign, 
+											aState, 
+											aNumberOfUnconvertibleCharacters, 
+											aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
+											aArrayOfStates, 
+											notUsed, 
+											0);
+	}
+
+/** @param aDefaultEndiannessOfForeignCharacters The default endian-ness for 
+the foreign characters. If an endian-ness for foreign characters is specified 
+in the conversion data, then that is used instead and the value of 
+aDefaultEndiannessOfForeignCharacters is ignored. 
+@param aUnicode On return, contains the text converted into Unicode. 
+@param aForeign The non-Unicode source text to be converted. 
+@param aState Used to store a modal character set encoding's current mode 
+across multiple calls to ConvertToUnicode() on the same input descriptor. This 
+argument should be passed the same object as passed to the plug-in's 
+ConvertToUnicode() exported function. 
+@param aNumberOfUnconvertibleCharacters On return, contains the number of 
+characters in aForeign which were not converted. Characters which cannot be 
+converted are output as Unicode replacement characters (0xfffd). 
+@param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
+of the first byte of the first unconvertible character. For instance if the 
+first character in the input descriptor (aForeign) could not be converted, 
+then this parameter is set to the first byte of that character, i.e. zero. 
+A negative value is returned if all the characters were converted. 
+@param aArrayOfStates Array of character set conversion data objects, and their 
+escape sequences. There must be one or more modes in this array, none of the 
+modes can have any NULL member data, and each mode's escape sequence must 
+begin with KControlCharacterEscape (0x1b) or a panic occurs. 
+@param aOutputConversionFlags If the input descriptor ended in a truncated 
+sequence, e.g. a part of a multi-byte character, aOutputConversionFlags 
+returns with the EOutputConversionFlagInputIsTruncated flag set. 
+@param aInputConversionFlags Specify 
+CCnvCharacterSetConverter::EInputConversionFlagAppend to append the text to 
+aUnicode. Specify EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable 
+to prevent the function from returning the error-code EErrorIllFormedInput 
+when the input descriptor consists of nothing but a truncated sequence. The 
+CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter 
+flag must not be set, otherwise a panic occurs. 
+@return The number of unconverted bytes left at the end of the input descriptor, 
+or a negative error value, as defined in TError. */
+EXPORT_C TInt CnvUtilities::ConvertToUnicodeFromModalForeign(
+								CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
+								TDes16& aUnicode, 
+								const TDesC8& aForeign, 
+								TInt& aState, 
+								TInt& aNumberOfUnconvertibleCharacters, 
+								TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
+								const TArray<SState>& aArrayOfStates, 
+								TUint& aOutputConversionFlags, 
+								TUint aInputConversionFlags)
+	{
+	__ASSERT_ALWAYS(~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter, Panic(EPanicBadInputConversionFlags2));
+	CheckArrayOfStates(aArrayOfStates);
+	aNumberOfUnconvertibleCharacters=0;
+	aIndexOfFirstByteOfFirstUnconvertibleCharacter=-1;
+	aOutputConversionFlags=0;
+	TUint internalInputConversionFlags=aInputConversionFlags;
+	if (~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAppend)
+		{
+		aUnicode.SetLength(0);
+		internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagAppend;
+		}
+	if (aForeign.Length()==0)
+		{
+		return 0;
+		}
+	if (aUnicode.MaxLength()==aUnicode.Length()) // relies on the fact that aUnicode's length has been set to zero if aInputConversionFlags does not have CCnvCharacterSetConverter::EInputConversionFlagAppend set
+		{
+		return aForeign.Length();
+		}
+	TPtrC8 remainderOfForeign(aForeign);
+	TPtrC8 homogeneousRun;
+	TInt numberOfForeignBytesConsumed=0;
+	const SCnvConversionData* conversionData = NULL;
+	const TInt startOfNextEscapeSequence=aForeign.Locate(KControlCharacterEscape);
+	if (startOfNextEscapeSequence!=0) // if aForeign doesn't start with an escape sequence...
+		{
+		conversionData=(aState!=CCnvCharacterSetConverter::KStateDefault)? REINTERPRET_CAST(const SCnvConversionData*, aState): aArrayOfStates[0].iConversionData;
+		if (startOfNextEscapeSequence==KErrNotFound)
+			{
+			homogeneousRun.Set(remainderOfForeign);
+			remainderOfForeign.Set(NULL, 0);
+			}
+		else
+			{
+			__ASSERT_DEBUG(startOfNextEscapeSequence>0, Panic(EPanicBadStartOfNextEscapeSequence));
+			homogeneousRun.Set(remainderOfForeign.Left(startOfNextEscapeSequence));
+			remainderOfForeign.Set(remainderOfForeign.Mid(startOfNextEscapeSequence));
+			}
+		goto handleHomogeneousRun;
+		}
+	FOREVER
+		{
+		if (!NextHomogeneousForeignRun(conversionData, numberOfForeignBytesConsumed, homogeneousRun, remainderOfForeign, aArrayOfStates, aOutputConversionFlags))
+			{
+			goto end;
+			}
+handleHomogeneousRun:
+		if (conversionData==NULL)
+			{
+			return CCnvCharacterSetConverter::EErrorIllFormedInput;
+			}
+		TInt numberOfUnconvertibleCharacters;
+		TInt indexOfFirstByteOfFirstUnconvertibleCharacter;
+		const TInt returnValue=CCnvCharacterSetConverter::DoConvertToUnicode(*conversionData, aDefaultEndiannessOfForeignCharacters, aUnicode, homogeneousRun, numberOfUnconvertibleCharacters, indexOfFirstByteOfFirstUnconvertibleCharacter, aOutputConversionFlags, internalInputConversionFlags);
+		if (returnValue<0)
+			{
+			return returnValue; // this is an error-code
+			}
+		if (numberOfUnconvertibleCharacters>0)
+			{
+			if (aNumberOfUnconvertibleCharacters==0)
+				{
+				aIndexOfFirstByteOfFirstUnconvertibleCharacter=numberOfForeignBytesConsumed+indexOfFirstByteOfFirstUnconvertibleCharacter;
+				}
+			aNumberOfUnconvertibleCharacters+=numberOfUnconvertibleCharacters;
+			}
+		numberOfForeignBytesConsumed+=homogeneousRun.Length();
+		if (returnValue>0)
+			{
+			numberOfForeignBytesConsumed-=returnValue;
+			goto end;
+			}
+		if (numberOfForeignBytesConsumed>0)
+			{
+			internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable;
+			}
+		__ASSERT_DEBUG(remainderOfForeign==aForeign.Mid(numberOfForeignBytesConsumed), Panic(EPanicInconsistentNumberOfForeignBytesRemaining));
+		}
+end:
+	if ((numberOfForeignBytesConsumed==0) && (aOutputConversionFlags&CCnvCharacterSetConverter::EOutputConversionFlagInputIsTruncated) && (~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable))
+		{
+		return CCnvCharacterSetConverter::EErrorIllFormedInput;
+		}
+	aState=REINTERPRET_CAST(TInt, conversionData);
+	return aForeign.Length()-numberOfForeignBytesConsumed;
+	}
+
+
+/**  Converts text from a non-modal complex character set encoding (e.g. 
+Shift-JIS or EUC-JP) into Unicode.The non-Unicode text specified in
+aForeign is converted using the array of character set
+conversion methods (aArrayOfMethods) provided by the
+plug-in, and the converted text is returned in aUnicode.
+Overwrites the contents, if any, of aUnicode.
+
+@param aDefaultEndiannessOfForeignCharacters The default endian-ness of the 
+foreign characters. If an endian-ness for foreign characters is specified 
+in the conversion data, then that is used instead and the value of 
+aDefaultEndiannessOfForeignCharacters is ignored. 
+@param aUnicode On return, contains the text converted into Unicode. 
+@param aForeign The non-Unicode source text to be converted. 
+@param aNumberOfUnconvertibleCharacters On return, contains the number of 
+characters in aForeign which were not converted. Characters which cannot be 
+converted are output as Unicode replacement characters (0xfffd). 
+@param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
+of the first byte of the first unconvertible character. For instance if the 
+first character in the input descriptor (aForeign) could not be converted, 
+then this parameter is set to the first byte of that character, i.e. zero. 
+A negative value is returned if all the characters were converted. 
+@param aArrayOfMethods Array of conversion methods. There must be one or more 
+methods in this array and none of the methods in the array can have any NULL 
+member data or a panic occurs. 
+@return The number of unconverted bytes left at the end of the input descriptor, 
+or a negative error value, as defined in TError. */
+EXPORT_C TInt CnvUtilities::ConvertToUnicodeFromHeterogeneousForeign(
+					CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
+					TDes16& aUnicode, 
+					const TDesC8& aForeign, 
+					TInt& aNumberOfUnconvertibleCharacters, 
+					TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
+					const TArray<SMethod>& aArrayOfMethods)
+	{
+	TUint notUsed;
+	return ConvertToUnicodeFromHeterogeneousForeign(
+				aDefaultEndiannessOfForeignCharacters, 
+				aUnicode, 
+				aForeign, 
+				aNumberOfUnconvertibleCharacters, 
+				aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
+				aArrayOfMethods, 
+				notUsed, 
+				0);
+	}
+
+/** @param aDefaultEndiannessOfForeignCharacters The default endian-ness for the 
+foreign characters. If an endian-ness for foreign characters is specified 
+in the conversion data, then that is used instead and the value of 
+aDefaultEndiannessOfForeignCharacters is ignored. 
+@param aUnicode On return, contains the text converted into Unicode. 
+@param aForeign The non-Unicode source text to be converted. 
+@param aNumberOfUnconvertibleCharacters On return, contains the number of 
+characters in aForeign which were not converted. Characters which cannot be 
+converted are output as Unicode replacement characters (0xfffd). 
+@param aIndexOfFirstByteOfFirstUnconvertibleCharacter On return, the index 
+of the first byte of the first unconvertible character. For instance if the 
+first character in the input descriptor (aForeign) could not be converted, 
+then this parameter is set to the first byte of that character, i.e. zero. 
+A negative value is returned if all the characters were converted. 
+@param aArrayOfMethods Array of conversion methods. There must be one or more 
+methods in this array and none of the methods in the array can have any NULL 
+member data or a panic occurs. 
+@param aOutputConversionFlags If the input descriptor ended in a truncated 
+sequence, e.g. a part of a multi-byte character, aOutputConversionFlags 
+returns with the EOutputConversionFlagInputIsTruncated flag set. 
+@param aInputConversionFlags Specify 
+CCnvCharacterSetConverter::EInputConversionFlagAppend to append the text to 
+aUnicode. Specify EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable 
+to prevent the function from returning the error-code EErrorIllFormedInput 
+when the input descriptor consists of nothing but a truncated sequence. The 
+CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter 
+flag must not be set, otherwise a panic occurs. 
+@return The number of unconverted bytes left at the end of the input descriptor, 
+or a negative error value, as defined in TError. */
+EXPORT_C TInt CnvUtilities::ConvertToUnicodeFromHeterogeneousForeign(
+						CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
+						TDes16& aUnicode, 
+						const TDesC8& aForeign, 
+						TInt& aNumberOfUnconvertibleCharacters, 
+						TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter, 
+						const TArray<SMethod>& aArrayOfMethods, 
+						TUint& aOutputConversionFlags, 
+						TUint aInputConversionFlags)
+	{
+	__ASSERT_ALWAYS(~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagStopAtFirstUnconvertibleCharacter, Panic(EPanicBadInputConversionFlags3));
+	CheckArrayOfMethods(aArrayOfMethods);
+	aNumberOfUnconvertibleCharacters=0;
+	aIndexOfFirstByteOfFirstUnconvertibleCharacter=-1;
+	aOutputConversionFlags=0;
+	TUint internalInputConversionFlags=aInputConversionFlags;
+	if (~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAppend)
+		{
+		aUnicode.SetLength(0);
+		internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagAppend;
+		}
+	if (aForeign.Length()==0)
+		{
+		return 0;
+		}
+	if (aUnicode.MaxLength()==aUnicode.Length()) // relies on the fact that aUnicode's length has been set to zero if aInputConversionFlags does not have CCnvCharacterSetConverter::EInputConversionFlagAppend set
+		{
+		return aForeign.Length();
+		}
+	const TInt numberOfMethods=aArrayOfMethods.Count();
+	TPtrC8 remainderOfForeign(aForeign);
+	TInt numberOfForeignBytesConsumed=0;
+	FOREVER
+		{
+		TInt lengthOfRunToConvert=0;
+		const SMethod* method=NULL;
+		for (TInt i=0;;)
+			{
+			method=&aArrayOfMethods[i];
+			__ASSERT_DEBUG(method!=NULL, Panic(EPanicBadMethodPointer));
+			lengthOfRunToConvert=(*method->iNumberOfBytesAbleToConvert)(remainderOfForeign);
+			if (lengthOfRunToConvert<0)
+				{
+				return lengthOfRunToConvert; // this is an error-code
+				}
+			if (lengthOfRunToConvert>0)
+				{
+				break;
+				}
+			__ASSERT_DEBUG(i<numberOfMethods, Panic(EPanicLoopCounterOverRun2));
+			++i;
+			if (i>=numberOfMethods)
+				{
+				aOutputConversionFlags|=CCnvCharacterSetConverter::EOutputConversionFlagInputIsTruncated;
+				goto end;
+				}
+			}
+		TBuf8<KMaximumLengthOfIntermediateBuffer> intermediateBuffer;
+		const TInt maximumUsableLengthOfIntermediateBuffer=ReduceToNearestMultipleOf(KMaximumLengthOfIntermediateBuffer, method->iNumberOfBytesPerCharacter);
+		FOREVER
+			{
+			const TInt numberOfForeignBytesConsumedThisTime=Min(lengthOfRunToConvert, maximumUsableLengthOfIntermediateBuffer);
+			intermediateBuffer=remainderOfForeign.Left(numberOfForeignBytesConsumedThisTime);
+			__ASSERT_DEBUG((numberOfForeignBytesConsumedThisTime%method->iNumberOfBytesPerCharacter)==0, Panic(EPanicDescriptorNotWholeNumberOfCharacters2));
+			(*method->iConvertToIntermediateBufferInPlace)(intermediateBuffer);
+			__ASSERT_DEBUG((intermediateBuffer.Length()%method->iNumberOfCoreBytesPerCharacter)==0, Panic(EPanicDescriptorNotWholeNumberOfCharacters3));
+			__ASSERT_DEBUG((intermediateBuffer.Length()/method->iNumberOfCoreBytesPerCharacter)*method->iNumberOfBytesPerCharacter==numberOfForeignBytesConsumedThisTime, Panic(EPanicBadMethodData1));
+			TInt numberOfUnconvertibleCharacters;
+			TInt indexOfFirstByteOfFirstUnconvertibleCharacter;
+			const TInt returnValue=CCnvCharacterSetConverter::DoConvertToUnicode(*method->iConversionData, aDefaultEndiannessOfForeignCharacters, aUnicode, intermediateBuffer, numberOfUnconvertibleCharacters, indexOfFirstByteOfFirstUnconvertibleCharacter, aOutputConversionFlags, internalInputConversionFlags);
+			if (returnValue<0)
+				{
+				return returnValue; // this is an error-code
+				}
+			if (numberOfUnconvertibleCharacters>0)
+				{
+				if (aNumberOfUnconvertibleCharacters==0)
+					{
+					aIndexOfFirstByteOfFirstUnconvertibleCharacter=numberOfForeignBytesConsumed+indexOfFirstByteOfFirstUnconvertibleCharacter;
+					}
+				aNumberOfUnconvertibleCharacters+=numberOfUnconvertibleCharacters;
+				}
+			numberOfForeignBytesConsumed+=numberOfForeignBytesConsumedThisTime;
+			if (returnValue>0)
+				{
+				__ASSERT_DEBUG((returnValue%method->iNumberOfCoreBytesPerCharacter)==0, Panic(EPanicDescriptorNotWholeNumberOfCharacters4));
+				numberOfForeignBytesConsumed-=(returnValue/method->iNumberOfCoreBytesPerCharacter)*method->iNumberOfBytesPerCharacter;
+				goto end;
+				}
+			if (numberOfForeignBytesConsumed>0)
+				{
+				internalInputConversionFlags|=CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable;
+				}
+			remainderOfForeign.Set(aForeign.Mid(numberOfForeignBytesConsumed));
+			lengthOfRunToConvert-=numberOfForeignBytesConsumedThisTime;
+			__ASSERT_DEBUG(lengthOfRunToConvert>=0, Panic(EPanicBadLengthOfRunToConvert2));
+			if (lengthOfRunToConvert<=0)
+				{
+				break;
+				}
+			}
+		}
+end:
+	if ((numberOfForeignBytesConsumed==0) && (aOutputConversionFlags&CCnvCharacterSetConverter::EOutputConversionFlagInputIsTruncated) && (~aInputConversionFlags&CCnvCharacterSetConverter::EInputConversionFlagAllowTruncatedInputNotEvenPartlyConsumable))
+		{
+		return CCnvCharacterSetConverter::EErrorIllFormedInput;
+		}
+	return aForeign.Length()-numberOfForeignBytesConsumed;
+	}
+
+void CnvUtilities::CheckArrayOfCharacterSets(const TArray<SCharacterSet>& aArrayOfCharacterSets)
+	{
+	const TInt numberOfCharacterSets=aArrayOfCharacterSets.Count();
+	__ASSERT_ALWAYS(numberOfCharacterSets>0, Panic(EPanicBadNumberOfCharacterSets));
+	for (TInt i=0; i<numberOfCharacterSets; ++i)
+		{
+		const SCharacterSet& characterSet=aArrayOfCharacterSets[i];
+		__ASSERT_ALWAYS(characterSet.iConversionData!=NULL, Panic(EPanicBadConversionDataPointer1));
+		__ASSERT_ALWAYS(characterSet.iConvertFromIntermediateBufferInPlace!=NULL, Panic(EPanicBadFunctionPointer1));
+		__ASSERT_ALWAYS(characterSet.iEscapeSequence!=NULL, Panic(EPanicBadEscapeSequencePointer1));
+		}
+	}
+
+void CnvUtilities::CheckArrayOfStates(const TArray<SState>& aArrayOfStates)
+	{
+	const TInt numberOfStates=aArrayOfStates.Count();
+	__ASSERT_ALWAYS(numberOfStates>0, Panic(EPanicBadNumberOfStates));
+	for (TInt i=0; i<numberOfStates; ++i)
+		{
+		const SState& state=aArrayOfStates[i];
+		__ASSERT_ALWAYS(state.iEscapeSequence!=NULL, Panic(EPanicBadEscapeSequencePointer2));
+		__ASSERT_ALWAYS((*state.iEscapeSequence)[0]==KControlCharacterEscape, Panic(EPanicBadEscapeSequenceStart));
+		__ASSERT_ALWAYS(state.iConversionData!=NULL, Panic(EPanicBadConversionDataPointer2));
+		}
+	}
+
+void CnvUtilities::CheckArrayOfMethods(const TArray<SMethod>& aArrayOfMethods)
+	{
+	const TInt numberOfMethods=aArrayOfMethods.Count();
+	__ASSERT_ALWAYS(numberOfMethods>0, Panic(EPanicBadNumberOfMethods));
+	for (TInt i=0; i<numberOfMethods; ++i)
+		{
+		const SMethod& method=aArrayOfMethods[i];
+		__ASSERT_ALWAYS(method.iNumberOfBytesAbleToConvert!=NULL, Panic(EPanicBadFunctionPointer2));
+		__ASSERT_ALWAYS(method.iConvertToIntermediateBufferInPlace!=NULL, Panic(EPanicBadFunctionPointer3));
+		__ASSERT_ALWAYS(method.iConversionData!=NULL, Panic(EPanicBadConversionDataPointer3));
+		__ASSERT_ALWAYS(method.iNumberOfBytesPerCharacter>0, Panic(EPanicBadMethodData2));
+		__ASSERT_ALWAYS(method.iNumberOfCoreBytesPerCharacter>0, Panic(EPanicBadMethodData3));
+		__ASSERT_ALWAYS(method.iNumberOfCoreBytesPerCharacter<=method.iNumberOfBytesPerCharacter, Panic(EPanicBadMethodData4));
+		}
+	}
+
+TInt CnvUtilities::LengthOfUnicodeCharacter(const TDesC16& aUnicode, TInt aIndex)
+	{
+	const TUint unicodeCharacter=aUnicode[aIndex];
+	if ((unicodeCharacter>=0xd800) && (unicodeCharacter<=0xdbff)) // if the unicode character is the first half of a surrogate-pair...
+		{
+		__ASSERT_DEBUG(aIndex+1<aUnicode.Length(), Panic(EPanicBadSurrogatePair1));
+#if defined(_DEBUG)
+		const TUint secondHalfOfSurrogatePair=aUnicode[aIndex+1];
+#endif
+		__ASSERT_DEBUG((secondHalfOfSurrogatePair>=0xdc00) && (secondHalfOfSurrogatePair<=0xdfff), Panic(EPanicBadSurrogatePair2)); // this can be asserted as CCnvCharacterSetConverter::DoConvertFromUnicode should have returned an error value if this was a bad surrogate pair
+		return 2;
+		}
+	return 1;
+	}
+
+TBool CnvUtilities::NextHomogeneousForeignRun(const SCnvConversionData*& aConversionData, TInt& aNumberOfForeignBytesConsumed, TPtrC8& aHomogeneousRun, TPtrC8& aRemainderOfForeign, const TArray<SState>& aArrayOfStates, TUint& aOutputConversionFlags)
+	{
+	__ASSERT_DEBUG((aRemainderOfForeign.Length()==0) || (aRemainderOfForeign[0]==KControlCharacterEscape), Panic(EPanicBadRemainderOfForeign));
+	FOREVER
+		{
+		if (aRemainderOfForeign.Length()==0)
+			{
+			return EFalse;
+			}
+		const TInt numberOfStates=aArrayOfStates.Count();
+		TInt i;
+		for (i=0; i<numberOfStates; ++i)
+			{
+			const SState& state=aArrayOfStates[i];
+			if (MatchesEscapeSequence(aNumberOfForeignBytesConsumed, aHomogeneousRun, aRemainderOfForeign, *state.iEscapeSequence))
+				{
+				aConversionData=state.iConversionData;
+				goto foundState;
+				}
+			}
+		for (i=0; i<numberOfStates; ++i)
+			{
+			if (IsStartOf(aRemainderOfForeign, *aArrayOfStates[i].iEscapeSequence))
+				{
+				// aRemainderOfForeign ends with a truncated escape sequence, so ConvertToUnicode cannot convert any more
+				aOutputConversionFlags|=CCnvCharacterSetConverter::EOutputConversionFlagInputIsTruncated;
+				return EFalse;
+				}
+			}
+		// force ConvertToUnicode to return CCnvCharacterSetConverter::EErrorIllFormedInput
+		aConversionData=NULL;
+		return ETrue;
+foundState:
+		if (aHomogeneousRun.Length()>0)
+			{
+			return ETrue;
+			}
+		}
+	}
+
+TBool CnvUtilities::MatchesEscapeSequence(TInt& aNumberOfForeignBytesConsumed, TPtrC8& aHomogeneousRun, TPtrC8& aRemainderOfForeign, const TDesC8& aEscapeSequence)
+	{
+	const TInt lengthOfEscapeSequence=aEscapeSequence.Length();
+	if (IsStartOf(aEscapeSequence, aRemainderOfForeign))
+		{
+		aRemainderOfForeign.Set(aRemainderOfForeign.Mid(lengthOfEscapeSequence));
+		const TInt startOfNextEscapeSequence=aRemainderOfForeign.Locate(KControlCharacterEscape);
+		if (startOfNextEscapeSequence==KErrNotFound)
+			{
+			aHomogeneousRun.Set(aRemainderOfForeign);
+			aRemainderOfForeign.Set(NULL, 0);
+			}
+		else
+			{
+			aHomogeneousRun.Set(aRemainderOfForeign.Left(startOfNextEscapeSequence));
+			aRemainderOfForeign.Set(aRemainderOfForeign.Mid(startOfNextEscapeSequence));
+			}
+		aNumberOfForeignBytesConsumed+=lengthOfEscapeSequence;
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+TBool CnvUtilities::IsStartOf(const TDesC8& aStart, const TDesC8& aPotentiallyLongerDescriptor)
+	{
+	const TInt lengthOfStart=aStart.Length();
+	return (aPotentiallyLongerDescriptor.Length()>=lengthOfStart) && (aPotentiallyLongerDescriptor.Left(lengthOfStart)==aStart);
+	}
+