diff -r 000000000000 -r 2f259fa3e83a lafagnosticuifoundation/uigraphicsutils/tulsrc/tultextresourceutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lafagnosticuifoundation/uigraphicsutils/tulsrc/tultextresourceutils.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,1737 @@ +// Copyright (c) 2002-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 +#include +#include "languagespecificnumberconverter.h" +#include +#include +#include + +// CP1252 ellipsis character value. +#define KEllipsis 0x2026 // cp1252=133 + +// KIntSize and KKeySize define maximum number of characters +// in input TInts and in keystring. KNumOfParams is maximum number of +// parameters in the resource string. +const TInt KIntSize(11); //Max 11 digits. +const TInt KNumOfParams(20); //Max 20 parameters +const TInt KKeySize (4); //Max 2 digits in index. For example %20U + +// Key strings for number and unicode data. +_LIT(KNumKeyBuf, "%N"); //Number data +_LIT(KStringKeyBuf, "%U"); //Unicode data + +// Key characters to format key strings. +const TText KKeyPrefix('%'); +const TText KNumKey('N'); +const TText KStringKey('U'); +const TText KSubStringSeparator(0x0001); // pipe ('|') character +const TText KDirNotFound( 0x0002 ); + +const TInt KNoIndex(-1); //No index- code in Format-method. + +//Panic category +_LIT(KPanicCategory, "TulTextResourceUtils"); + +const TInt KExtraSpaceForMainStringDirMarker = 1; +const TInt KExtraSpaceForSubStringDirMarkers = 2; +const TText KLRMarker = 0x200E; +const TText KRLMarker = 0x200F; + +// KUnknownCount is used as default value for param count in FormatStringL +const TInt KUnknownCount(-99); + +// +// class TulTextResourceUtils +// + +/** +Reads a resource string without memory allocation. The loaded string is stored in the +destination TDes&. Because this method doesn't allocate memory the destination +descriptor must be long enough. + +@param aResourceId The numeric ID of the resource string to be read. +@param aDest Reference to the descriptor where the resource string is loaded. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. + +@panic ECCoeEnvNotInitialized Parameter aLoaderEnv is NULL and CCoeEnv::Static returned NULL. +*/ +EXPORT_C void TulTextResourceUtils::Load(TDes& aDest, TInt aResourceId, CCoeEnv* aLoaderEnv) + { + if (!aLoaderEnv) + { + aLoaderEnv=CCoeEnv::Static(); + if (!aLoaderEnv) + User::Panic(KPanicCategory, ECCoeEnvNotInitialized); + } + + //If aDes is too small, this function causes CCoeEnv::HandleError() to be called. + TInt ignore(KErrNone); // To avoid compiler warning. + // Trapped because ReadResource() is deprecated and method cannot leave. + TRAP(ignore, aLoaderEnv->ReadResourceL(aDest, aResourceId)); + } + +/** +Reads a resource string with memory allocation. + +@param aResourceId The numeric ID of the resource string to be read. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the resource + string. The calling program must destroy the heap descriptor + when it is no longer needed. + +@leave KErrNotSupported Parameter aLoaderEnv is NULL and CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, CCoeEnv* aLoaderEnv) + { + if (!aLoaderEnv) + { + aLoaderEnv=CCoeEnv::Static(); + if (!aLoaderEnv) + User::Leave(KErrNotSupported); + } + return aLoaderEnv->AllocReadResourceL(aResourceId); + } + +/** +Reads a resource string with memory allocation and replaces the first \%N-string in it +with replacement TInt. In debug builds the Symbian OS panic mechanism is used to +notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aInt The replacing TInt. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. The calling program must destroy the heap + descriptor when it is no longer needed. + +@panic EKeyStringNotFound In debug build if the key string 'N' wasn't + found in formatting. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, TInt aInt, CCoeEnv* aLoaderEnv) + { + HBufC* resbuf = LoadLC(aResourceId, aLoaderEnv); + TPtr retptr = resbuf->Des(); + // + //Converting input TInt to a descriptor. This way the size + //of the return string can be controlled. + // + TBuf intbuf; + intbuf.Num(aInt); + + if (LanguageSpecificNumberConverter::IsConversionNeeded()) + LanguageSpecificNumberConverter::Convert(intbuf); + // + // Get number of sub strings + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Adding int + HBufC* retbuf = FormatStringL(*buffer, KNumKeyBuf, intbuf, mainDir); + + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +/** +Reads a resource string with memory allocation and replaces the first \%U-string in it +with replacement string. In debug builds the Symbian OS panic mechanism is used to +notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aString Reference to the replacing string. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. The calling program must destroy the heap + descriptor when it is no longer needed. + +@panic EKeyStringNotFound In debug build if the key string 'U' wasn't + found in formatting. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, const TDesC& aString, CCoeEnv* aLoaderEnv) + { + HBufC* resbuf = LoadLC(aResourceId, aLoaderEnv); + TPtr retptr(resbuf->Des()); + + // Get number of sub strings + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Formating the return string with FormatStringL. + HBufC* retbuf = FormatStringL(*buffer, KStringKeyBuf, aString, mainDir); + + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +/** +Reads a resource string with memory allocation, replaces the first \%N-string in it with +replacement TInt and the first \%U-string in it with replacement string. +In debug builds the Symbian OS panic mechanism is used to +notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aString Reference to the replacing string. +@param aInt The replacing TInt. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. The calling program must destroy the heap + descriptor when it is no longer needed. + +@panic EKeyStringNotFound In debug build if the key string 'N' or 'U' + wasn't found in formatting. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, const TDesC& aString, TInt aInt, CCoeEnv* aLoaderEnv) + { + HBufC* resbuf = LoadLC(aResourceId, aLoaderEnv); + TPtr retptr = resbuf->Des(); + + //Converting input TInt to a descriptor. This way the size + //of the return string can be controlled. + TBuf intbuf; + intbuf.Num(aInt); + + if (LanguageSpecificNumberConverter::IsConversionNeeded()) + LanguageSpecificNumberConverter::Convert(intbuf); + + // Get number of sub strings + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Adding int + HBufC* cacbuf = FormatStringL(*buffer, KNumKeyBuf, intbuf, mainDir); + CleanupStack::PushL(cacbuf); + + // Resolve directionality of the modified text and + // forward information to Formater(). + mainDir = DirectionalityL(*cacbuf, &found); + + //Adding string. + HBufC* retbuf = FormatStringL(*cacbuf, KStringKeyBuf, aString, mainDir); + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + + CleanupStack::PopAndDestroy(cacbuf); + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +/** +Reads a resource string with memory allocation and replaces the \%(index)N-strings +in it with replacement TInts from an array. In debug builds the Symbian OS +panic mechanism is used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aInts Reference to the array including the replacing TInts. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. The calling program must destroy the heap + descriptor when it is no longer needed. + +@panic ETooManyArguments In debug build if too many replacing + elements in aInts array. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, const CArrayFix& aInts, CCoeEnv* aLoaderEnv) + { + HBufC* resbuf = LoadLC(aResourceId, aLoaderEnv); + TPtr retptr(resbuf->Des()); + TInt max = aInts.Count(); //Number of keystrings in resource string + __ASSERT_DEBUG(max <= KNumOfParams, + User::Panic(KPanicCategory, ETooManyArguments)); + + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Formating the return string with FormatStringL. + HBufC* retbuf = FormatStringL(*buffer, aInts, max, mainDir); + + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +/** +Reads a resource string with memory allocation and replaces the \%(index)U-strings +in it with replacement strings from an array. In debug builds the Symbian OS +panic mechanism is used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aStrings Reference to the array including pointers to the + replacing strings. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. The calling program must destroy the heap + descriptor when it is no longer needed. + +@panic ETooManyArguments In debug build if too many replacing + elements in aStrings + array. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, const MDesCArray& aStrings, CCoeEnv* aLoaderEnv) + { + HBufC* resbuf = LoadLC(aResourceId, aLoaderEnv); + TPtr retptr(resbuf->Des()); + + TInt max = aStrings.MdcaCount(); //Number of keystrings in resource string + __ASSERT_DEBUG(max <= KNumOfParams, + User::Panic(KPanicCategory, ETooManyArguments)); + + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Formating the return string with FormatStringL. + HBufC* retbuf = FormatStringL(*buffer, aStrings, max, mainDir); + + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +/** +Reads a resource string with memory allocation and replaces the +\%(index)U-strings in it with replacement strings from an array and +the \%(index)N-strings in it with replacement TInts from another +array. In debug builds the Symbian OS panic mechanism is used to +notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aStrings Reference to the array including pointers to the + replacing strings. +@param aInts Reference to the array including the replacing TInts. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. The calling program must destroy the heap + descriptor when it is no longer needed. + +@panic ETooManyArguments In debug build if too many replacing + elements in aStrings and/or aInts arrays. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadL(TInt aResourceId, const MDesCArray& aStrings, const CArrayFix& aInts, CCoeEnv* aLoaderEnv) + { + HBufC* resbuf = LoadLC(aResourceId, aLoaderEnv); + TPtr retptr(resbuf->Des()); + + //Number of keystrings in resource string. + TInt max = (aInts.Count() + aStrings.MdcaCount()); + __ASSERT_DEBUG(max <= KNumOfParams, User::Panic(KPanicCategory, + ETooManyArguments)); + + // Get number of sub strings + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Adding int + HBufC* cacbuf = FormatStringL(*buffer, aInts, max, mainDir); //Adding ints + CleanupStack::PushL(cacbuf); + + // Resolve directionality of the modified text and + // forward information to Formater(). + mainDir = DirectionalityL(*cacbuf, &found); + + //Adding string. + HBufC* retbuf = FormatStringL(*cacbuf, aStrings, max, mainDir); //Adding strings + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + + CleanupStack::PopAndDestroy(cacbuf); + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +/** +Reads a resource string with memory allocation and pushes the string +onto the cleanup stack. + +@param aResourceId The numeric ID of the resource string to be read. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the resource + string. This pointer is in the cleanup stack. The calling + program should pop and destroy the heap descriptor when it is + no longer needed. + +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, CCoeEnv* aLoaderEnv) + { + if (!aLoaderEnv) + { + aLoaderEnv=CCoeEnv::Static(); + if (!aLoaderEnv) + User::Leave(KErrNotSupported); + } + + return aLoaderEnv->AllocReadResourceLC(aResourceId); + } + +/** +Reads a resource string with memory allocation, replaces the first \%N-string +in it with replacement TInt and pushes the string onto the cleanup stack. In debug builds +the Symbian OS panic mechanism is used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aInt the replacing TInt. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return pointer to a heap descriptor containing the formatted + resource string. This pointer is in the cleanup stack. + The calling program should pop and destroy the heap + descriptor when it is no longer needed. + +@panic EKeyStringNotFound In debug build if the key string 'N' wasn't + found in formatting. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, TInt aInt, CCoeEnv* aLoaderEnv) + { + HBufC* retbuf = LoadL(aResourceId, aInt, aLoaderEnv); + CleanupStack::PushL(retbuf); + return retbuf; + } + +/** +Reads a resource string with memory allocation, replaces the first \%U-string +in it with replacement string and pushes the string onto the cleanup stack. +In debug builds the Symbian OS panic mechanism is used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aString Reference to the replacing string. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. This pointer is in the cleanup stack. + The calling program should pop and destroy the heap + descriptor when it is no longer needed. + +@panic EKeyStringNotFound In debug build if the key string 'U' wasn't + found in formatting. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, const TDesC& aString, CCoeEnv* aLoaderEnv) + { + HBufC* retbuf = LoadL(aResourceId, aString, aLoaderEnv); + CleanupStack::PushL(retbuf); + return retbuf; + } + +/** +Reads a resource string with memory allocation, replaces the first \%N-string +in it with replacement TInt and the first \%U-string in it with replacement +string and pushes the string onto the cleanup stack. In debug builds +the Symbian OS panic mechanism is used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be + read. +@param aString Reference to the replacing string. +@param aInt The replacing TInt. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. This pointer is in the cleanup stack. + The calling program should pop and destroy the heap + descriptor when it is no longer needed. + +@panic EKeyStringNotFound In debug build if the key string 'N' or 'U' + wasn't found in formatting. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, const TDesC& aString, TInt aInt, CCoeEnv* aLoaderEnv) + { + HBufC* retbuf = LoadL(aResourceId, aString, aInt, aLoaderEnv); + CleanupStack::PushL(retbuf); + return retbuf; + } + +/** +Reads a resource string with memory allocation, replaces the \%(index)N-strings in it with +replacement TInts from an array and pushes the string onto the +cleanup stack. In debug builds the Symbian OS panic mechanism is +used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be + read. +@param aInts Reference to the array including the replacing TInts. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. This pointer is in the cleanup stack. + The calling program should pop and destroy the heap + descriptor when it is no longer needed. + +@panic ETooManyArguments In debug build if too many replacing + elements in aInts array. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and +* CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, const CArrayFix& aInts, CCoeEnv* aLoaderEnv) + { + HBufC* retbuf = LoadL(aResourceId, aInts, aLoaderEnv); + CleanupStack::PushL(retbuf); + return retbuf; + } + + +/** +Reads a resource string with memory allocation, replaces the \%(index)U-strings +in it with replacement strings from an array and pushes the string onto the +cleanup stack. In debug builds the Symbian OS panic mechanism is +used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aStrings Reference to the array including pointers to the + replacing strings. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. This pointer is in the cleanup stack. + The calling program should pop and destroy the heap + descriptor when it is no longer needed. + +@panic ETooManyArguments In debug build if too many replacing + elements in aStrings array. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, const MDesCArray& aStrings, CCoeEnv* aLoaderEnv) + { + HBufC* retbuf = LoadL(aResourceId, aStrings, aLoaderEnv); + CleanupStack::PushL(retbuf); + return retbuf; + } + +/** +Reads a resource string with memory allocation, replaces the \%(index)U-strings +in it with replacement strings from an array. Replaces +the \%(index)N-strings with replacement TInts from another +array. Pushes the string onto the cleanup stack. In debug builds +the Symbian OS panic mechanism is used to notify programming errors. + +@param aResourceId The numeric ID of the resource string to be read. +@param aStrings Reference to the array including pointers to the + replacing strings. +@param aInts Reference to the array including the replacing TInts. +@param aLoaderEnv Pointer to the control environment. If user doesn't + give this, CCoeEnv::Static is called to get it. +@return Pointer to a heap descriptor containing the formatted + resource string. This pointer is in the cleanup stack. + The calling program should pop and destroy the heap + descriptor when it is no longer needed. + +@panic ETooManyArguments In debug build if too many replacing + elements in aStrings and/or aInts arrays. +@leave KErrNotSupported Parameter aLoaderEnv is NULL and + CCoeEnv::Static returned NULL. +*/ +EXPORT_C HBufC* TulTextResourceUtils::LoadLC(TInt aResourceId, const MDesCArray& aStrings, const CArrayFix& aInts, CCoeEnv* aLoaderEnv) + { + HBufC* retbuf = LoadL(aResourceId, aStrings, aInts, aLoaderEnv); + CleanupStack::PushL(retbuf); + return retbuf; + } + +/** +Formats a resource string without memory allocation. The formatted string +is stored in the destination TDes&. Since this method doesn't allocate memory the +destination descriptor must be long enough. In aPosition -1 means +that there is no index in the key string and all \%U-strings in the +original string are replaced with aSubs. In debug builds the +Symbian OS panic mechanism is used to notify programming errors. + +@param aDest Reference to the descriptor where the resource string + is formatted. +@param aSource Reference to the original string. +@param aPosition The index of the key string. +@param aSubs Reference to the replacing string. + +@panic EInvalidIndex In debug build if the index of the key string + is invalid. +@panic EDescriptorTooSmall In debug build if the length of the + destination descriptor is too small. +@panic EKeyStringNotFound In debug build if the key string 'U' wasn't + found, aDest is empty. + +One small sample describing the usage of the method. +@code + // Load example string "%0U %1U" defined in rss- and loc-files. + // %0U stands for weekday string and %1U for date string. + HBufC* timeFormat = TulTextResourceUtils::LoadLC(R_TIME_FORMAT, iEikonEnv); + + // The replacing string. + _LIT(dateString, "02/10/2006"); + + TulTextResourceUtils::Format(destBuf, timeFormat, + 1, // %1U stands for date string + dateString); + + // After returning destBuf contains string "%0U 02/10/2006". + @endcode +*/ +EXPORT_C void TulTextResourceUtils::Format(TDes& aDest, const TDesC& aSource, TInt aPosition, const TDesC& aSubs) + { + //Checking the index. + __ASSERT_DEBUG((aPosition >= KNoIndex && aPosition <=KNumOfParams), + User::Panic(KPanicCategory, EInvalidIndex)); + // + //Formating the keystring. + // + TBuf keybuf; + KeyStringFormater(keybuf, KStringKey, aPosition, KStringKeyBuf); + +#ifdef _RD_COMMONENGINE_DETAILED_TRACE + TInt paramCount = GetParamCount(aSource, aPosition); + #ifdef _DEBUG + TInt checklength(0); + #endif + TInt subslength(aSubs.Length() * paramCount); + TInt keylength(keybuf.Length() * paramCount); + if (subslength > keylength) + { + #ifdef _DEBUG + checklength = + #endif + aSource.Length()+subslength-keylength; + } + else + { + #ifdef _DEBUG + checklength = + #endif + aSource.Length(); + } + + //Checking the length of the destination descriptor. + __ASSERT_DEBUG(checklength <= aDest.MaxLength(), User::Panic( + KPanicCategory, EDescriptorTooSmall)); +#endif // _RD_COMMONENGINE_DETAILED_TRACE + + TRAPD( err, FormatL( aDest, aSource, keybuf, aSubs ) ); + + if ( err != KErrNone ) + { + aDest.Zero(); + aDest.Copy(aSource); + TBool found(EFalse); + TBidiText::TDirectionality dir = ResolveDirectionality(aDest, &found); + aDest.Zero(); + + //Formating the resource string. + Formater(aDest, aSource, keybuf, aSubs, dir); + } + + //If the key string wasn't found, aDest is empty. + __ASSERT_DEBUG( aDest.Length(), User::Panic( KPanicCategory, + EKeyStringNotFound ) ); + } + +/** +Formats a resource string without memory allocation. The formatted string is stored +in the destination TDes&. Since this method doesn't allocate memory the destination +descriptor must be long enough. In aPosition -1 means that there is +no index in the key string and all \%N-strings in the original string +are replaced with aSubs. In debug builds the Symbian OS panic +mechanism is used to notify programming errors. + +@param aDest Reference to the descriptor where the resource string + is formatted. +@param aSource Reference to the original string. +@param aPosition The index of the key string. +@param aSubs The replacing TInt. + +@panic EInvalidIndex In debug build if the index of the key string + is invalid. +@panic EDescriptorTooSmall In debug build if the length of the + destination descriptor is too small. +@panic EKeyStringNotFound In debug build if the key string 'N' wasn't + found, aDest is empty. + +One small sample describing the usage of the method. + @code + // Load example string "%0N %1N" defined in rss- and loc-files. + // %0N stands for area code and %1N for phone number. + HBufC* telFormat = TulTextResourceUtils::LoadLC(R_TEL_FORMAT, iEikonEnv); + + // The replacing number. + TInt areaCode(123); + + TulTextResourceUtils::Format(destBuf, telFormat, + 0, // %0N stands for area code + areaCode); + + // After returning destBuf contains string "123 %1N". +*/ +EXPORT_C void TulTextResourceUtils::Format(TDes& aDest, const TDesC& aSource, TInt aPosition, TInt aSubs) + { + //Checking the index. + __ASSERT_DEBUG((aPosition >= KNoIndex && aPosition <=KNumOfParams), + User::Panic(KPanicCategory, EInvalidIndex)); + // + //Formating the keystring. + // + TBuf keybuf; + KeyStringFormater(keybuf, KNumKey, aPosition, KNumKeyBuf); + TBuf intbuf; + intbuf.Num(aSubs); + + if (LanguageSpecificNumberConverter::IsConversionNeeded()) + LanguageSpecificNumberConverter::Convert(intbuf); + +#ifdef _RD_COMMONENGINE_DETAILED_TRACE + TInt paramCount = GetParamCount(aSource, aPosition); + #ifdef _DEBUG + TInt checklength(0); + #endif + TInt subslength(intbuf.Length() * paramCount); + TInt keylength(keybuf.Length() * paramCount); + + if (subslength > keylength) + { + #ifdef _DEBUG + checklength = + #endif + aSource.Length()+subslength-keylength; + } + else + { + #ifdef _DEBUG + checklength = + #endif + aSource.Length(); + } + + //Checking the length of the destination descriptor. + __ASSERT_DEBUG(checklength <= aDest.MaxLength(), User::Panic( + KPanicCategory, EDescriptorTooSmall)); +#endif // _RD_COMMONENGINE_DETAILED_TRACE + TRAPD(err, FormatL(aDest, aSource, keybuf, intbuf)); + + if(err != KErrNone) + { + aDest.Zero(); + aDest.Copy(aSource); + TBool found(EFalse); + TBidiText::TDirectionality dir = ResolveDirectionality(aDest, &found); + aDest.Zero(); + + //Formating the resource string. + Formater(aDest, aSource, keybuf, intbuf, dir); + } + // + //If the key string wasn't found, aDest is empty. + // + __ASSERT_DEBUG(aDest.Length(), User::Panic(KPanicCategory, + EKeyStringNotFound)); + } + +/** +Finds the keystring from the source string and replaces it with the +replacement string. +*/ +HBufC* TulTextResourceUtils::FormatStringL(const TDesC& aSource, const TDesC& aKey, const TDesC& aSubs,TBidiText::TDirectionality aDir) + { + TInt paramCount(KUnknownCount); // variable needed as it may be updated + return FormatStringL(aSource, aKey, aSubs, aDir, paramCount, KUnknownCount); + } + +/** +Finds the keystring from the source string and replaces it with the +replacement string. +*/ +HBufC* TulTextResourceUtils::FormatStringL(const TDesC& aSource, const TDesC& aKey, const TDesC& aSubs, TBidiText::TDirectionality aDirectionality, + TInt& aParamCount, TInt aSubCount) + { + if (aParamCount == KUnknownCount) + aParamCount = GetParamCount(aSource); + + if (aSubCount == KUnknownCount) + aSubCount = GetSubStringCount(aSource); + + // determine lenght of needed buffer + TInt sourcelength(aSource.Length()); + TInt keylength(aKey.Length()); + TInt subslength(aSubs.Length()); + TInt destlength = 0; + if (subslength >= keylength) + { + destlength = sourcelength + ((subslength - keylength) * aParamCount); + } + else + { + destlength = sourcelength; + } + + destlength += KExtraSpaceForMainStringDirMarker * aSubCount; + destlength += KExtraSpaceForSubStringDirMarkers * aParamCount; + // + // Allocating heap buffer for return string. + // + + HBufC* retbuf = HBufC::NewL(destlength); + TPtr retptr(retbuf->Des()); + + // Formating the resource string. Don't bother with format, + // if parameter count is not above zero + if (aParamCount > 0) + { + aParamCount -= Formater(retptr, aSource, aKey, aSubs, aDirectionality); + __ASSERT_DEBUG(aParamCount >= 0, User::Invariant()); + } + + // + // If the key string wasn't found, retbuf is empty. + // + return retbuf; + } + +/** +Finds the \%(index)N-keystrings from the source string and replaces it with the +replacement TInts. +*/ +HBufC* TulTextResourceUtils::FormatStringL(TDesC& aSource, const CArrayFix& aInts, TInt aMax, TBidiText::TDirectionality aDir) + { + TInt numbers = aInts.Count(); //Number of input TInts. + // + //Allocating heap buffer for return string. + // + TInt paramCount = GetParamCount(aSource); + TInt subCount = GetSubStringCount(aSource); + HBufC* retbuf = HBufC::NewLC( + aSource.Length() + + paramCount * KIntSize + + paramCount * KExtraSpaceForSubStringDirMarkers + + subCount * KExtraSpaceForMainStringDirMarker); + TPtr retptr(retbuf->Des()); + + TBidiText::TDirectionality mainDir = aDir; + + + //The input TInt is converted to a descriptor. This way the size + //of the return string can be controlled. + TBuf intbuf; + + //The key string must be formated again in the for-loop every round. + TBuf keybuf; + + //intcount keeps track of used TInts from aInts. + TInt intcount(0); + + //loopcount counts the loops in the while loop. + TInt loopcount(0); + + //The resource string is read from retptr and formatted in retbuf + //in every round. + retptr.Append(aSource); + + while (loopcount <= aMax && paramCount > 0) + { + //Formating key string. + keybuf.Zero(); + keybuf.Append(KKeyPrefix); + keybuf.AppendNum(loopcount); + keybuf.Append(KNumKey); + + //If all the TInts from aInts are used, the resource string is checked + //for unsolved parameters. + if (intcount == numbers) + { +#ifdef _RD_COMMONENGINE_DETAILED_TRACE // debug build + HBufC* checkbuf = FormatStringL(retptr, keybuf, keybuf, mainDir, + paramCount, subCount); + __ASSERT_DEBUG(!checkbuf->Length(), User::Panic( + KPanicCategory, ETooFewArguments)); + delete checkbuf; +#endif // _RD_COMMONENGINE_DETAILED_TRACE + } + else if (loopcount == aMax) + { +#ifdef _RD_COMMONENGINE_DETAILED_TRACE // debug build + HBufC* checkbuf = FormatStringL(retptr, keybuf, keybuf, mainDir, + paramCount, subCount); + __ASSERT_DEBUG(!checkbuf->Length(), User::Panic( + KPanicCategory, EInvalidIndex)); + delete checkbuf; +#endif // _RD_COMMONENGINE_DETAILED_TRACE + } + else + { + //Converting TInt. + intbuf.Zero(); + intbuf.Num(aInts[intcount]); + + if (LanguageSpecificNumberConverter::IsConversionNeeded()) + LanguageSpecificNumberConverter::Convert(intbuf); + + //Formating the return string. + HBufC* cacbuf = FormatStringL(retptr, keybuf, intbuf, mainDir, paramCount, subCount); + TPtr cacptr(cacbuf->Des()); + + //If the cacbuf is empty, the key string with this round's + //index was a string variable. If there are no string + //variables in this resource string, it's an error. + // + if (cacptr.Length()) + { + retptr = cacptr; + intcount++; + } + else + __ASSERT_DEBUG(numbers != aMax, User::Panic(KPanicCategory, + EInvalidIndex)); + delete cacbuf; + } + + loopcount++; + } + __ASSERT_DEBUG(intcount == numbers, User::Panic(KPanicCategory, + ETooManyArguments)); + + //Reallocating the return buffer to right size. + retbuf = retbuf->ReAllocL(retptr.Length()); + CleanupStack::Pop(); //retbuf + return retbuf; + } + +/** +Finds the \%(index)U-keystrings from the source string and replaces it with the +replacement strings. +*/ +HBufC* TulTextResourceUtils::FormatStringL(TDesC& aSource, const MDesCArray& aStrings, TInt aMax, TBidiText::TDirectionality aDir) + { + TInt strings(aStrings.MdcaCount()); //Number of input strings. + + //Counting the overall length of input strings. + TInt maxSubsLength(0); + for (TInt i(0); i < strings; i++) + { + if (maxSubsLength < aStrings.MdcaPoint(i).Length()) + maxSubsLength = aStrings.MdcaPoint(i).Length(); + } + + //Allocating heap buffer for return string. + TInt paramCount = GetParamCount(aSource); + TInt subCount = GetSubStringCount(aSource); + HBufC* retbuf = HBufC::NewLC( + aSource.Length() + + paramCount * maxSubsLength + // worst case scenario; more accurate alloc + // would require complex analysis + paramCount * KExtraSpaceForSubStringDirMarkers + + subCount * KExtraSpaceForMainStringDirMarker); + TPtr retptr(retbuf->Des()); + + TBidiText::TDirectionality mainDir = aDir; + + //The key string must be formated again in the for-loop every round. + TBuf keybuf; + + //descount keeps track of used HBufC*'s from aStrings. + TInt descount(0); + + //loopcount counts the loops in the while loop. + TInt loopcount(0); + + //The resource strings is read from retptr and formatted in retbuf every round. + retptr.Append(aSource); + + while (loopcount <= aMax && paramCount > 0) + { + //Formating key string. + keybuf.Zero(); + keybuf.Append(KKeyPrefix); + keybuf.AppendNum(loopcount); + keybuf.Append(KStringKey); + + //If all the strings from aStrings are used, the resource string is + //checked for unsolved parameters. + if (descount == strings) + { +#ifdef _RD_COMMONENGINE_DETAILED_TRACE // debug build + HBufC* checkbuf = FormatStringL(retptr, keybuf, keybuf, mainDir, + paramCount, subCount); + __ASSERT_DEBUG(!checkbuf->Length(), User::Panic( + KPanicCategory, ETooFewArguments)); + delete checkbuf; +#endif // _RD_COMMONENGINE_DETAILED_TRACE + } + else if (loopcount == aMax) + { +#ifdef _RD_COMMONENGINE_DETAILED_TRACE // debug build + HBufC* checkbuf = FormatStringL(retptr, keybuf, keybuf, + mainDir, paramCount, subCount); + __ASSERT_DEBUG(!checkbuf->Length(), User::Panic( + KPanicCategory, EInvalidIndex)); + delete checkbuf; +#endif // _RD_COMMONENGINE_DETAILED_TRACE + } + else + { + //Formating the return string. + HBufC* cacbuf = FormatStringL(retptr, keybuf, aStrings.MdcaPoint(descount), mainDir, paramCount, subCount); + TPtr cacptr(cacbuf->Des()); + + //If the cacbuf is empty, the key string with this + //round's index was a number variable. If there are no + //number variables in this resource string, it's an error. + if (cacptr.Length()) + { + retptr = cacptr; + descount++; + } + else + __ASSERT_DEBUG(strings != aMax, User::Panic(KPanicCategory, EInvalidIndex)); + + delete cacbuf; + } + loopcount++; + } + + __ASSERT_DEBUG(descount == strings, User::Panic(KPanicCategory, ETooManyArguments)); + + //Reallocating the return buffer to right size. + retbuf = retbuf->ReAllocL(retptr.Length()); + CleanupStack::Pop(); //retbuf + return retbuf; + } + +/** +Finds the keystring from the source string and replaces it with the +replacement string. The formated string is stored in the destination +descriptor. +*/ +TInt TulTextResourceUtils::Formater(TDes& aDest, const TDesC& aSource, const TDesC& aKey, const TDesC& aSubs, TBidiText::TDirectionality aDirectionality) + { + // substitute string must not contain KSubStringSeparator, + // or results will be unpredictable + __ASSERT_DEBUG(aSubs.Locate(KSubStringSeparator) == KErrNotFound, + User::Panic(KPanicCategory, EInvalidSubstitute)); + + TInt keylength(aKey.Length()); + + //aDest must be empty. + aDest.Zero(); + + // offset indicates end of last handled key in source + TInt offset(0); + + // offset in destination string + TInt desOffset(0); + + // Substring directionalities are adjusted after all changes are done. + TBool checkSubstringDirectionalities(EFalse); + + // count is the position in the source from which the substring starts + TInt count(0); + + // Replaced parameters count + TInt replaceCount(0); + + while (count != KErrNotFound) + { + // desCount is the position of the substring starts in destination. + TInt desCount(0); + + TPtrC remainder = aSource.Right(aSource.Length() - offset); + count = remainder.Find(aKey); + + TInt maxSubLength = -1; + if (count != KErrNotFound) + { + replaceCount++; + desOffset += count; + offset += count; + count = offset; + desCount = desOffset; + + // copy source to destination if first time + if (aDest.Length() == 0) + aDest.Append(aSource); + + // delete found key from destination + aDest.Delete(desCount, keylength); + + offset += keylength; // increase offset by key length + + if (count + keylength < (aSource.Length()-1)) // aKey is not at the end of string + { + if (aSource[count+keylength] == '[') // Key includes max datalength + { + maxSubLength = 10*(aSource[count+keylength+1]-'0') + + (aSource[count+keylength+2]-'0'); + aDest.Delete(desCount,4); // Length information stored->delete from descriptor + offset += 4; // increase offset by max sub length indicator + } + } + + aDest.Insert(desCount, aSubs); + + desOffset = desCount + aSubs.Length(); + + if (maxSubLength > 0 && aSubs.Length() > maxSubLength) + { + aDest.Delete(desCount+maxSubLength-1, aSubs.Length()+1-maxSubLength); + TText ellipsis(KEllipsis); + aDest.Insert(desCount+maxSubLength-1, TPtrC(&ellipsis,1)); + desOffset = desCount + maxSubLength; + } + + TBidiText::TDirectionality subsDir = + TBidiText::TextDirectionality(aDest.Mid(desCount, desOffset - desCount)); + + // If inserted string has different directionality, + // insert directionality markers so that bidi algorithm works in a desired way. + if (aDirectionality != subsDir) + { + checkSubstringDirectionalities = ETrue; + + TInt freeSpace = aDest.MaxLength() - aDest.Length(); + + // Protect the directionality of the inserted string. + if (freeSpace >= KExtraSpaceForSubStringDirMarkers) + { + TBuf<1> subsMarker; + subsMarker.Append(subsDir == TBidiText::ELeftToRight ? + KLRMarker : KRLMarker); + + aDest.Insert(desOffset, subsMarker); + aDest.Insert(desCount, subsMarker); + desOffset += KExtraSpaceForSubStringDirMarkers; + } + } + } + } + + // Adjust substring directionality markers if necessary + // and if there is enough room in destination string + if (checkSubstringDirectionalities) + { + TText mainMarker = (aDirectionality == TBidiText::ELeftToRight ? + KLRMarker : KRLMarker); + + TInt freeSpace = aDest.MaxLength() - aDest.Length(); + + // If not already done, protect the directionality of the original string + // and all of the KSubStringSeparator separated substrings. + if (freeSpace > 0 + && aDest.Length() + && aDest[0] != mainMarker + && aDest[0] != KSubStringSeparator + && aDest[0] != KDirNotFound) + { + aDest.Insert(0, TPtrC(&mainMarker, 1)); + freeSpace--; + } + + // Find and protect KSubStringSeparator separated substrings. + // Go through string backwards so that any changes will not affect indexes + // that are not yet checked. + TInt j(aDest.Length()-1); + while (freeSpace > 0 && j >= 0) + { + if (aDest[j] == KSubStringSeparator && j < (aDest.Length() - 1) + && aDest[j+1] != mainMarker && aDest[j+1] != KDirNotFound) + { + aDest.Insert(j+1, TPtrC(&mainMarker, 1)); + freeSpace--; + } + j--; + } + } + + return replaceCount; + } + +/** +Formats the keystring from given parameters. +*/ +void TulTextResourceUtils::KeyStringFormater(TDes& aDest, const TText& aKey, TInt aPosition, const TDesC& aKeyString) + { + if (aPosition > KNoIndex) + { + aDest.Append(KKeyPrefix); + aDest.AppendNum(aPosition); + aDest.Append(aKey); + } + else + { + aDest.Append(aKeyString); + } + } + +/** +Resolves directionality of the given source text. +Place-holder strings are removed so that they don't affect the result. +*/ +TBidiText::TDirectionality TulTextResourceUtils::ResolveDirectionality(TDes& aText, TBool* aFound) + { + TInt i = 0; + + // Remove place-holders from string so they don't affect directionality + // length parameters e.g. "[29]" do not contain strongly directional + // characters so can ignore them. + while (i < aText.Length()) + { + TPtrC remainder = aText.Right(aText.Length() - i); + TInt nextKey = remainder.Locate(KKeyPrefix); + i += nextKey; + + if (nextKey != KErrNotFound && i < aText.Length() - 1) + { + TInt lastCharInKey = i + 1; + + // skip possible key index + TText t = aText[lastCharInKey]; + if (t >= '0' && t <= '9') + { + lastCharInKey++; + + if (lastCharInKey < aText.Length()) + { + t = aText[lastCharInKey]; + if (t >= '0' && t <= '9') + { + lastCharInKey++; + } + } + } + + // lastCharInKey is now the index of 'N' or 'U' in the key + + if (lastCharInKey < aText.Length()) + { + TText t = aText[lastCharInKey]; + if (t == 'U' || t == 'N') + { + // found key, delete it and continue loop to + // search for the next key + aText.Delete(i, lastCharInKey - i + 1); + } + // This was not a proper key - check the remaining string + else + { + i = lastCharInKey + 1; + } + } + // end of string encountered - stop + else + { + break; + } + } + // no key found - stop + else + { + break; + } + } + + return TBidiText::TextDirectionality(aText, aFound); + } + +/** +Counts the number of parameters in the text. +Needed for correct memory allocations. +*/ +TInt TulTextResourceUtils::GetParamCount(const TDesC& aText, TInt aIndex) + { + TInt paramCount(0); + TInt i(0); + TBool singleIndex((aIndex < 0) || (aIndex > KNumOfParams) ? EFalse : ETrue); + + while (i < aText.Length()) + { + TPtrC remainder = aText.Right(aText.Length() - i); + TInt nextKey = remainder.Locate(KKeyPrefix); + i += nextKey; + + if (nextKey != KErrNotFound && i < aText.Length() - 1) + { + TInt lastCharInKey = i + 1; + + // skip possible key index + TText t = aText[lastCharInKey]; + TInt foundIndex(-1); + + if (t >= '0' && t <= '9') + { + lastCharInKey++; + foundIndex = t - '0'; + + if (lastCharInKey < aText.Length()) + { + t = aText[lastCharInKey]; + if (t >= '0' && t <= '9') + { + foundIndex *= 10; + foundIndex += t - '0'; + lastCharInKey++; + } + } + } + + // lastCharInKey is now the index of 'N' or 'U' in the key + + if (lastCharInKey < aText.Length()) + { + // Only count parameter, if index matches + if (!singleIndex || (foundIndex == aIndex)) + { + TText t = aText[lastCharInKey]; + if (t == 'U' || t == 'N') + { + // found legit key, count it + paramCount++; + // continue search after index + i = lastCharInKey + 1; + } + else if (t == '%') + i = lastCharInKey; + else // continue search after index + i = lastCharInKey + 1; + } + else // continue search after index + i = lastCharInKey + 1; + } + else // end of string encountered - stop + break; + } + else // no key found - stop + break; + } + + return paramCount; + } + +/** +Counts the number of substrings (separated by KSubStringSeparators) in the text. +Needed for correct memory allocations. +*/ +TInt TulTextResourceUtils::GetSubStringCount(const TDesC& aText) + { + TInt subCount = 0; + TInt i = 0; + + while (i < aText.Length()) + { + TPtrC remainder = aText.Right(aText.Length() - i); + TInt nextKey = remainder.Locate(KSubStringSeparator); + i += nextKey; + + // Always increase subcount, as a string without any separators counts as one substring. + // However, if string length is zero, then there are no substrings. + subCount++; + + if (nextKey != KErrNotFound && i < aText.Length() - 1) + { + i++; // skip separator + } + else + break; + } + + return subCount; + } + +/** +Resolves sub strings. Uses ResolveSubStringL() +*/ +HBufC* TulTextResourceUtils::ResolveSubStringDirsL(TDes& aText, TInt aCount, TBool* aMarker) + { + // Allocating heap buffer for return string. + TInt destlength(aText.Length()); + destlength = destlength + (KExtraSpaceForMainStringDirMarker) * aCount; + HBufC* retbuf = HBufC::NewLC(destlength); + TPtr retptr(retbuf->Des()); + TInt freeSpace(destlength); + TInt i(0); + TInt j(0); + TBuf<1> subsMarker; + subsMarker.Append(KSubStringSeparator); + TInt count(aCount - 1); + + while (i < aCount) + { + // Resolve sub string + HBufC* buffer = ResolveSubStringL(aText, aMarker); + TPtr ptr = buffer->Des(); + CleanupStack::PushL(buffer); + + // Restore sub string separators + if (freeSpace >= ptr.Length()) + { + retptr.Insert(j, ptr); + freeSpace -= ptr.Length(); + j += ptr.Length(); + if (freeSpace > KExtraSpaceForMainStringDirMarker && i < count) + { + retptr.Append(subsMarker); + j ++; + } + } + CleanupStack::PopAndDestroy(buffer); + i++; + } + + retbuf = retbuf->ReAllocL(retptr.Length()); + CleanupStack::Pop(); //retbuf + return retbuf; + } + +/** +Resolves sub string and directionality of the sub string. +Adds no dir marker if directionality of the string not found. +*/ +HBufC* TulTextResourceUtils::ResolveSubStringL(TDes& aText, TBool* aMarker) + { + // Allocating heap buffer for return string. + TInt destlength(aText.Length()); + HBufC* retbuf = HBufC::NewLC(destlength + 1); // no dir marker + TPtr retptr(retbuf->Des()); + + TBuf<1> marker; + marker.Append(KDirNotFound); + + TPtrC remainder = aText.Right(aText.Length()); + TInt nextKey = remainder.Locate(KSubStringSeparator); + + if (nextKey == 0) + { + remainder.Set(remainder.Mid(1)); + nextKey = remainder.Locate(KSubStringSeparator); + if (nextKey != KErrNotFound) + { + retptr.Insert(0, aText.Mid(1, nextKey)); + // Remove string from aText + aText.Delete(0, nextKey + 1); + } + else + { + TInt length = aText.Length(); + retptr.Insert(0, aText.Mid(1, length - 1)); + // Remove string from aText + aText.Delete(0, length); + } + } + else if (nextKey == KErrNotFound) + { + retptr.Insert(0, aText); + // Remove string from aText + aText.Delete(0, aText.Length()); + } + else + { + retptr.Insert(0, aText.Mid(0, nextKey)); + // Remove string from aText + aText.Delete(0, nextKey); + } + + // Resolve directionality of sub string + HBufC* dirbuf = retbuf->AllocL(); + TPtr dirptr = dirbuf->Des(); + TBool found(EFalse); + TBidiText::TDirectionality mainDir = ResolveDirectionality(dirptr, &found); + delete dirbuf; + + if (!found) + { + retptr.Insert(0, marker); + *aMarker = ETrue; + } + else + { + *aMarker = EFalse; + } + + retbuf = retbuf->ReAllocL(retptr.Length()); + CleanupStack::Pop(); //retbuf + // If the key string wasn't found, retbuf is empty. + return retbuf; + } + +TBidiText::TDirectionality TulTextResourceUtils::DirectionalityL(const TDesC& aText, TBool* aFound) + { + // Resolve directionality of sub string + HBufC* dirbuf = aText.AllocL(); + TPtr dirptr = dirbuf->Des(); + TBidiText::TDirectionality dir = ResolveDirectionality(dirptr, aFound); + delete dirbuf; + return dir; + } + +/** +Removes no dir markers from source text. +*/ +void TulTextResourceUtils::RemoveNoDirMarkers(TDes& aText) + { + TInt nextkey(0); + while (nextkey < aText.Length()) + { + nextkey = aText.Locate(KDirNotFound); + if (nextkey != KErrNotFound) + { + aText.Delete(nextkey, 1); + nextkey++; + } + else + { + break; + } + } + } + +/** +Used by exported Format methods. +*/ +void TulTextResourceUtils::FormatL(TDes& aDest, const TDesC& aSource, const TDesC& aKeybuf, const TDesC& aSubs) +{ + // Get number of sub strings + TInt count = GetSubStringCount(aSource); + + if (count >= 1) + { + HBufC* retbuf = retbuf = aSource.AllocLC(); + + TPtr retptr(retbuf->Des()); + TBool marker(EFalse); + HBufC* buffer = buffer = ResolveSubStringDirsL(retptr, count, &marker); + + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality dir = DirectionalityL(*buffer, &found); + + if (!marker) + { + //Formating the resource string. + Formater(aDest, aSource, aKeybuf, aSubs, dir); + //If the key string wasn't found, aDest is empty. + __ASSERT_DEBUG(aDest.Length(), User::Panic(KPanicCategory, + EKeyStringNotFound)); + } + else + { + // length of input string. + TInt maxSubsLength = aSubs.Length(); + TInt subCount = GetSubStringCount(aSource); + HBufC* destbuf = HBufC::NewLC( + aSource.Length() + + count * maxSubsLength + // worst case scenario; more accurate alloc + // would require complex analysis + count * KExtraSpaceForSubStringDirMarkers + + subCount * KExtraSpaceForMainStringDirMarker + + subCount * KExtraSpaceForMainStringDirMarker); // no dir markers + TPtr destptr(destbuf->Des()); + //Formating the resource string. + Formater(destptr, *buffer, aKeybuf, aSubs, dir); + + if (destptr.Length()) + { + RemoveNoDirMarkers(destptr); + } + + aDest.Zero(); + aDest.Append(destptr); + //If the key string wasn't found, aDest is empty. + __ASSERT_DEBUG(aDest.Length(), User::Panic(KPanicCategory,EKeyStringNotFound)); + CleanupStack::PopAndDestroy(destbuf); + } + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(retbuf); + } + + __ASSERT_DEBUG(aDest.Length(), User::Panic(KPanicCategory, EKeyStringNotFound)); + }