kernel/eka/common/des16.cpp
changeset 90 947f0dc9f7a8
parent 0 a41df078684a
child 153 1f2940c968a9
child 245 647ab20fee2e
--- a/kernel/eka/common/des16.cpp	Tue Feb 02 01:24:03 2010 +0200
+++ b/kernel/eka/common/des16.cpp	Fri Apr 16 16:24:37 2010 +0300
@@ -765,6 +765,13 @@
 #endif
 	}
 
+// Surrogate-aware version of lookup() above.
+// aChar can be over 0xFFFF.
+inline TUint lookup2(const TUint aChar, const TText *aConv)
+	{
+	return TUnicode(aChar).Fold((TInt)aConv, GetLocaleCharSet()->iCharDataSet);
+	}
+
 TInt DoMatch16(const TDesC16 &aLeftD,const TDesC16 &aRightD,TMatchType aType)
 	{
 	const TText* table=convTable(aType);
@@ -1368,6 +1375,558 @@
 
 #endif  // !defined(__DES16_MACHINE_CODED__)
 
+
+/**
+ * A helper function, which moves a pointer one Unicode character forward.
+ * 
+ * @aStart points to the head of the string to process.
+ * @aEnd   points to the end of the string. Note that aEnd points to the first
+ *         16-bit unit after the string. That is, the string length (i.e, count
+ *         of 16-bit units) is (aEnd-aStart).
+ * 
+ * On return,
+ *      if find valid character, then return KErrNone, with aNewStart pointing
+ *          to the 16-bit unit after the found character;
+ *      if meet corrupt surrogate before find a valid character, then return
+ *          KErrCorruptSurrogateFound, with aNewStart pointing to the corrupt surrogate;
+ *      if meet aEnd before find a valid character, then return KErrNotFound.
+ * 
+ * @return KErrNone if ok;
+ *         KErrNotFound if get to aEnd;
+ *         KErrCorruptSurrogateFound if meet corrupt surrogate.
+ */
+TInt ProceedOneCharacter(const TText16* aStart, const TText16* aEnd, TText16*& aNewStart, TUint& aCurrentChar)
+	{
+	if (!aStart || !aEnd || aStart>=aEnd)
+		return KErrNotFound;
+	if (!TChar::IsSurrogate(aStart[0]))
+		{
+		aCurrentChar = aStart[0];
+		aNewStart = const_cast<TText16*> (aStart + 1);
+		return KErrNone;
+		}
+	else if (TChar::IsHighSurrogate(aStart[0]))
+		{
+		if (aEnd < aStart + 2)
+			return KErrCorruptSurrogateFound;
+		if (!TChar::IsLowSurrogate(aStart[1]))
+			{
+			aNewStart = const_cast<TText16*> (aStart + 2);
+			return KErrCorruptSurrogateFound;
+			}
+		aCurrentChar = TChar::JoinSurrogate(aStart[0], aStart[1]);
+		aNewStart = const_cast<TText16*> (aStart + 2);
+		return KErrNone;
+		}
+	else
+		{
+		aNewStart = const_cast<TText16*> (aStart);
+		return KErrCorruptSurrogateFound;
+		}
+	}
+
+/**
+ * A helper function, which moves a pointer one or more Unicode characters forward.
+ * 
+ * This function starts from aStart, stops when one of below conditions matched:
+ *   1) 16-bit position >= (aEnd - aStart);
+ *   2) 16-bit position >= aMaxInt16Position;
+ *   3) character position >= aMaxCharacterPosition;
+ * 
+ * Specify a huge integer (say KMaskDesLength16) for aMaxInt16Position or 
+ * aMaxCharacterPosition to indicate unlimited 16-bit position or character 
+ * position.
+ * 
+ * When return, aOutInt16Position, aOutCharacterPosition and aLastChar will 
+ *              indicate the same one character, whose 
+ *              16-bit position <= aMaxInt16Position, and 
+ *              character position <= aMaxCharacterPosition.
+ * 
+ * @return KErrNone if no error found;
+ *         KErrNotFound if get to aEnd before find wanted position; or,
+ *                      if aMaxIntPosition<=0 or aMaxCharacterPosition<=0;
+ *         KErrCorruptSurrogateFound if meet corrupt surrogate.
+ */
+TInt ProceedMultiCharacters(const TText16* aStart, const TText16* aEnd,
+							const TInt aMaxInt16Position, const TInt aMaxCharacterPosition,
+							TInt& aOutInt16Position, TInt& aOutCharacterPosition, TUint& aLastChar)
+	{
+	TText16 *next;
+	TInt status = KErrNotFound;
+	aOutInt16Position = 0;
+	aOutCharacterPosition = 0;
+	while (aOutInt16Position <= aMaxInt16Position && aOutCharacterPosition <= aMaxCharacterPosition)
+		{
+		status = ::ProceedOneCharacter(aStart+aOutInt16Position, aEnd, next, aLastChar);
+		if (status == KErrNotFound || status == KErrCorruptSurrogateFound)
+			return status;
+		if (next - aStart > aMaxInt16Position || aOutInt16Position == aMaxInt16Position || aOutCharacterPosition == aMaxCharacterPosition)
+			{
+			return status;
+			}
+		aOutInt16Position = (next - aStart);
+		++aOutCharacterPosition;
+		}
+	return status;
+	}
+
+EXPORT_C TInt TDesC16::FindCorruptSurrogate() const
+/**
+Look for the first corrupt surrogate in the descriptor.
+
+@return The 16-bit position of the first corrupt surrogate. KErrNotFound, if 
+        not found.
+*/
+	{
+	// Do not use TUTF32Iterator, because it hides some characters, including corrupt surrogate.
+	TInt strLength = Length();
+
+	const TText16* start = Ptr();
+	const TText16* end = Ptr() + strLength;
+	TInt int16Pos;
+	TInt charPos;
+	TUint lastChar;
+	TInt status = ::ProceedMultiCharacters(start, end, KMaskDesLength16, KMaskDesLength16, int16Pos, charPos, lastChar);
+	if (status == KErrCorruptSurrogateFound)
+		return int16Pos;
+	return KErrNotFound;
+	}
+
+EXPORT_C TInt TDesC16::Locate2(TChar aChar) const
+/**
+The surrogate aware version of Locate().
+
+Searches for the first occurrence of a character within this descriptor's 
+data.
+
+The search starts at the beginning of the data, i.e. at the leftmost 
+position.
+
+@param aChar The Unicode character to be found. Can be inside or outside BMP.
+
+@return The offset of the character position from the beginning of the data.
+        KErrNotFound, if no matching character can be found.
+        KErrCorruptSurrogateFound, if meet corrupt surrogate in the searching.
+
+@see TDesC16::Locate()
+*/
+	{
+	TInt strLength = Length();
+	const TText16* start = Ptr();
+	const TText16* end = Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		if (status != KErrNone)
+			return status;
+		if (currentChar == aChar)
+			return int16Index;
+		int16Index = (next - start);
+		}
+	}
+
+LOCAL_C TInt DoLocateF16_2(const TDesC16& aDes, TUint aChar)
+// Surrogate-aware version of DoLocateF16().
+// Locate character aChar in the descriptor folded.
+	{
+	const TText* table = convTable(EMatchFolded);
+	TUint aChar32 = aChar;
+	aChar = lookup2(aChar32, table);
+	
+	// find aChar in aDes
+	TInt strLength = aDes.Length();
+	const TText16* start = aDes.Ptr();
+	const TText16* end = aDes.Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	while (status == KErrNone)
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+        if (status != KErrNone)
+            break;
+		if (lookup2(currentChar, table) == aChar)
+			return int16Index;
+		int16Index = (next - start);
+		}
+	return status;
+	}
+
+EXPORT_C TInt TDesC16::LocateF2(TChar aChar) const
+/**
+The surrogate aware version of LocateF().
+
+Searches for the first occurrence of a folded character within this
+descriptor's folded data.
+
+The search starts at the beginning of the data, i.e. at the leftmost 
+position.
+
+Note that folding is locale-independent behaviour. It is also important to 
+note that there can be no guarantee that folding is in any way culturally 
+appropriate, and should not be used for searching strings in natural language.
+
+@param aChar The Unicode character to be found. Can be inside or outside BMP.
+
+@return The offset of the character position from the beginning of the data.
+        KErrNotFound, if no matching character can be found.
+        KErrCorruptSurrogateFound, if meet corrupt surrogate in the searching.
+
+@see TDesC16::LocateF()
+*/
+	{
+	return DoLocateF16_2(*this, aChar);
+	}
+
+/**
+ * Proceed backward from aEnd toward aStart by one character.
+ * 
+ * @aStart points to the first 16-bit unit in a descriptor.
+ * @aEnd   points to the 16-bit unit after the last one. So, count of 16-bit 
+ *         units to process is (aEnd-aStart).
+ * 
+ * On return,
+ *      if valid character found, then return KErrNone, with aNewEnd pointing 
+ *          to the character found;
+ *      if meet corrupt surrogate before find a valid character, then return 
+ *          KErrCorruptSurrogateFound, with aNewStart point to the corrupt
+ *          surrogate;
+ *      if aStart met, then return KErrNotFound.
+ * 
+ * @return KErrNone if ok;
+ *         KErrNotFound if get to aStart;
+ *         KErrCorruptSurrogateFound if meet corrupt surrogate.
+ */
+TInt RecedeOneCharacter(const TText16* aStart, const TText16* aEnd, TText16*& aNewEnd, TUint& aCurrentChar)
+	{
+	if (!aStart || !aEnd || aStart>=aEnd)
+		return KErrNotFound;
+	if (!TChar::IsSurrogate(aEnd[-1]))
+		{
+		aCurrentChar = aEnd[-1];
+		aNewEnd = const_cast<TText16*> (aEnd - 1);
+		return KErrNone;
+		}
+	else if (TChar::IsLowSurrogate(aEnd[-1]))
+		{
+		if (aEnd < aStart + 2)
+			return KErrNotFound;
+		if (!TChar::IsHighSurrogate(aEnd[-2]))
+			{
+			aNewEnd = const_cast<TText16*> (aEnd - 2);
+			return KErrCorruptSurrogateFound;
+			}
+		aCurrentChar = TChar::JoinSurrogate(aEnd[-2], aEnd[-1]);
+		aNewEnd = const_cast<TText16*> (aEnd - 2);
+		return KErrNone;
+		}
+	else
+		{
+		aNewEnd = const_cast<TText16*> (aEnd);
+		return KErrCorruptSurrogateFound;
+		}
+	}
+
+EXPORT_C TInt TDesC16::LocateReverse2(TChar aChar) const
+/**
+The surrogate aware version of LocateReverse().
+
+Searches for the first occurrence of a character within this descriptor's 
+data, searching from the end of the data.
+
+The search starts at the rightmost position.
+
+@param aChar The Unicode character to be found. Can be inside or outside BMP.
+
+@return The offset of the character position from the beginning of the data.
+        KErrNotFound, if no matching character can be found.
+        KErrCorruptSurrogateFound, if meet corrupt surrogate in the searching.
+
+@see TDesC16::LocateReverse()
+*/
+	{
+	TInt strLength = Length();
+	const TText16* start = Ptr();
+	TText16* newEnd;
+	TUint currentChar;
+	TInt int16Index = strLength;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::RecedeOneCharacter(start, start+int16Index, newEnd, currentChar);
+		if (status != KErrNone)
+		    return status;
+		int16Index = (newEnd - start);
+		if (currentChar == aChar)
+			return int16Index;
+		}
+	}
+
+EXPORT_C TInt TDesC16::LocateReverseF2(TChar aChar) const
+/**
+The surrogate aware version of LocateReverseF().
+
+Searches for the first occurrence of a folded character within this descriptor's 
+folded data, searching from the end of the data.
+
+The search starts at the rightmost position.
+
+Note that folding is locale-independent behaviour. It is also important to 
+note that there can be no guarantee that folding is in any way culturally 
+appropriate, and should not be used for searching strings in natural language.
+
+@param aChar The Unicode character to be found. Can be inside or outside BMP.
+
+@return The offset of the character position from the beginning of the data.
+        KErrNotFound, if no matching character can be found.
+        KErrCorruptSurrogateFound, if meet corrupt surrogate in the searching.
+
+@see TDesC16::LocateReverseF()
+*/
+	{
+	TInt strLength = Length();
+	const TText16* start = Ptr();
+	const TText16* end = Ptr() + strLength;
+	TText16* newEnd;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::RecedeOneCharacter(start, end, newEnd, currentChar);
+        if (status != KErrNone)
+            return status;
+		TCharF c(currentChar);
+		if (c == aChar)
+			return int16Index;
+		int16Index = (newEnd - start);
+		}
+	}
+
+inline TUint conv2(TUint aChar, const TText *aConv, const TUnicodeDataSet* aCharDataSet)
+// Surrogate-aware version of conv().
+// If aConv is not NULL then convert the character.
+	{
+	if (aConv)
+		return TUnicode(aChar).Fold((TInt)aConv, aCharDataSet);
+	else
+		return aChar;
+	}
+
+// Surrogate-aware version of DoMatch16().
+// This helper function uses the same search algorithm as DoMatch16().
+TInt DoMatch16_2(const TDesC16 &aLeftD, const TDesC16 &aRightD, TMatchType aType)
+	{
+	const TText* table=convTable(aType);
+	const TUint16* const pRight=aRightD.Ptr();
+	const TUint16* pM=pRight-1;						// pre-increment addressing
+	const TUint16* const pP=pM+aRightD.Length();
+	const TUint16* const pLeft=aLeftD.Ptr()-1;		// pre-increment addressing
+	const TUint16* pB=pLeft;	
+	const TUint16* pB2=pLeft;						// always points to current char; pB2==pB or pB-1
+	const TUint16* const pE=pB+aLeftD.Length();
+
+	// Note: pM and pB always point to the int16 unit before the character to handle.
+	//       so, pM[0] and pB[0] may be a low surrogate.
+	//       but, pM[1] and pB[1] must be start of a character.
+	// Note: pB2 always points to current character being handled.
+	//       pB2 is used to generated return value.
+	//       if pB[0] is low surrogate, then pB2=pB-1;
+	//       if pB[0] is BMP, then pB2=pB.
+	//
+	// A 'diagram' shows the pointers:
+	//
+	// before search:
+	//     left:       ############################
+	//                ^                           ^
+	//             pLeft/pB/pB2                   pE
+	//
+	//     right:      ############################
+	//                ^^                          ^
+	//              pM  pRight                    pP
+	//
+	//
+	// after several iterations (C is the next character going to be checked):
+    //     left:       ###############C############
+    //                ^              ^            ^
+    //             pLeft             pB/pB2       pE
+    //
+    //     right:      ##########C#################
+    //                 ^        ^                 ^
+    //                 pRight   pM                pP
+	//
+
+	const TUnicodeDataSet* charDataSet = GetLocaleCharSet()->iCharDataSet;
+
+	// Match any pattern up to the first star
+	TUint c;
+	TInt status;
+	TText* newStart;
+	for (;;)
+		{
+		status = ::ProceedOneCharacter(pM+1, pP+1, newStart, c);
+		if (status == KErrCorruptSurrogateFound)
+		    return KErrCorruptSurrogateFound;
+		if (status == KErrNotFound)		// exhausted the pattern
+			return pB==pE ? 0 : KErrNotFound;
+		pM = newStart - 1;
+		c = conv2(c, table, charDataSet);
+		if (c==KMatchAny)
+			break;
+		if (pB==pE)			// no more input
+			return KErrNotFound;
+		TUint c2;
+		pB2 = pB + 1;
+		status = ::ProceedOneCharacter(pB+1, pE+1, newStart, c2);
+        if (status == KErrCorruptSurrogateFound)
+            return KErrCorruptSurrogateFound;
+		pB = newStart - 1;
+		if (c != conv2(c2, table, charDataSet) && c != KMatchOne)	// match failed
+			return KErrNotFound;
+		}
+	// reached a star
+	if (pM==pP)
+		return 0;
+	TInt r=pM==pRight ? -1 : 0;		// r = how many int16 has been matched in candidate (aLeftD)
+	for (;;)
+		{
+		status = ::ProceedOneCharacter(pM+1, pP+1, newStart, c);
+        if (status == KErrCorruptSurrogateFound)
+            return KErrCorruptSurrogateFound;
+		pM = newStart - 1;
+		c = conv2(c, table, charDataSet);
+		if (c==KMatchAny)
+			{
+star:		if (pM==pP)		// star at end of pattern, always matches
+				return Max(r,0);
+			if (r<-1)		// skipped some '?', matches at beginning
+				r=0;
+			continue;
+			}
+		if (pB==pE)			// no more input
+			return KErrNotFound;
+		if (c==KMatchOne)
+			{				// skip a character in the input
+			if (pM==pP)
+				return r+((r>=0) ? 0 : (pE-pLeft));
+			TUint dummyC;
+			pB2 = pB + 1;
+			status = ::ProceedOneCharacter(pB+1, pE+1, newStart, dummyC);
+	        if (status == KErrCorruptSurrogateFound)
+	            return KErrCorruptSurrogateFound;
+			pB = newStart - 1;
+			if (r < 0)
+				r -= (newStart - pB2);	// back r by 1 or 2, depending on dummyC is BMP or non-BMP.
+			continue;
+			}
+	// Matching a non-wild character
+		for (;;)
+			{
+			if (table)
+				{
+				TUint c2;
+				for (;;)
+					{
+					pB2 = pB + 1;
+					status = ::ProceedOneCharacter(pB+1, pE+1, newStart, c2);
+			        if (status == KErrCorruptSurrogateFound)
+			            return KErrCorruptSurrogateFound;
+					pB = newStart - 1;
+					if (lookup2(c2, table) == c)
+						break;
+					if (pB==pE)				// no more input
+						return KErrNotFound;
+					}
+				}
+			else
+				{
+				TUint c2;
+				for (;;)
+					{
+					pB2 = pB + 1;
+					status = ::ProceedOneCharacter(pB+1, pE+1, newStart, c2);
+			        if (status == KErrCorruptSurrogateFound)
+			            return KErrCorruptSurrogateFound;
+					pB = newStart - 1;
+					if (c2 == c)
+						break;
+					if (pB==pE)				// no more input
+						return KErrNotFound;
+					}
+				}
+			// Try to match up to the next star
+			const TUint16* pb=pB;
+			const TUint16* pm=pM;
+			for (;;)
+				{
+				if (pm<pP)
+					{
+					TUint cc;
+					status = ::ProceedOneCharacter(pm+1, pP+1, newStart, cc);
+			        if (status == KErrCorruptSurrogateFound)
+			            return KErrCorruptSurrogateFound;
+					pm = newStart - 1;
+					cc = conv2(cc, table, charDataSet);
+					if (cc==KMatchAny)
+						{	// sub-match successful, back to main loop
+						r+=(r>=0 ? 0 : pB2-pLeft);
+						pB=pb;
+						pM=pm;
+						goto star;
+						}
+					if (pb==pE)
+						return KErrNotFound;	// no more input
+					TUint cc2;
+					status = ::ProceedOneCharacter(pb+1, pE+1, newStart, cc2);
+			        if (status == KErrCorruptSurrogateFound)
+			            return KErrCorruptSurrogateFound;
+					pb = newStart - 1;
+					if (cc != conv2(cc2, table, charDataSet) && cc != KMatchOne)
+						break;	// sub-match failed, try next input character
+					}
+				else if (pb==pE)	// end of matching pattern
+					{
+					return r+(r>=0 ? 0 : pB2-pLeft);	// end of input, so have a match
+					}
+				else
+					break;		// try next input character
+				}
+			}
+		}
+	}
+
+EXPORT_C TInt TDesC16::Match2(const TDesC16 &aDes) const
+/**
+The surrogate aware version of Match().
+
+Searches this descriptor's data for a match with the match pattern supplied 
+in the specified descriptor.
+
+The match pattern can contain the wildcard characters "*" and "?", where "*" 
+matches zero or more consecutive occurrences of any character and "?" matches 
+a single occurrence of any character.
+
+Note that there is no 'escape character', which means that it is not possible
+to match either the "*" character itself or the "?" character itself using
+this function.
+
+@param aDes A 16-bit non-modifable descriptor containing the match pattern.
+
+@return If a match is found, the offset within this descriptor's data where 
+        the match first occurs. KErrNotFound, if there is no match.
+        KErrCorruptSurrogateFound, if meet corrupt surrogate in the searching.
+
+@see TDesC16::Match()
+*/
+	{
+	return DoMatch16_2(*this, aDes, EMatchNormal);
+	}
+
 #if !defined( __DES16_MACHINE_CODED__) | defined(__EABI_CTORS__)
 EXPORT_C TBufCBase16::TBufCBase16()
 //
@@ -3383,6 +3942,930 @@
     AppendFormatList(aFmt,list);
     }
 
+EXPORT_C void TDes16::Append2(TChar aChar)
+/**
+The surrogate aware version of Append().
+
+Appends data onto the end of this descriptor's data.
+
+The length of this descriptor is incremented to reflect the new content. The
+length will be increased by 1 if aChar is inside BMP or 2 if aChar is outside
+BMP.
+
+@param aChar A single character to be appended. Can be inside or outside BMP.
+
+@panic USER 11  if the resulting new length of this descriptor is greater than
+                its maximum length.
+
+@panic USER 217 if corrupt surrogate found in aChar. This functions will not
+                validate already existing surrogate in the descriptor.
+
+@see TDes16::Append()
+*/
+	{
+	__ASSERT_ALWAYS(TChar::IsSupplementary(aChar) || !TChar::IsSurrogate((TText16)aChar), Panic(ECorruptSurrogateFound));
+
+	TInt len = Length();
+	TUint16 *pB = WPtr() + len;
+	if (TChar::IsSupplementary(aChar))
+		{
+		SetLength(len + 2);
+		*pB++ = TChar::GetHighSurrogate(aChar);
+		*pB = TChar::GetLowSurrogate(aChar);
+		}
+	else
+		{
+		SetLength(len + 1);
+		*pB = (TText16)aChar;
+		}
+	}
+
+EXPORT_C void TDes16::Fill2(TChar aChar)
+/**
+The surrogate aware version of Fill().
+
+Fills the descriptor's data area with the specified character, replacing any 
+existing data.
+
+The descriptor is filled from the beginning up to its current length. The 
+descriptor's length does not change. It is not filled to its maximum length.
+If aChar is supplementary character, and available space to fill is odd in
+16-bit unit, then the last 16-bit unit will be left unchanged, and the length
+will keep unchanged.
+
+@param aChar The fill character. Can be inside or outside BMP.
+
+@see TDes16::Fill()
+*/
+	{
+	TUint16 *pB = WPtr();
+	TUint16 *pE = pB + Length();
+	if (!TChar::IsSupplementary(aChar))
+		{
+		while (pB < pE)
+			*pB++ = (TUint16)aChar;
+		}
+	else
+		{
+		while (pB < pE - 1)
+			{
+			*pB++ = TChar::GetHighSurrogate(aChar);
+			*pB++ = TChar::GetLowSurrogate(aChar);
+			}
+		}
+	}
+
+EXPORT_C void TDes16::Fill2(TChar aChar, TInt aLength)
+/**
+The surrogate aware version of Fill().
+
+Fills the descriptor's data area with the specified character, replacing any 
+existing data.
+
+The descriptor is filled with the specified number of characters,
+and its length is changed to reflect this.
+
+If aChar is supplementary character, and available space to fill is odd in
+16-bit unit, then the last 16-bit unit will be left unchanged.
+
+@param aChar   The fill character. Can be inside or outside BMP.
+@param aLength The new length of the descriptor.
+
+@panic USER 11  if aLength is negative or is greater than the maximum length
+                of this descriptor.
+
+@panic USER 217 if corrupt surrogate found in aChar. These functions will not 
+                validate already existing surrogate in the descriptor.
+
+@see TDes16::Fill()
+*/
+	{
+	__ASSERT_ALWAYS(TChar::IsSupplementary(aChar) || !TChar::IsSurrogate((TText16)aChar), Panic(ECorruptSurrogateFound));
+
+	SetLength(aLength);
+	Fill2(aChar);
+	}
+
+EXPORT_C void TDes16::AppendFill2(TChar aChar, TInt aLength)
+/**
+The surrogate aware version of AppendFill().
+
+Appends and fills this descriptor with the specified character.
+
+The descriptor is appended with the specified number of characters, and its
+length is changed to reflect this.
+
+If aChar is supplementary character, and available space to fill is odd in 
+16-bit unit, then the last 16-bit unit will be left unchanged.
+
+@param aChar   The fill character. Can be inside or outside BMP.
+@param aLength The length of additional space to append into.
+
+@panic USER 11  if aLength is negative, or the resulting length of this
+                descriptor is greater than its maximum length.
+
+@panic USER 217 if corrupt surrogate found in aChar. These functions will not 
+                validate already existing surrogate in the descriptor.
+
+@see TDes16::AppendFill()
+*/
+	{
+	__ASSERT_ALWAYS(TChar::IsSupplementary(aChar) || !TChar::IsSurrogate((TText16)aChar), Panic(ECorruptSurrogateFound));
+
+	TInt len=Length();
+	TUint16 *pB=WPtr()+len;
+	SetLength(len+aLength);
+	TUint16 *pE=pB+aLength;
+	if (!TChar::IsSupplementary(aChar))
+		{
+		while (pB < pE)
+			*pB++ = (TUint16)aChar;
+		}
+	else
+		{
+		while (pB < pE - 1)
+			{
+			*pB++ = TChar::GetHighSurrogate(aChar);
+			*pB++ = TChar::GetLowSurrogate(aChar);
+			}
+		}
+	}
+
+EXPORT_C void TDes16::Justify2(const TDesC16 &aDes, TInt aWidth, TAlign anAlignment, TChar aFill)
+/**
+The surrogate aware version of Justify().
+
+Copies data into this descriptor and justifies it, replacing any existing data.
+
+The length of this descriptor is set to reflect the new data.
+
+The target area is considered to be an area of specified width positioned at
+the beginning of this descriptor's data area. Source data is copied into, and
+aligned within this target area according to the specified alignment
+instruction.
+
+If the length of the target area is larger than the length of the source, then
+spare space within the target area is padded with the fill character.
+
+@param aDes        A 16-bit non-modifiable descriptor containing the source data.
+                   The length of the data to be copied is the smaller of:
+                   the length of the source descriptor, and 
+                   the width of the target area (only if this is not the
+                   explicit negative value KDefaultJustifyWidth).
+
+@param aWidth      The width of the target area. If this has the specific
+                   negative value KDefaultJustifyWidth, then the width is
+                   re-set to the length of the data source.
+
+@param anAlignment The alignment of the data within the target area
+
+@param aFill       The fill character used to pad the target area. Can be
+                   inside or outside BMP.
+
+@panic USER 11  if the resulting length of this descriptor is greater than
+                its maximum length or aWidth has a negative value other 
+                than KDefaultJustifyWidth.
+
+@panic USER 217 if corrupt surrogate found in the parameters or in the 
+                descriptor.
+
+@see TDes16::Justify()
+*/
+	{
+    Zero();
+    AppendJustify2(aDes.Ptr(),aDes.Length(),aWidth,anAlignment,aFill);
+	}
+
+EXPORT_C void TDes16::AppendJustify2(const TDesC16 &aDes, TInt aWidth, TAlign anAlignment, TChar aFill)
+/**
+The surrogate aware version of AppendJustify.
+
+Appends data onto the end of this descriptor's data and justifies it.
+    
+The source of the appended data is an existing descriptor.
+    
+The target area is considered to be an area of specified width, immediately 
+following this descriptor's existing data. Source data is copied into, and 
+aligned within this target area according to the specified alignment instruction.
+    
+If the length of the target area is larger than the length of the source, 
+then spare space within the target area is padded with the fill character.
+        
+@param aDes        A 16-bit non-modifiable descriptor containing the source
+                   data. The length of the data to be copied is the smaller of:
+                   the length of the source descriptor, and
+                   the width of the target area (only if this is not the
+                   explicit negative value KDefaultJustifyWidth). 
+    
+@param aWidth      The width of the target area. If this has the specific
+                   negative value KDefaultJustifyWidth, then the width is
+                   re-set to the length of the data source.
+    
+@param anAlignment The alignment of the data within the target area. 
+    
+@param aFill       The fill character used to pad the target area. Can be
+                   inside or outside BMP.
+
+@panic USER 11  if the resulting length of this descriptor is greater than
+                its maximum length or aWidth has a negative value other 
+                than KDefaultJustifyWidth.
+
+@panic USER 217 if corrupt surrogate found in the parameters or in the 
+                descriptor.
+
+@see TDes16::AppendJustify()
+*/
+	{
+    AppendJustify2(aDes.Ptr(),aDes.Length(),aWidth,anAlignment,aFill);
+	}
+
+EXPORT_C void TDes16::AppendJustify2(const TDesC16 &aDes, TInt aLength, TInt aWidth, TAlign anAlignment, TChar aFill)
+/**
+The surrogate aware version of AppendJustify.
+
+Appends data onto the end of this descriptor's data and justifies it.
+    
+The source of the appended data is an existing descriptor.
+    
+The target area is considered to be an area of specified width, immediately 
+following this descriptor's existing data. Source data is copied into, and 
+aligned within this target area according to the specified alignment instruction.
+    
+If the length of the target area is larger than the length of the source, 
+then spare space within the target area is padded with the fill character.
+    
+@param aDes        An 8-bit non-modifiable descriptor containing the source data. 
+
+@param aLength     The length of data to be copied from the source descriptor. 
+                   If this is greater than the width of the target area, then
+                   the length of data copied is limited to the width.
+                   The length of data to be copied must not be  greater than
+                   the length of the source descriptor. Note that this
+                   condition is not automatically tested. 
+                   
+@param aWidth      The width of the target area. If this has the specific negative 
+                   value KDefaultJustifyWidth, then the width is
+                   re-set to the length of the data source.
+
+@param anAlignment The alignment of the data within the target area. 
+
+@param aFill       The fill character used to pad the target area. Can be
+                   inside or outside BMP.
+
+@panic USER 11  if the resulting length of this descriptor is greater than
+                its maximum length or aWidth has a negative value other 
+                than KDefaultJustifyWidth.
+
+@panic USER 217 if corrupt surrogate found in the parameters or in the 
+                descriptor.
+
+@see TDes16::AppendJustify()
+*/
+	{
+    AppendJustify2(aDes.Ptr(),aLength,aWidth,anAlignment,aFill);
+	}
+
+EXPORT_C void TDes16::AppendJustify2(const TUint16 *aString, TInt aWidth, TAlign anAlignment, TChar aFill)
+/**
+The surrogate aware version of AppendJustify.
+
+Appends a zero terminated string onto the end of this descriptor's data and 
+justifies it.
+
+The zero terminator is not copied.
+
+The target area is considered to be an area of specified width, immediately 
+following this descriptor's existing data. Source data is copied into, and 
+aligned within, this target area according to the specified alignment instruction.
+
+If the length of the target area is larger than the length of the source, 
+then spare space within the target area is padded with the fill character.
+
+@param aString     A pointer to a zero terminated string The length of the data 
+                   to be copied is the smaller of: the length of the string (excluding the zero 
+                   terminator), the width of the target area (only if this is not the explicit 
+                   negative value KDefaultJustifyWidth). 
+                    
+@param aWidth      The width of the target area. If this has the specific negative 
+                   value KDefaultJustifyWidth, then the width is re-set to the length of the 
+                   zero terminated string (excluding the zero terminator).
+                    
+@param anAlignment The alignment of the data within the target area. 
+
+@param aFill       The fill character used to pad the target area. Can be
+                   inside or outside BMP.
+
+@panic USER 11  if the resulting length of this descriptor is greater than
+                its maximum length or aWidth has a negative value other 
+                than KDefaultJustifyWidth.
+
+@panic USER 217 if corrupt surrogate found in the parameters or in the 
+                descriptor.
+
+@see TDes16::AppendJustify()
+*/
+	{
+ 	__CHECK_ALIGNMENT(aString,ETDes16AppendJustify1);
+	AppendJustify2(aString,STRING_LENGTH_16(aString),aWidth,anAlignment,aFill);
+	}
+
+EXPORT_C void TDes16::AppendJustify2(const TUint16 *aString, TInt aLength, TInt aWidth, TAlign anAlignment, TChar aFill)
+/**
+The surrogate aware version of AppendJustify.
+
+Appends data onto the end of this descriptor's data and justifies it.
+
+The source of the appended data is a memory location.
+
+The target area is considered to be an area of specified width, immediately 
+following this descriptor's existing data. Source data is copied into, and 
+aligned within, this target area according to the specified alignment instruction.
+
+If the length of the target area is larger than the length of the source, 
+then spare space within the target area is padded with the fill character.
+
+@param aString     A pointer to a source memory location. 
+
+@param aLength     The length of data to be copied. If this is greater than the 
+                   width of the target area, then the length of data copied is
+                   limited to the width.
+               
+@param aWidth      The width of the target area. If this has the specific negative 
+                   value KDefaultJustifyWidth, then the width is
+                   re-set to the length of the data source. 
+               
+@param anAlignment The alignment of the data within the target area. 
+
+@param aFill       The fill character used to pad the target area. Can be
+                   inside or outside BMP.
+
+@panic USER 11  if the resulting length of this descriptor is greater than
+                its maximum length or aWidth has a negative value other 
+                than KDefaultJustifyWidth.
+
+@panic USER 17  if aLength is negative.
+  
+@panic USER 217 if corrupt surrogate found in the parameters or in the 
+                descriptor.
+
+@see TDes16::AppendJustify()
+*/
+	{
+	__ASSERT_ALWAYS(aLength>=0,Panic(ETDes16LengthNegative));
+	__CHECK_ALIGNMENT(aString,ETDes16AppendJustify2);
+	if (aWidth==KDefaultJustifyWidth)
+		aWidth=aLength;
+	if (aLength>aWidth)
+		aLength=aWidth;
+	TInt offset=Length();
+	AppendFill2(aFill,aWidth);
+	TInt r=aWidth-aLength;
+	if (anAlignment==ECenter)
+		r>>=1;
+	else if (anAlignment==ELeft)
+		r=0;
+	memCopy(WPtr()+offset+r,aString,aLength);
+	}
+
+EXPORT_C void TDes16::Fold2()
+/**
+The surrogate aware version of Fold().
+
+Performs folding on the content of this descriptor.
+
+Note that folding is locale-independent behaviour. It is also important to 
+note that there can be no guarantee that folding is in any way culturally 
+appropriate, and should not be used when dealing with strings in natural
+language.
+
+@panic USER 217 if corrupt surrogate found in the descriptor.
+
+@see TDes16::Fold()
+*/
+	{
+	TInt strLength = Length();
+	TText16* start = WPtr();
+	const TText16* end = Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		TCharF c(currentChar);
+		// at present, c and currentChar always in the same plane
+		if (TChar::IsSupplementary(c))
+			{
+			start[int16Index] = TChar::GetHighSurrogate(c);
+			start[int16Index+1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			start[int16Index] = (TText16)c;
+			}
+		int16Index = (next - start);
+		}
+	}
+
+EXPORT_C void TDes16::Collate2()
+/**
+The surrogate aware version of Collate().
+
+Performs collation on the content of this descriptor.
+
+@panic USER 217 if corrupt surrogate found in the descriptor.
+
+@see TDes16::Collate()
+*/
+	{
+	TInt strLength = Length();
+	TText16* start = WPtr();
+	const TText16* end = Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		TChar c = User::Collate(currentChar);
+		// at present, c and currentChar always in the same plane
+		if (TChar::IsSupplementary(c))
+			{
+			start[int16Index] = TChar::GetHighSurrogate(c);
+			start[int16Index+1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			start[int16Index] = (TText16)c;
+			}
+		int16Index = (next - start);
+		}
+	}
+
+EXPORT_C void TDes16::LowerCase2()
+/**
+The surrogate aware version of LowerCase().
+
+Converts the content of this descriptor to lower case.
+
+Conversion is implemented as appropriate to the current locale.
+
+@panic USER 217 if corrupt surrogate found in the descriptor.
+
+@see TDes16::LowerCase()
+*/
+	{
+	TInt strLength = Length();
+	TText16* start = WPtr();
+	const TText16* end = Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		TCharLC c(currentChar);
+		// at present, c and currentChar always in the same plane
+		if (TChar::IsSupplementary(c))
+			{
+			start[int16Index] = TChar::GetHighSurrogate(c);
+			start[int16Index+1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			start[int16Index] = (TText16)c;
+			}
+		int16Index = (next - start);
+		}
+	}
+
+EXPORT_C void TDes16::UpperCase2()
+/**
+The surrogate aware version of UpperCase().
+
+Converts the content of this descriptor to upper case.
+
+Conversion is implemented as appropriate to the current locale.
+
+@panic USER 217 if corrupt surrogate found in the descriptor.
+
+@see TDes16::UpperCase()
+*/
+	{
+	TInt strLength = Length();
+	TText16* start = WPtr();
+	const TText16* end = Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		TCharUC c(currentChar);
+		// at present, c and currentChar always in the same plane
+		if (TChar::IsSupplementary(c))
+			{
+			start[int16Index] = TChar::GetHighSurrogate(c);
+			start[int16Index+1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			start[int16Index] = (TText16)c;
+			}
+		int16Index = (next - start);
+		}
+	}
+
+EXPORT_C void TDes16::Capitalize2()
+/**
+The surrogate aware version of Capitalize().
+
+Capitalises the content of this descriptor.
+
+Capitalisation is implemented as appropriate to the current locale.
+
+@panic USER 217 if corrupt surrogate found in the descriptor.
+
+@see TDes16::Capitalize()
+*/
+	{
+	TInt strLength = Length();
+	TText16* start = WPtr();
+	const TText16* end = Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	
+	// the first character: title case
+	status = ::ProceedOneCharacter(start, end, next, currentChar);
+	__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+	TChar c = User::TitleCase(currentChar);
+	// at present, c and currentChar always in the same plane
+	if (TChar::IsSupplementary(c))
+		{
+		start[0] = TChar::GetHighSurrogate(c);
+		start[1] = TChar::GetLowSurrogate(c);
+		}
+	else
+		{
+		start[0] = (TText16)c;
+		}
+	int16Index = (next - start);
+	
+	// following characters: lower case
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		TChar c = User::LowerCase(currentChar);
+		// at present, c and currentChar always in the same plane
+		if (TChar::IsSupplementary(c))
+			{
+			start[int16Index] = TChar::GetHighSurrogate(c);
+			start[int16Index+1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			start[int16Index] = (TText16)c;
+			}
+		int16Index = (next - start);
+		}
+	}
+
+EXPORT_C void TDes16::CopyF2(const TDesC16 &aDes)
+/**
+The surrogate aware version of CopyF().
+
+Copies and folds data from the specified descriptor into this descriptor replacing 
+any existing data.
+
+The length of this descriptor is set to reflect the new 
+data.
+
+Note that folding is locale-independent behaviour. It is also important to 
+note that there can be no guarantee that folding is in any way culturally 
+appropriate, and should not be used when dealing with strings in natural
+language.
+
+@param aDes A 16-bit non-modifiable descriptor.
+
+@panic USER 11  if the length of aDes is greater than the maximum length of
+                this target descriptor.
+
+@panic USER 217 if corrupt surrogate found in aDes or in the descriptor.
+
+@see TDes16::CopyF()
+*/
+	{
+	TText16* pT = WPtr();
+	TInt len = 0;
+	const TInt maxLen = MaxLength();
+	
+	// iterate through aDes
+	TInt strLength = aDes.Length();
+	const TText16* start = aDes.Ptr();
+	const TText16* end = aDes.Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		int16Index = (next - start);
+		TCharF c(currentChar);
+		if (TChar::IsSupplementary(c))
+			{
+			len += 2;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-2] = TChar::GetHighSurrogate(c);
+			pT[len-1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			++len;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-1] = (TText16)c;
+			}
+		}
+	SetLength(len);
+	}
+
+EXPORT_C void TDes16::CopyC2(const TDesC16 &aDes)
+/**
+The surrogate aware version of CopyC().
+
+Copies and collates data from the specified descriptor
+into this descriptor replacing any existing data.
+
+The length of this descriptor is set to reflect the new data.
+
+@param aDes A 16-bit non-modifiable descriptor.
+
+@panic USER 11  if the length of aDes is greater than the maximum length of
+                this target descriptor.
+
+@panic USER 217 if corrupt surrogate found in aDes or in the descriptor.
+
+@see TDes16::CopyC()
+*/
+	{
+	TText16* pT = WPtr();
+	TInt len = 0;
+	const TInt maxLen = MaxLength();
+	
+	// iterate through aDes
+	TInt strLength = aDes.Length();
+	const TText16* start = aDes.Ptr();
+	const TText16* end = aDes.Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		int16Index = (next - start);
+		TChar c = User::Collate(currentChar);
+		if (TChar::IsSupplementary(c))
+			{
+			len += 2;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-2] = TChar::GetHighSurrogate(c);
+			pT[len-1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			++len;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-1] = (TText16)c;
+			}
+		}
+	SetLength(len);
+	}
+
+EXPORT_C void TDes16::CopyLC2(const TDesC16 &aDes)
+/**
+The surrogate aware version of CopyLC().
+
+Copies text from the specified descriptor and converts it to lower case before 
+putting it into this descriptor, replacing any existing data.
+
+The length of this descriptor is set to reflect the new data.
+
+Conversion to lower case is implemented as appropriate to the current locale.
+
+@param aDes A 16-bit non modifiable descriptor.
+
+@panic USER 11  if the length of aDes is greater than the maximum length of
+                this target descriptor.
+
+@panic USER 217 if corrupt surrogate found in aDes or in the descriptor.
+
+@see TDes16::CopyLC()
+*/
+	{
+	TText16* pT = WPtr();
+	TInt len = 0;
+	const TInt maxLen = MaxLength();
+	
+	// iterate through aDes
+	TInt strLength = aDes.Length();
+	const TText16* start = aDes.Ptr();
+	const TText16* end = aDes.Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		int16Index = (next - start);
+		TCharLC c(currentChar);
+		if (TChar::IsSupplementary(c))
+			{
+			len += 2;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-2] = TChar::GetHighSurrogate(c);
+			pT[len-1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			++len;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-1] = (TText16)c;
+			}
+		}
+	SetLength(len);
+	}
+
+EXPORT_C void TDes16::CopyUC2(const TDesC16 &aDes)
+/**
+The surrogate aware version of CopyUC().
+
+Copies text from the specified descriptor and converts it to upper case before 
+putting it into this descriptor, replacing any existing data.
+
+The length of this descriptor is set to reflect the new data.
+
+Conversion to upper case is implemented as appropriate to the current locale.
+
+@param aDes A 16-bit non modifiable descriptor.
+
+@panic USER 11  if the length of aDes is greater than the maximum length of
+                this target descriptor.
+
+@panic USER 217 if corrupt surrogate found in aDes or in the descriptor.
+
+@see TDes16::CopyUC()
+*/
+	{
+	TText16* pT = WPtr();
+	TInt len = 0;
+	const TInt maxLen = MaxLength();
+	
+	// iterate through aDes
+	TInt strLength = aDes.Length();
+	const TText16* start = aDes.Ptr();
+	const TText16* end = aDes.Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		int16Index = (next - start);
+		TCharUC c(currentChar);
+		if (TChar::IsSupplementary(c))
+			{
+			len += 2;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-2] = TChar::GetHighSurrogate(c);
+			pT[len-1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			++len;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-1] = (TText16)c;
+			}
+		}
+	SetLength(len);
+	}
+
+EXPORT_C void TDes16::CopyCP2(const TDesC16 &aDes)
+/**
+The surrogate aware version of CopyCP().
+
+Copies text from the specified descriptor and capitalises it before putting 
+it into this descriptor, replacing any existing data.
+
+The length of this descriptor is set to reflect the new data.
+
+Capitalisation is implemented as appropriate to the current locale.
+
+@param aDes A 16-bit non-modifiable descriptor.
+
+@panic USER 11  if the length of aDes is greater than the maximum length of
+                this target descriptor.
+
+@panic USER 217 if corrupt surrogate found in aDes or in the descriptor.
+
+@see TDes16::CopyCP()
+*/
+	{
+	TText16* pT = WPtr();
+	TInt len = 0;
+	const TInt maxLen = MaxLength();
+	
+	// iterate through aDes
+	TInt strLength = aDes.Length();
+	const TText16* start = aDes.Ptr();
+	const TText16* end = aDes.Ptr() + strLength;
+	TText16* next;
+	TUint currentChar;
+	TInt int16Index = 0;
+	TInt status = KErrNone;
+	
+	// first character: title case
+	status = ::ProceedOneCharacter(start, end, next, currentChar);
+	__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+	int16Index = (next - start);
+	TChar c(currentChar);
+	c.TitleCase();
+	if (TChar::IsSupplementary(c))
+		{
+		len += 2;
+		__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+		pT[len-2] = TChar::GetHighSurrogate(c);
+		pT[len-1] = TChar::GetLowSurrogate(c);
+		}
+	else
+		{
+		++len;
+		__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+		pT[len-1] = (TText16)c;
+		}
+	
+	// following characters: lower case
+	FOREVER
+		{
+		status = ::ProceedOneCharacter(start+int16Index, end, next, currentChar);
+		__ASSERT_ALWAYS(status != KErrCorruptSurrogateFound, Panic(ECorruptSurrogateFound));
+		if (status == KErrNotFound)
+			break;
+		int16Index = (next - start);
+		TCharLC c(currentChar);
+		if (TChar::IsSupplementary(c))
+			{
+			len += 2;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-2] = TChar::GetHighSurrogate(c);
+			pT[len-1] = TChar::GetLowSurrogate(c);
+			}
+		else
+			{
+			++len;
+			__ASSERT_ALWAYS(len<=maxLen, Panic(ETDes16Overflow));
+			pT[len-1] = (TText16)c;
+			}
+		}
+	SetLength(len);
+	}
+
+
 #if !defined(__DES16_MACHINE_CODED__) | defined(__EABI_CTORS__)
 EXPORT_C TPtrC16::TPtrC16()
 	: TDesC16(EPtrC,0),iPtr(0)