--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/httpfilters/cookie/ManagerSrc/CookieIPC.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,704 @@
+/*
+* Copyright (c) 2002 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: Implementation of class TCookiePacker
+*
+*
+*/
+
+
+// INCLUDE FILES
+ // User includes
+#include "cookie.h"
+#include "cookieipc.h"
+#include "CookieLogger.h"
+
+#ifdef __TEST_COOKIE_LOG__
+const TInt KCookiePackerLogLevel = 4;
+#endif
+
+// Maximum cookie size (defined in RFC2965)
+const TInt KMaxCookieBufferSize = 0x1000; // 4 kilobytes
+
+
+// ---------------------------------------------------------
+// TCookiePacker::TCookiePacker
+// ---------------------------------------------------------
+//
+TCookiePacker::TCookiePacker( RStringPool aStringPool )
+: iStringPool( aStringPool )
+ {
+ }
+
+
+// ---------------------------------------------------------
+// TCookiePacker::AddDateL
+// ---------------------------------------------------------
+//
+TInt TCookiePacker::AddDateL( const CCookie& aCookie,
+ TDes8& aBuffer,
+ TBool aNoDefaulted ) const
+ {
+ CLOG( ( EClient, KCookiePackerLogLevel, _L("-> TCookiePacker::AddDate") ) );
+
+ THTTPHdrVal attributeVal;
+ TInt error = KErrNone;
+
+ TBool defaulted( EFalse );
+ TInt found = aCookie.Attribute( CCookie::EDate, attributeVal, defaulted );
+ // Date attribute must present in the RFC cookie
+ if ( found == KErrNone )
+ {
+ if (aNoDefaulted && defaulted )
+ {// pass a null text, that is, a length of 0
+ AppendAttributeLength( 0, aBuffer );
+ }
+ else
+ {
+ TDateTime attrTime = attributeVal.DateTime();
+ TTime cookieDate( attrTime );
+
+ // This FormatString must be shorter than sizeof(TDateTime)!
+ // As the cookie's date attribute always costs sizeof(TDateTime) byte
+ // in the memory (when we calculate its size in GetCookieSize),
+ // we have to allocate sizeof(TDateTime) byte in the client-server
+ // communication buffer too.
+ _LIT(KDateFormatString, "%F%Y%M%D:%H%T%S");
+ // convert DateTime to string (16 bit)
+ TInt size = sizeof( TDateTime );
+ HBufC *buf = HBufC::NewLC( size );
+ TPtr bufDes( buf->Des() );
+ bufDes.Fill( ' ', size );
+ cookieDate.FormatL( bufDes, KDateFormatString );
+ bufDes.SetLength( size );
+ // convert to 8 bit
+ HBufC8 *buf8 = HBufC8::NewLC( size );
+ TPtr8 buf8Des( buf8->Des() );
+ buf8Des.Copy( bufDes );
+
+ AppendAttributeLength( buf8Des.Length(), aBuffer );
+ aBuffer.Append( buf8Des );
+
+ CleanupStack::PopAndDestroy(); // buf8
+ CleanupStack::PopAndDestroy(); // buf
+ }
+ }
+ else // Netscape cookie?
+ { // pass a null text, that is, a length of 0
+ AppendAttributeLength( 0, aBuffer );
+ }
+
+ // always append 'found' to the end...
+ // if found == 0 -> HAS IT, 1
+ // otherwise, 0
+ AppendAttributeLength( found ? 0 : 1, aBuffer);
+
+ // always append 'defaulted' to the end...
+ AppendAttributeLength( defaulted, aBuffer);
+
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L("<- TCookiePacker::AddDate, errcode %d"), error ) );
+ return error;
+ }
+
+// ---------------------------------------------------------
+// TCookiePacker::AddStringF
+// ---------------------------------------------------------
+//
+TInt TCookiePacker::AddStringF( const CCookie::TCookieAttributeName aAttrib,
+ const CCookie& aCookie,
+ TDes8& aBuffer,
+ TBool aNoDefaulted ) const
+ {
+ CLOG( ( EClient, KCookiePackerLogLevel, _L( "-> TCookiePacker::AddStringF" ) ) );
+
+ THTTPHdrVal attributeVal;
+ TInt error = KErrNone;
+
+ TBool defaulted( EFalse );
+ TInt found = aCookie.Attribute( aAttrib, attributeVal, defaulted );
+ if ( found == KErrNone )
+ {
+ if ( aNoDefaulted && defaulted )
+ {// pass a null text, that is, a length of 0
+ AppendAttributeLength( 0, aBuffer );
+ }
+ else
+ {
+ HBufC8* txt( NULL );
+ if( attributeVal.Type() == THTTPHdrVal::KStrFVal )
+ txt = attributeVal.StrF().DesC().Alloc();
+ else if ( attributeVal.Type() == THTTPHdrVal::KStrVal )
+ txt = attributeVal.Str().DesC().Alloc();
+
+ if ( txt )
+ {
+ AppendAttributeLength( txt->Length(), aBuffer );
+ aBuffer.Append( *txt );
+ delete txt;
+ }
+ else
+ {
+ error = KErrNoMemory;
+ }
+ }
+ }
+ else
+ { // pass a null text, that is, a length of 0
+ AppendAttributeLength( 0, aBuffer );
+ }
+
+ // always append 'found' to the end...
+ // if found == 0 -> HAS IT, 1
+ // otherwise, 0
+ AppendAttributeLength( found ? 0 : 1, aBuffer);
+
+ // always append 'defaulted' to the end...
+ AppendAttributeLength( defaulted, aBuffer);
+
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L( "<- TCookiePacker::AddStringF, errcode%d" ), error ) );
+
+ return error;
+ }
+
+
+// ---------------------------------------------------------
+// TCookiePacker::AppendAttributeLength
+// ---------------------------------------------------------
+//
+void TCookiePacker::AppendAttributeLength( TInt aLength, TDes8& aBuffer ) const
+ {
+ CLOG( ( EClient, KCookiePackerLogLevel, _L( "-> TCookiePacker::AppendAttributeLength" ) ) );
+
+ TInt attrLength = aLength;
+ TPtrC8 attrDes( (const TUint8*)&attrLength, sizeof( TInt ) );
+ aBuffer.Append( attrDes );
+
+ CLOG( ( EClient, KCookiePackerLogLevel, _L( "<- TCookiePacker::AppendAttributeLength" ) ) );
+ }
+
+
+
+// ---------------------------------------------------------
+// TCookiePacker::CliPackCookie
+// ---------------------------------------------------------
+//
+TInt TCookiePacker::CliPackCookie( TDes8& aBuffer,
+ const CCookie& aCookie ) const
+ {
+ return DoPackCookie( aBuffer, aCookie, EFalse );
+ }
+
+
+
+// ---------------------------------------------------------
+// TCookiePacker::SrvPackCookie
+// ---------------------------------------------------------
+//
+TInt TCookiePacker::SrvPackCookie( TDes8& aBuffer,
+ const CCookie& aCookie ) const
+ {
+ return DoPackCookie( aBuffer, aCookie, ETrue );
+ }
+
+
+
+// ---------------------------------------------------------
+// TCookiePacker::GetPackedAttribute
+// ---------------------------------------------------------
+//
+void TCookiePacker::GetPackedAttributeL
+ ( const CCookie::TCookieAttributeName aAttrib,
+ CCookie& aCookie,
+ const TUint8*& aPtrStart ) const
+ {
+ // the first 4 bytes (i.e. sizeof(TInt)) contains the size
+ TInt size;
+ TPtr8 sizeDes( (TUint8*)&size, sizeof( TInt ) );
+ sizeDes.Copy( aPtrStart, sizeof( TInt ) );
+
+ User::LeaveIfError(size);
+ // now we have the size, jump to the value
+ aPtrStart += sizeof( TInt );
+
+ if ( size )
+ {
+ HBufC8* buf = HBufC8::NewLC( size );
+ TPtr8 bufDes( buf->Des() ); // buffer descriptor
+ Mem::Copy( (void*)buf->Ptr(), (void*)aPtrStart, size );
+ bufDes.SetLength( size );
+
+ aPtrStart += size;
+
+ // now get the 'found' value
+ TInt found;
+ TPtr8 foundDes( (TUint8*)&found, sizeof( TInt ) );
+ foundDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ // now get the 'defaulted' value
+ TInt defaulted;
+ TPtr8 defaultedDes( (TUint8*)&defaulted, sizeof( TInt ) );
+ defaultedDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ THTTPHdrVal attributeVal;
+ // Name and Value are case-sensitive
+ if( ( CCookie::EName == aAttrib ) || ( CCookie::EValue == aAttrib ) )
+ {
+ RString str = iStringPool.OpenStringL( bufDes );
+ attributeVal.SetStr( str );
+ aCookie.SetAttribute( aAttrib,
+ attributeVal,
+ defaulted ); // ignore the result
+ str.Close();
+ }
+ else
+ {
+ RStringF strf = iStringPool.OpenFStringL( bufDes );
+ attributeVal.SetStrF( strf );
+ aCookie.SetAttribute( aAttrib,
+ attributeVal,
+ defaulted ); // ignore the result
+ strf.Close();
+ }
+
+ CleanupStack::PopAndDestroy(); // buf
+ }
+ else
+ {
+ // now get the 'found' value
+ TInt found;
+ TPtr8 foundDes( (TUint8*)&found, sizeof( TInt ) );
+ foundDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ // now get the 'defaulted' value
+ TInt defaulted;
+ TPtr8 defaultedDes( (TUint8*)&defaulted, sizeof( TInt ) );
+ defaultedDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ if ( found )
+ { // still add empty str...
+ HBufC8* buf = HBufC8::NewLC( 0 );
+ TPtr8 bufDes( buf->Des() ); // buffer descriptor
+ bufDes.SetLength( 0 );
+
+ THTTPHdrVal attributeVal;
+ // Name and Value are case-sensitive
+ // It is a serious error if Name or Value is empty!
+ if( ( CCookie::EName == aAttrib ) || ( CCookie::EValue == aAttrib ) )
+ {
+ RString str = iStringPool.OpenStringL( bufDes );
+ attributeVal.SetStr( str );
+ aCookie.SetAttribute( aAttrib,
+ attributeVal,
+ defaulted ); // ignore the result
+ str.Close();
+ }
+ else
+ {
+ RStringF strf = iStringPool.OpenFStringL( bufDes );
+ attributeVal.SetStrF( strf );
+ aCookie.SetAttribute( aAttrib,
+ attributeVal,
+ defaulted ); // ignore the result
+ strf.Close();
+ }
+
+ CleanupStack::PopAndDestroy(); // buf
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------
+// TCookiePacker::GetPackedDateAttributeL
+// ---------------------------------------------------------
+//
+void TCookiePacker::GetPackedDateAttributeL( CCookie& aCookie,
+ const TUint8*& aPtrStart ) const
+ {
+ // the first 4 bytes (i.e. sizeof(TInt)) contains the size
+ TInt size;
+ TPtr8 sizeDes( (TUint8*)&size, sizeof( TInt ) );
+ sizeDes.Copy( aPtrStart, sizeof( TInt ) );
+ User::LeaveIfError(size);
+ // now we have the size, jump to the value
+ aPtrStart += sizeof( TInt );
+ if ( size )
+ {
+ HBufC8* buf8 = HBufC8::NewLC( size );
+ TPtr8 buf8Des( buf8->Des() ); // buffer descriptor
+ Mem::Copy( (void*)buf8->Ptr(), (void*)aPtrStart, size );
+ buf8Des.SetLength( size );
+ aPtrStart += size;
+
+ // now get the 'found' value
+ TInt found;
+ TPtr8 foundDes( (TUint8*)&found, sizeof( TInt ) );
+ foundDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ // now get the 'defaulted' value
+ TInt defaulted;
+ TPtr8 defaultedDes( (TUint8*)&defaulted, sizeof( TInt ) );
+ defaultedDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ // convert string to 16 bit
+ HBufC *buf = HBufC::NewLC( size );
+ TPtr bufDes( buf->Des() );
+ bufDes.Copy( buf8Des );
+
+ // convert to DateTime
+ TTime cookieDate;
+ // TTime::Set() uses 0 value as offset for Month and Day,
+ // we convert those values.
+ DecreaseNumericValueL( bufDes, 5 ); // Month
+ DecreaseNumericValueL( bufDes, 7 ); // Day
+ bufDes.Trim(); // spaces must be removed before TTime::Set()
+ // TInt parseError =
+ cookieDate.Set( bufDes );
+ TDateTime temp = cookieDate.DateTime();
+ THTTPHdrVal attributeVal( temp );
+ aCookie.SetAttribute( CCookie::EDate, attributeVal, defaulted );
+
+ CleanupStack::PopAndDestroy(); // buf
+ CleanupStack::PopAndDestroy(); // buf8
+ }
+ else
+ {
+ // now get the 'found' value
+ TInt found;
+ TPtr8 foundDes( (TUint8*)&found, sizeof( TInt ) );
+ foundDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ // now get the 'defaulted' value
+ TInt defaulted;
+ TPtr8 defaultedDes( (TUint8*)&defaulted, sizeof( TInt ) );
+ defaultedDes.Copy( aPtrStart, sizeof( TInt ) );
+ aPtrStart += sizeof( TInt );
+
+ if ( found )
+ {
+ TTime nowTime;
+ nowTime.UniversalTime();
+ TDateTime attrTime = nowTime.DateTime();
+ THTTPHdrVal attributeVal( attrTime );
+ aCookie.SetAttribute( CCookie::EDate, attributeVal, defaulted );
+ }
+
+ }
+ }
+
+// ---------------------------------------------------------
+// TCookiePacker::UnpackCookieL
+// get the cookie entries, one after the other
+// an entry with a length of 0 and no txtbuf means empty value
+// ---------------------------------------------------------
+//
+void TCookiePacker::UnpackCookieL( const TUint8*& aPtr,
+ CCookie& aCookie ) const
+ {
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L( "-> TCookiePacker::UnpackCookieL" ) ) );
+ GetPackedAttributeL( CCookie::EName, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EValue, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EComment, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::ECommentURI, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EDiscard, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EDomain, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EMaxAge, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EPath, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EPort, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::ESecure, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EVersion, aCookie, aPtr );
+ GetPackedAttributeL( CCookie::EExpires, aCookie, aPtr );
+ GetPackedDateAttributeL( aCookie, aPtr );
+ // now get the FromCookie2 TBool, which comes a TInt...
+ TInt fromcookie2( 0 );
+ TPtr8 sizeDes( (TUint8*)&fromcookie2, sizeof( TInt ) );
+ sizeDes.Copy( aPtr, sizeof( TInt ) );
+ aPtr += sizeof( TInt );
+ // now we have the size, jump to the value
+ aCookie.SetCookie2( fromcookie2 );
+
+ THTTPHdrVal hVal;
+ // We're checking the Version attribute - this
+ // attribute is present in RFC but not in Netscape cookies
+ if ( aCookie.Attribute( CCookie::EVersion, hVal ) == KErrNone )
+ {
+ aCookie.SetFromNetscape( EFalse );
+ }
+ else
+ {
+ aCookie.SetFromNetscape( ETrue );
+ }
+ TrimNameAndValueL( aCookie );
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L( "<- TCookiePacker::UnpackCookieL" ) ) );
+ }
+
+// ---------------------------------------------------------
+// TCookiePacker::TrimNameAndValueL
+// ---------------------------------------------------------
+//
+void TCookiePacker::TrimNameAndValueL( CCookie& aCookie ) const
+ {
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L( "-> TCookiePacker::TrimNameAndValueL" ) ) );
+ THTTPHdrVal hValName;
+ if( aCookie.Attribute( CCookie::EName, hValName ) == KErrNone )
+ {
+ THTTPHdrVal hValValue;
+ if( aCookie.Attribute( CCookie::EValue, hValValue ) == KErrNone )
+ {
+ TInt lenName( hValName.Str().DesC().Length() );
+ TInt lenValue( hValValue.Str().DesC().Length() );
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L( "NameLen: %d, ValueLen: %d" ), lenName, lenValue ) );
+ if( lenName + lenValue < KMaxCookieBufferSize )
+ {
+ // everything is OK.
+ return;
+ }
+ if( lenName >= KMaxCookieBufferSize )
+ {
+ // Cookie should be discarded
+ User::Leave( KErrTooBig );
+ }
+ else
+ {
+ // trim value
+ TInt size( KMaxCookieBufferSize - lenName );
+ HBufC8* buf = HBufC8::NewLC( size + 1 );
+ TPtr8 bufDes( buf->Des() ); // buffer descriptor
+ bufDes.Copy( hValValue.Str().DesC().Left( size ) );
+ bufDes.ZeroTerminate();
+ // modify aCookie
+ RString str = iStringPool.OpenStringL( bufDes );
+ THTTPHdrVal attributeVal( str );
+ aCookie.RemoveAttribute( CCookie::EValue );
+ aCookie.SetAttribute( CCookie::EValue, attributeVal );
+ str.Close();
+ CleanupStack::PopAndDestroy( buf );
+ }
+ }
+ }
+ CLOG( ( EClient, KCookiePackerLogLevel,
+ _L( "<- TCookiePacker::TrimNameAndValueL" ) ) );
+ }
+
+// ---------------------------------------------------------
+// TCookiePacker::UnpackCookieL
+// ---------------------------------------------------------
+//
+void TCookiePacker::UnpackCookieL( const TDesC8& aBuffer,
+ CCookie& aCookie ) const
+ {
+ const TUint8* ptr = aBuffer.Ptr();
+ UnpackCookieL( ptr, aCookie );
+ }
+
+// ---------------------------------------------------------
+// TCookiePacker::UnpackCookiesFromBufferL
+// ---------------------------------------------------------
+//
+void TCookiePacker::UnpackCookiesFromBufferL( const TDesC8& aBuffer,
+ RPointerArray<CCookie>& aCookies ) const
+ {
+ const TUint8* bufferPtr = aBuffer.Ptr();
+ const TUint8* bufferEndPtr = bufferPtr + aBuffer.Size();
+
+ while ( bufferPtr < bufferEndPtr )
+ {
+ CCookie* cookie = CCookie::NewL( iStringPool );
+ CleanupStack::PushL( cookie );
+
+ UnpackCookieL( bufferPtr, *cookie );
+
+ if ( bufferEndPtr < bufferPtr ) // we read in too many bytes
+ {
+ CleanupStack::PopAndDestroy(); // destroy the last bad cookie
+ }
+ else // everything is okay
+ {
+ // The cookie pointer array (i.e. iCookies) takes over the
+ // ownership
+ User::LeaveIfError( aCookies.Append( cookie ) );
+
+ CleanupStack::Pop(); // cookie
+ }
+ }
+ }
+
+
+
+// ---------------------------------------------------------
+// TCookiePacker::DoPackCookie
+// ---------------------------------------------------------
+//
+TInt TCookiePacker::DoPackCookie( TDes8& aBuffer,
+ const CCookie& aCookie,
+ TBool aServer ) const
+ {
+ CLOG( ( EClient, KCookiePackerLogLevel, _L( "-> TCookiePacker::DoPackCookie" ) ) );
+ TInt error = AddStringF( CCookie::EName, aCookie, aBuffer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF( CCookie::EValue, aCookie, aBuffer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF( CCookie::EComment, aCookie, aBuffer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF( CCookie::ECommentURI, aCookie, aBuffer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF( CCookie::EDiscard,
+ aCookie,
+ aBuffer );
+ if ( error == KErrNone )
+ {
+ // If the server is packing, need to take extra care
+ // for the Domain attribute...
+ // If the Domain is defaulted, defaulted domain
+ // should not be sent back...
+ // for this, set aNoDefaulted to aServer:
+ // if server is packing, attribute will be suppressed
+ // if the client is packing, attribute
+ // will be transferred normally...
+ error = AddStringF( CCookie::EDomain,
+ aCookie,
+ aBuffer,
+ aServer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF( CCookie::EMaxAge,
+ aCookie,
+ aBuffer );
+ if ( error == KErrNone )
+ {
+ // If the server is packing, need to take extra care
+ // If the Path is defaulted, defaulted path
+ // should not be sent back...
+ // for this, set aNoDefaulted to aServer:
+ // if server is packing, attribute will be
+ // suppressed
+ // if the client is packing, attribute
+ // will be transferred normally...
+ error = AddStringF( CCookie::EPath,
+ aCookie,
+ aBuffer,
+ aServer );
+ if ( error == KErrNone )
+ {
+ // If the server is packing,
+ // need to take extra care
+ // If the Port is defaulted,
+ // defaulted Port
+ // should not be sent back...
+ // for this, set aNoDefaulted to aServer:
+ // if server is packing, attribute will be
+ // suppressed
+ // if the client is packing, attribute
+ // will be transferred normally...
+ error = AddStringF( CCookie::EPort,
+ aCookie,
+ aBuffer,
+ aServer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF( CCookie::ESecure,
+ aCookie,
+ aBuffer );
+ if ( error == KErrNone )
+ {
+ error =
+ AddStringF( CCookie::EVersion,
+ aCookie,
+ aBuffer );
+ if ( error == KErrNone )
+ {
+ error = AddStringF
+ ( CCookie::EExpires,
+ aCookie,
+ aBuffer );
+ if ( error == KErrNone )
+ {
+ TRAPD( err, error = AddDateL
+ ( aCookie,
+ aBuffer ) );
+ if ( err != KErrNone )
+ {
+ error = err;
+ }
+ if ( error == KErrNone )
+ {
+ // handle
+ // CCookie::FromCookie2()
+ AppendAttributeLength(
+ aCookie.FromCookie2(),
+ aBuffer );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ CLOG( ( EClient, KCookiePackerLogLevel, _L( "<- TCookiePacker::DoPackCookie" ) ) );
+ return error;
+ }
+
+// ---------------------------------------------------------
+// TCookiePacker::DecreaseNumericValueL
+// ---------------------------------------------------------
+//
+TInt TCookiePacker::DecreaseNumericValueL( TDes& aBuffer, const TInt aIndex ) const
+{
+ HBufC *nums = HBufC::NewLC( 12 );
+ TPtr numDes( nums->Des() );
+ numDes.Copy( _L("98765432109") );
+ HBufC *midChar = HBufC::NewLC( 2 );
+ TPtr charDes( midChar->Des() );
+ charDes.FillZ( 2 );
+
+ TInt found = numDes.Length() - 1;
+ TInt i = aIndex + 1;
+ while( (i > 0 ) && ( found == numDes.Length() - 1 ) )
+ {
+ i--;
+ found = numDes.Locate( aBuffer[i] ) + 1;
+ charDes = numDes.Mid( found, 1 );
+ charDes.ZeroTerminate();
+ aBuffer.Replace( i, 1, charDes );
+ }
+
+ CleanupStack::PopAndDestroy(); // midChar
+ CleanupStack::PopAndDestroy(); // nums
+ return ( (i == 0 ) && ( found == numDes.Length() - 1 ) ) ?
+ KErrGeneral : KErrNone;
+}
+