--- /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 <tultextresourceutils.h>
+#include <tulpanics.h>
+#include "languagespecificnumberconverter.h"
+#include <coeutils.h>
+#include <bautils.h>
+#include <coemain.h>
+
+// 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<KIntSize> 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<KIntSize> 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<TInt>& 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<TInt>& 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<TInt>& 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<TInt>& 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<KKeySize> 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<KKeySize> keybuf;
+ KeyStringFormater(keybuf, KNumKey, aPosition, KNumKeyBuf);
+ TBuf<KIntSize> 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<TInt>& 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<KIntSize> intbuf;
+
+ //The key string must be formated again in the for-loop every round.
+ TBuf<KKeySize> 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<KKeySize> 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));
+ }