lafagnosticuifoundation/uigraphicsutils/tulsrc/tultextresourceutils.cpp
changeset 0 2f259fa3e83a
--- /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));
+	}