emailservices/emailstore/base_plugin/src/basepluginresourceloader.cpp
branchRCL_3
changeset 16 4ce476e64c59
parent 13 0396474f30f5
equal deleted inserted replaced
13:0396474f30f5 16:4ce476e64c59
    15 *              CCoeEnv is not available.
    15 *              CCoeEnv is not available.
    16 *
    16 *
    17 */
    17 */
    18 
    18 
    19 
    19 
       
    20 
    20 #include <barsread.h>
    21 #include <barsread.h>
    21 #include <bautils.h>
    22 #include <bautils.h>
       
    23 #include <biditext.h>
       
    24 #include <tulpanics.h>
       
    25 
    22 #include "basepluginresourceloader.h"
    26 #include "basepluginresourceloader.h"
       
    27 
       
    28 // panic category constant
       
    29 #ifdef _DEBUG
       
    30 _LIT( KPanicCategory, "CResourceLoader" );
       
    31 #endif
       
    32 
       
    33 // CP1252 ellipsis character value.
       
    34 #define KEllipsis       0x2026  // cp1252=133
       
    35 
       
    36 // Key characters to format key strings.
       
    37 const TText KKeyPrefix('%');
       
    38 const TText KSubStringSeparator(0x0001);    // pipe ('|') character
       
    39 const TText KDirNotFound( 0x0002 );
       
    40 
       
    41 const TInt KExtraSpaceForMainStringDirMarker = 1;
       
    42 const TInt KExtraSpaceForSubStringDirMarkers = 2;
       
    43 const TText KLRMarker = 0x200E; 
       
    44 const TText KRLMarker = 0x200F;
       
    45 
       
    46 // KIntSize and KKeySize define maximum number of characters
       
    47 // in input TInts and in keystring. KNumOfParams is maximum number of
       
    48 // parameters in the resource string.
       
    49 const TInt KIntSize(11); //Max 11 digits.
       
    50 const TInt KNumOfParams(20); //Max 20 parameters
       
    51 
       
    52 // Key strings for number and unicode data.
       
    53 _LIT(KNumKeyBuf, "%N"); //Number data
       
    54 _LIT(KStringKeyBuf, "%U"); //Unicode data
       
    55 
       
    56 // KUnknownCount is used as default value for param count in FormatStringL
       
    57 const TInt KUnknownCount(-99);
    23 
    58 
    24 EXPORT_C CResourceLoader* CResourceLoader::NewL( const TDesC& aName )
    59 EXPORT_C CResourceLoader* CResourceLoader::NewL( const TDesC& aName )
    25     {
    60     {
    26     CResourceLoader* temp = new( ELeave ) CResourceLoader();
    61     CResourceLoader* temp = new( ELeave ) CResourceLoader();
    27     CleanupStack::PushL( temp );
    62     CleanupStack::PushL( temp );
    52 EXPORT_C RFs& CResourceLoader::Fs() 
    87 EXPORT_C RFs& CResourceLoader::Fs() 
    53     {
    88     {
    54     return iFs;
    89     return iFs;
    55     }
    90     }
    56 
    91 
    57 EXPORT_C HBufC* CResourceLoader::LoadLC(TInt aResourceId)
    92 EXPORT_C HBufC* CResourceLoader::LoadLC( TInt aResourceId )
    58     {
    93     {
    59     TResourceReader reader;
    94     TResourceReader reader;
    60     HBufC8* readBuffer = CreateResourceReaderLC( reader, aResourceId );
    95     HBufC8* readBuffer = CreateResourceReaderLC( reader, aResourceId );
    61     TPtrC textdata = reader.ReadTPtrC();
    96     TPtrC textdata = reader.ReadTPtrC();
    62     
    97     
    63     HBufC16* textBuffer = HBufC16::NewL( textdata.Length() );
    98     HBufC16* textBuffer = HBufC16::NewL( textdata.Length() );
    64     *textBuffer = textdata;
    99     *textBuffer = textdata;
    65     CleanupStack::PopAndDestroy(readBuffer);
   100     CleanupStack::PopAndDestroy( readBuffer );
    66     CleanupStack::PushL( textBuffer );
   101     CleanupStack::PushL( textBuffer );
    67     return textBuffer;
   102     return textBuffer;
       
   103     }
       
   104 
       
   105 EXPORT_C HBufC* CResourceLoader::Load2L( TInt aResourceId )
       
   106     {
       
   107     HBufC8* readBuffer = iResFile.AllocReadLC( aResourceId );
       
   108     const TPtrC16 ptrReadBuffer( ( TText16* ) readBuffer->Ptr(), ( readBuffer->Length()+1 )>>1 );
       
   109     HBufC16* textBuffer=HBufC16::NewL( ptrReadBuffer.Length() );
       
   110     *textBuffer=ptrReadBuffer;
       
   111     CleanupStack::PopAndDestroy( readBuffer );
       
   112     return textBuffer;
       
   113     }
       
   114 
       
   115 EXPORT_C HBufC* CResourceLoader::Load2LC( TInt aResourceId )
       
   116     {
       
   117     HBufC* retbuf = Load2L( aResourceId );
       
   118     CleanupStack::PushL( retbuf );
       
   119     return retbuf;
       
   120     }
       
   121 
       
   122 EXPORT_C HBufC* CResourceLoader::Load2L( TInt aResourceId, const TDesC& aString )
       
   123     {
       
   124     HBufC* resbuf = Load2LC( aResourceId );
       
   125     TPtr retptr(resbuf->Des());
       
   126         
       
   127     // Get number of sub strings
       
   128     TInt count = GetSubStringCount( retptr ); 
       
   129     TBool marker(EFalse); 
       
   130     
       
   131     if (count >= 1)
       
   132         {
       
   133         HBufC* buffer = ResolveSubStringDirsL( retptr, count, &marker );
       
   134         CleanupStack::PushL(buffer);
       
   135         
       
   136         TBool found(EFalse);
       
   137         TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found);
       
   138         
       
   139         //Formating the return string with FormatStringL.
       
   140         HBufC* retbuf = FormatStringL(*buffer, KStringKeyBuf, aString, mainDir);
       
   141         
       
   142         CleanupStack::PopAndDestroy(buffer);
       
   143         CleanupStack::PopAndDestroy(resbuf);
       
   144                         
       
   145         if (marker && retbuf->Length())
       
   146             {
       
   147             TPtr ptr = retbuf->Des();
       
   148             RemoveNoDirMarkers(ptr);
       
   149             } 
       
   150             
       
   151         __ASSERT_DEBUG(retbuf->Length(), 
       
   152                     User::Panic(KPanicCategory, EKeyStringNotFound));    
       
   153         return retbuf;
       
   154         }
       
   155      else
       
   156         {
       
   157         CleanupStack::PopAndDestroy(resbuf);
       
   158         HBufC* retbuf = HBufC::NewL(0); // return empty buffer
       
   159         __ASSERT_DEBUG(retbuf->Length(), 
       
   160                     User::Panic(KPanicCategory, EKeyStringNotFound));
       
   161         return retbuf;
       
   162         }
       
   163     }
       
   164 
       
   165 EXPORT_C HBufC* CResourceLoader::Load2LC( TInt aResourceId, const TDesC& aString )
       
   166     {
       
   167     HBufC* retbuf = Load2L( aResourceId, aString );
       
   168     CleanupStack::PushL( retbuf );
       
   169     return retbuf;
       
   170     }
       
   171 
       
   172 EXPORT_C HBufC* CResourceLoader::Load2L(TInt aResourceId, TInt aInt )
       
   173     {
       
   174     HBufC* resbuf = Load2LC( aResourceId );
       
   175     TPtr retptr = resbuf->Des();
       
   176     //
       
   177     //Converting input TInt to a descriptor. This way the size
       
   178     //of the return string can be controlled.
       
   179     //
       
   180     TBuf<KIntSize> intbuf;
       
   181     intbuf.Num(aInt);
       
   182 
       
   183     if (LanguageSpecificNumberConverter::IsConversionNeeded())
       
   184         LanguageSpecificNumberConverter::Convert(intbuf);
       
   185     //
       
   186     // Get number of sub strings
       
   187     TInt count = GetSubStringCount(retptr); 
       
   188     TBool marker(EFalse); 
       
   189     
       
   190     if (count >= 1)
       
   191         {
       
   192         HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker);
       
   193         CleanupStack::PushL(buffer);
       
   194         
       
   195         TBool found(EFalse);
       
   196         TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found);
       
   197         
       
   198         //Adding int    
       
   199         HBufC* retbuf = FormatStringL(*buffer, KNumKeyBuf, intbuf, mainDir);
       
   200         
       
   201         CleanupStack::PopAndDestroy(buffer);
       
   202         CleanupStack::PopAndDestroy(resbuf);
       
   203                         
       
   204         if (marker && retbuf->Length())
       
   205             {
       
   206             TPtr ptr = retbuf->Des();
       
   207             RemoveNoDirMarkers(ptr);
       
   208             } 
       
   209         __ASSERT_DEBUG(retbuf->Length(), 
       
   210                     User::Panic(KPanicCategory, EKeyStringNotFound));
       
   211         return retbuf;
       
   212         }
       
   213      else
       
   214         {
       
   215         CleanupStack::PopAndDestroy(resbuf);
       
   216         HBufC* retbuf = HBufC::NewL(0); // return empty buffer
       
   217         __ASSERT_DEBUG(retbuf->Length(), 
       
   218                     User::Panic(KPanicCategory, EKeyStringNotFound));
       
   219         return retbuf;
       
   220         }
       
   221     }
       
   222 
       
   223 EXPORT_C HBufC* CResourceLoader::Load2LC( TInt aResourceId, TInt aInt )
       
   224     {
       
   225     HBufC* retbuf = Load2L( aResourceId, aInt );
       
   226     CleanupStack::PushL( retbuf );
       
   227     return retbuf;
    68     }
   228     }
    69 
   229 
    70 EXPORT_C HBufC8* CResourceLoader::CreateResourceReaderLC(TResourceReader& aReader,TInt aResourceId) const
   230 EXPORT_C HBufC8* CResourceLoader::CreateResourceReaderLC(TResourceReader& aReader,TInt aResourceId) const
    71     {
   231     {
    72     HBufC8* readBuffer = iResFile.AllocReadLC( aResourceId );
   232     HBufC8* readBuffer = iResFile.AllocReadLC( aResourceId );
    73     aReader.SetBuffer( readBuffer );
   233     aReader.SetBuffer( readBuffer );
    74     return readBuffer;
   234     return readBuffer;
    75     }
   235     }
    76         
   236         
       
   237 /**
       
   238 Counts the number of substrings (separated by KSubStringSeparators) in the text. 
       
   239 Needed for correct memory allocations.
       
   240 */
       
   241 TInt CResourceLoader::GetSubStringCount(const TDesC& aText)
       
   242     {
       
   243     TInt subCount = 0;
       
   244     TInt i = 0;
       
   245 
       
   246     while (i < aText.Length())
       
   247         {
       
   248         TPtrC remainder = aText.Right(aText.Length() - i);
       
   249         TInt nextKey = remainder.Locate(KSubStringSeparator);
       
   250         i += nextKey;
       
   251 
       
   252         // Always increase subcount, as a string without any separators counts as one substring.
       
   253         // However, if string length is zero, then there are no substrings.
       
   254         subCount++;
       
   255 
       
   256         if (nextKey != KErrNotFound && i < aText.Length() - 1)
       
   257             {
       
   258             i++; // skip separator
       
   259             }
       
   260         else
       
   261             break;
       
   262         }
       
   263 
       
   264     return subCount;
       
   265     }
       
   266 
       
   267 HBufC* CResourceLoader::ResolveSubStringDirsL(TDes& aText, TInt aCount, TBool* aMarker)
       
   268     {   
       
   269     // Allocating heap buffer for return string.
       
   270     TInt destlength(aText.Length());
       
   271     destlength = destlength + (KExtraSpaceForMainStringDirMarker) * aCount;
       
   272     HBufC* retbuf = HBufC::NewLC(destlength);
       
   273     TPtr retptr(retbuf->Des());
       
   274     TInt freeSpace(destlength); 
       
   275     TInt i(0);
       
   276     TInt j(0);
       
   277     TBuf<1> subsMarker;
       
   278     subsMarker.Append(KSubStringSeparator);
       
   279     TInt count(aCount - 1);
       
   280 
       
   281     while (i  < aCount)
       
   282         {
       
   283         // Resolve sub string
       
   284         HBufC* buffer = ResolveSubStringL(aText, aMarker);
       
   285         TPtr ptr = buffer->Des();
       
   286         CleanupStack::PushL(buffer); 
       
   287         
       
   288         // Restore sub string separators
       
   289         if (freeSpace >= ptr.Length()) 
       
   290             {
       
   291             retptr.Insert(j, ptr);
       
   292             freeSpace -= ptr.Length();
       
   293             j += ptr.Length();
       
   294             if (freeSpace > KExtraSpaceForMainStringDirMarker && i < count)
       
   295                 {
       
   296                 retptr.Append(subsMarker);
       
   297                 j ++;
       
   298                 }
       
   299             }    
       
   300         CleanupStack::PopAndDestroy(buffer);  
       
   301         i++;                       
       
   302         } 
       
   303     
       
   304     retbuf = retbuf->ReAllocL(retptr.Length());
       
   305     CleanupStack::Pop(); //retbuf  
       
   306     return retbuf;
       
   307     }
       
   308 
       
   309 TBidiText::TDirectionality CResourceLoader::DirectionalityL(const TDesC& aText, TBool* aFound)
       
   310     {
       
   311     // Resolve directionality of sub string
       
   312     HBufC* dirbuf = aText.AllocL();
       
   313     TPtr dirptr = dirbuf->Des();
       
   314     TBidiText::TDirectionality dir = ResolveDirectionality(dirptr, aFound);
       
   315     delete dirbuf;
       
   316     return dir;
       
   317     }
       
   318     
       
   319 /**
       
   320 Resolves directionality of the given source text.
       
   321 Place-holder strings are removed so that they don't affect the result.
       
   322 */
       
   323 TBidiText::TDirectionality CResourceLoader::ResolveDirectionality(TDes& aText, TBool* aFound)
       
   324     {
       
   325     TInt i = 0;
       
   326 
       
   327     // Remove place-holders from string so they don't affect directionality
       
   328     // length parameters e.g. "[29]" do not contain strongly directional
       
   329     // characters so can ignore them.
       
   330     while (i < aText.Length())
       
   331         {
       
   332         TPtrC remainder = aText.Right(aText.Length() - i);
       
   333         TInt nextKey = remainder.Locate(KKeyPrefix);
       
   334         i += nextKey;
       
   335 
       
   336         if (nextKey != KErrNotFound && i < aText.Length() - 1)
       
   337             {
       
   338             TInt lastCharInKey = i + 1;
       
   339 
       
   340             // skip possible key index
       
   341             TText t = aText[lastCharInKey];
       
   342             if (t >= '0' && t <= '9')
       
   343                 {
       
   344                 lastCharInKey++;
       
   345 
       
   346                 if (lastCharInKey < aText.Length())
       
   347                     {
       
   348                     t = aText[lastCharInKey];
       
   349                     if (t >= '0' && t <= '9')
       
   350                         {
       
   351                         lastCharInKey++;
       
   352                         }
       
   353                     }
       
   354                 }
       
   355 
       
   356             // lastCharInKey is now the index of 'N' or 'U' in the key
       
   357 
       
   358             if (lastCharInKey < aText.Length())
       
   359                 {
       
   360                 TText t = aText[lastCharInKey];
       
   361                 if (t == 'U' || t == 'N')
       
   362                     {
       
   363                     // found key, delete it and continue loop to
       
   364                     // search for the next key
       
   365                     aText.Delete(i, lastCharInKey - i + 1);
       
   366                     }
       
   367                 // This was not a proper key - check the remaining string
       
   368                 else
       
   369                     {
       
   370                     i = lastCharInKey + 1;
       
   371                     }
       
   372                 }
       
   373             // end of string encountered - stop
       
   374             else
       
   375                 {
       
   376                 break;
       
   377                 }
       
   378             }
       
   379         // no key found - stop
       
   380         else
       
   381             {
       
   382             break;
       
   383             }
       
   384         }
       
   385 
       
   386     return TBidiText::TextDirectionality(aText, aFound);
       
   387     }
       
   388 
       
   389 /**
       
   390 Finds the keystring from the source string and replaces it with the
       
   391 replacement string.
       
   392 */
       
   393 HBufC* CResourceLoader::FormatStringL(const TDesC& aSource, const TDesC& aKey, const TDesC& aSubs,TBidiText::TDirectionality aDir)
       
   394     {
       
   395     TInt paramCount(KUnknownCount); // variable needed as it may be updated
       
   396     return FormatStringL(aSource, aKey, aSubs, aDir, paramCount, KUnknownCount);
       
   397     }
       
   398 
       
   399 /**
       
   400 Finds the keystring from the source string and replaces it with the
       
   401 replacement string.
       
   402 */
       
   403 HBufC* CResourceLoader::FormatStringL(const TDesC& aSource, const TDesC& aKey, const TDesC& aSubs, TBidiText::TDirectionality aDirectionality,
       
   404     TInt& aParamCount, TInt aSubCount)
       
   405     {
       
   406     if (aParamCount == KUnknownCount)
       
   407         aParamCount = GetParamCount(aSource);
       
   408 
       
   409     if (aSubCount == KUnknownCount)
       
   410         aSubCount = GetSubStringCount(aSource);
       
   411 
       
   412     // determine lenght of needed buffer 
       
   413     TInt sourcelength(aSource.Length()); 
       
   414     TInt keylength(aKey.Length());
       
   415     TInt subslength(aSubs.Length());
       
   416     TInt destlength = 0;
       
   417     if (subslength >= keylength)
       
   418         {
       
   419         destlength = sourcelength + ((subslength - keylength) * aParamCount);
       
   420         }
       
   421     else
       
   422         {
       
   423         destlength = sourcelength;
       
   424         }
       
   425 
       
   426     destlength += KExtraSpaceForMainStringDirMarker * aSubCount;
       
   427     destlength += KExtraSpaceForSubStringDirMarkers * aParamCount;
       
   428     //
       
   429     // Allocating heap buffer for return string.
       
   430     //
       
   431 
       
   432     HBufC* retbuf = HBufC::NewL(destlength);
       
   433     TPtr retptr(retbuf->Des());
       
   434 
       
   435     // Formating the resource string. Don't bother with format, 
       
   436     // if parameter count is not above zero
       
   437     if (aParamCount > 0)
       
   438         {
       
   439         aParamCount -= Formater(retptr, aSource, aKey, aSubs, aDirectionality);
       
   440         __ASSERT_DEBUG(aParamCount >= 0, User::Invariant());
       
   441         }
       
   442 
       
   443     //
       
   444     // If the key string wasn't found, retbuf is empty.
       
   445     //
       
   446     return retbuf; 
       
   447     }
       
   448 
       
   449 /**
       
   450 Finds the keystring from the source string and replaces it with the
       
   451 replacement string. The formated string is stored in the destination
       
   452 descriptor.
       
   453 */
       
   454 TInt CResourceLoader::Formater(TDes& aDest, const TDesC& aSource, const TDesC& aKey, const TDesC& aSubs, TBidiText::TDirectionality aDirectionality)    
       
   455     {
       
   456     // substitute string must not contain KSubStringSeparator, 
       
   457     // or results will be unpredictable 
       
   458     __ASSERT_DEBUG(aSubs.Locate(KSubStringSeparator) == KErrNotFound, 
       
   459         User::Panic(KPanicCategory, EInvalidSubstitute));
       
   460 
       
   461     TInt keylength(aKey.Length());
       
   462 
       
   463     //aDest must be empty.
       
   464     aDest.Zero();
       
   465 
       
   466     // offset indicates end of last handled key in source
       
   467     TInt offset(0);
       
   468 
       
   469     // offset in destination string
       
   470     TInt desOffset(0);
       
   471 
       
   472     // Substring directionalities are adjusted after all changes are done.
       
   473     TBool checkSubstringDirectionalities(EFalse);
       
   474 
       
   475     // count is the position in the source from which the substring starts
       
   476     TInt count(0);
       
   477 
       
   478     // Replaced parameters count
       
   479     TInt replaceCount(0);
       
   480 
       
   481     while (count != KErrNotFound)
       
   482         {
       
   483         // desCount is the position of the substring starts in destination.
       
   484         TInt desCount(0);
       
   485 
       
   486         TPtrC remainder = aSource.Right(aSource.Length() - offset);
       
   487         count = remainder.Find(aKey);
       
   488 
       
   489         TInt maxSubLength = -1;
       
   490         if (count != KErrNotFound)
       
   491             {
       
   492             replaceCount++;
       
   493             desOffset += count;
       
   494             offset += count;
       
   495             count = offset;
       
   496             desCount = desOffset;
       
   497 
       
   498             // copy source to destination if first time
       
   499             if (aDest.Length() == 0)
       
   500                 aDest.Append(aSource);
       
   501 
       
   502             // delete found key from destination
       
   503             aDest.Delete(desCount, keylength);
       
   504 
       
   505             offset += keylength; // increase offset by key length
       
   506 
       
   507             if (count + keylength < (aSource.Length()-1)) // aKey is not at the end of string
       
   508                 {
       
   509                 if (aSource[count+keylength] == '[') // Key includes max datalength
       
   510                     {
       
   511                     maxSubLength = 10*(aSource[count+keylength+1]-'0') 
       
   512                                    + (aSource[count+keylength+2]-'0');
       
   513                     aDest.Delete(desCount,4); // Length information stored->delete from descriptor
       
   514                     offset += 4; // increase offset by max sub length indicator
       
   515                     }
       
   516                 }
       
   517          
       
   518             aDest.Insert(desCount, aSubs);
       
   519         
       
   520             desOffset = desCount + aSubs.Length();
       
   521 
       
   522             if (maxSubLength > 0 && aSubs.Length() > maxSubLength)
       
   523                 {
       
   524                 aDest.Delete(desCount+maxSubLength-1, aSubs.Length()+1-maxSubLength);     
       
   525                 TText ellipsis(KEllipsis);
       
   526                 aDest.Insert(desCount+maxSubLength-1, TPtrC(&ellipsis,1));
       
   527                 desOffset = desCount + maxSubLength;
       
   528                 }
       
   529 
       
   530             TBidiText::TDirectionality subsDir =
       
   531                 TBidiText::TextDirectionality(aDest.Mid(desCount, desOffset - desCount));
       
   532 
       
   533             // If inserted string has different directionality,
       
   534             // insert directionality markers so that bidi algorithm works in a desired way.
       
   535             if (aDirectionality != subsDir)
       
   536                 {
       
   537                 checkSubstringDirectionalities = ETrue;
       
   538 
       
   539                 TInt freeSpace = aDest.MaxLength() - aDest.Length();
       
   540 
       
   541                 // Protect the directionality of the inserted string.
       
   542                 if (freeSpace >= KExtraSpaceForSubStringDirMarkers)
       
   543                     {
       
   544                     TBuf<1> subsMarker;
       
   545                     subsMarker.Append(subsDir == TBidiText::ELeftToRight ?
       
   546                         KLRMarker : KRLMarker);
       
   547 
       
   548                     aDest.Insert(desOffset, subsMarker);
       
   549                     aDest.Insert(desCount, subsMarker);
       
   550                     desOffset += KExtraSpaceForSubStringDirMarkers;
       
   551                     }
       
   552                 }
       
   553             }
       
   554         }
       
   555 
       
   556     // Adjust substring directionality markers if necessary
       
   557     // and if there is enough room in destination string
       
   558     if (checkSubstringDirectionalities)
       
   559         {
       
   560         TText mainMarker = (aDirectionality == TBidiText::ELeftToRight ? 
       
   561             KLRMarker : KRLMarker);
       
   562 
       
   563         TInt freeSpace = aDest.MaxLength() - aDest.Length();
       
   564 
       
   565         // If not already done, protect the directionality of the original string
       
   566         // and all of the KSubStringSeparator separated substrings.
       
   567         if (freeSpace > 0 
       
   568             && aDest.Length()
       
   569             && aDest[0] != mainMarker 
       
   570             && aDest[0] != KSubStringSeparator
       
   571             && aDest[0] != KDirNotFound)  
       
   572             {
       
   573             aDest.Insert(0, TPtrC(&mainMarker, 1));
       
   574             freeSpace--;
       
   575             }
       
   576 
       
   577         // Find and protect KSubStringSeparator separated substrings.
       
   578         // Go through string backwards so that any changes will not affect indexes 
       
   579         // that are not yet checked.
       
   580         TInt j(aDest.Length()-1);
       
   581         while (freeSpace > 0 && j >= 0) 
       
   582             {
       
   583             if (aDest[j] == KSubStringSeparator && j < (aDest.Length() - 1) 
       
   584                 && aDest[j+1] != mainMarker && aDest[j+1] != KDirNotFound)
       
   585                 {
       
   586                 aDest.Insert(j+1, TPtrC(&mainMarker, 1));
       
   587                 freeSpace--;
       
   588                 }
       
   589             j--;
       
   590             }
       
   591         }
       
   592 
       
   593     return replaceCount;
       
   594     }
       
   595 
       
   596 /**
       
   597 Counts the number of parameters in the text. 
       
   598 Needed for correct memory allocations.
       
   599 */
       
   600 TInt CResourceLoader::GetParamCount(const TDesC& aText, TInt aIndex)
       
   601     {
       
   602     TInt paramCount(0);
       
   603     TInt i(0);
       
   604     TBool singleIndex((aIndex < 0) || (aIndex > KNumOfParams) ? EFalse : ETrue);
       
   605 
       
   606     while (i < aText.Length())
       
   607         {
       
   608         TPtrC remainder = aText.Right(aText.Length() - i);
       
   609         TInt nextKey = remainder.Locate(KKeyPrefix);
       
   610         i += nextKey;
       
   611 
       
   612         if (nextKey != KErrNotFound && i < aText.Length() - 1)
       
   613             {
       
   614             TInt lastCharInKey = i + 1;
       
   615 
       
   616             // skip possible key index
       
   617             TText t = aText[lastCharInKey];
       
   618             TInt foundIndex(-1);
       
   619             
       
   620             if (t >= '0' && t <= '9')
       
   621                 {
       
   622                 lastCharInKey++;
       
   623                 foundIndex = t - '0';
       
   624 
       
   625                 if (lastCharInKey < aText.Length())
       
   626                     {
       
   627                     t = aText[lastCharInKey];
       
   628                     if (t >= '0' && t <= '9')
       
   629                         {
       
   630                         foundIndex *= 10;
       
   631                         foundIndex += t - '0';
       
   632                         lastCharInKey++;
       
   633                         }
       
   634                     }
       
   635                 }
       
   636 
       
   637             // lastCharInKey is now the index of 'N' or 'U' in the key
       
   638 
       
   639             if (lastCharInKey < aText.Length())
       
   640                 {
       
   641                 // Only count parameter, if index matches
       
   642                 if (!singleIndex || (foundIndex == aIndex))
       
   643                     {
       
   644                     TText t = aText[lastCharInKey];
       
   645                     if (t == 'U' || t == 'N')
       
   646                         {
       
   647                         // found legit key, count it
       
   648                         paramCount++;
       
   649                         // continue search after index
       
   650                         i = lastCharInKey + 1;
       
   651                         }
       
   652                     else if (t == '%')
       
   653                         i = lastCharInKey;
       
   654                     else    // continue search after index
       
   655                         i = lastCharInKey + 1;
       
   656                     }
       
   657                 else    // continue search after index
       
   658                     i = lastCharInKey + 1;
       
   659                 }
       
   660             else    // end of string encountered - stop
       
   661                 break;
       
   662             }
       
   663         else     // no key found - stop
       
   664             break;
       
   665         }
       
   666 
       
   667     return paramCount;
       
   668     }
       
   669 
       
   670 /**
       
   671 Resolves sub string and directionality of the sub string.
       
   672 Adds no dir marker if directionality of the string not found.
       
   673 */
       
   674 HBufC* CResourceLoader::ResolveSubStringL(TDes& aText, TBool* aMarker)
       
   675     {
       
   676     // Allocating heap buffer for return string.
       
   677     TInt destlength(aText.Length());
       
   678     HBufC* retbuf = HBufC::NewLC(destlength + 1); // no dir marker
       
   679     TPtr retptr(retbuf->Des());
       
   680     
       
   681     TBuf<1> marker;
       
   682     marker.Append(KDirNotFound);
       
   683         
       
   684     TPtrC remainder = aText.Right(aText.Length());
       
   685     TInt nextKey = remainder.Locate(KSubStringSeparator);
       
   686     
       
   687     if (nextKey == 0)
       
   688         {
       
   689         remainder.Set(remainder.Mid(1));
       
   690         nextKey = remainder.Locate(KSubStringSeparator);
       
   691         if (nextKey != KErrNotFound)
       
   692             {
       
   693             retptr.Insert(0, aText.Mid(1, nextKey));           
       
   694             // Remove string from aText
       
   695             aText.Delete(0, nextKey + 1);
       
   696             }
       
   697         else
       
   698             {
       
   699             TInt length = aText.Length();
       
   700             retptr.Insert(0, aText.Mid(1, length - 1));
       
   701             // Remove string from aText
       
   702             aText.Delete(0, length);
       
   703             }
       
   704         }
       
   705     else if (nextKey == KErrNotFound)
       
   706         {
       
   707         retptr.Insert(0, aText); 
       
   708         // Remove string from aText
       
   709         aText.Delete(0, aText.Length());
       
   710         }
       
   711     else
       
   712         {
       
   713         retptr.Insert(0, aText.Mid(0, nextKey));
       
   714         // Remove string from aText
       
   715         aText.Delete(0, nextKey);
       
   716         }
       
   717      
       
   718     // Resolve directionality of sub string
       
   719     HBufC* dirbuf = retbuf->AllocL();
       
   720     TPtr dirptr = dirbuf->Des();
       
   721     TBool found(EFalse);
       
   722     TBidiText::TDirectionality mainDir = ResolveDirectionality(dirptr, &found);
       
   723     delete dirbuf;
       
   724     
       
   725     if (!found)
       
   726         {
       
   727         retptr.Insert(0, marker);
       
   728         *aMarker = ETrue;
       
   729         }
       
   730     else
       
   731         {
       
   732         *aMarker = EFalse;
       
   733         }
       
   734         
       
   735     retbuf = retbuf->ReAllocL(retptr.Length());
       
   736     CleanupStack::Pop(); //retbuf
       
   737     // If the key string wasn't found, retbuf is empty.
       
   738     return retbuf;     
       
   739     }
       
   740     
       
   741 /**
       
   742 Removes no dir markers from source text.
       
   743 */
       
   744 void CResourceLoader::RemoveNoDirMarkers(TDes& aText)
       
   745     {
       
   746     TInt nextkey(0);
       
   747     while (nextkey < aText.Length())
       
   748         {
       
   749         nextkey = aText.Locate(KDirNotFound);
       
   750         if (nextkey != KErrNotFound)
       
   751             {
       
   752             aText.Delete(nextkey, 1);
       
   753             nextkey++;    
       
   754             }
       
   755         else
       
   756             {
       
   757             break;
       
   758             }     
       
   759         }
       
   760     }
       
   761     
       
   762 // ============================ MEMBER FUNCTIONS ===============================
       
   763 
       
   764 static TChar NumberToBase(const TChar& aCharacter )
       
   765     {
       
   766     const TDigitType d[] = { EDigitTypeWestern, 
       
   767                        EDigitTypeArabicIndic, 
       
   768                        EDigitTypeEasternArabicIndic, 
       
   769                        EDigitTypeDevanagari, 
       
   770                        EDigitTypeThai };
       
   771     
       
   772     const TInt num = sizeof( d ) / sizeof( d[0] );
       
   773     
       
   774     TInt i = 0;
       
   775     while( i < num )
       
   776         {
       
   777         if (aCharacter > TChar( d[i] ) && aCharacter < TChar( d[i]+10 )) 
       
   778             return d[i];
       
   779         
       
   780         i++;
       
   781         }
       
   782         
       
   783     return aCharacter;
       
   784     }
       
   785 
       
   786 /**
       
   787 This routine is used to convert between European digits and 
       
   788 Arabic-Indic, Eastern Arabic-Indic, Devanagari or Thai digits 
       
   789 based on existing digit type setting. 
       
   790 
       
   791 @param aDes  Parameter to change
       
   792 */
       
   793 void CResourceLoader::LanguageSpecificNumberConverter::Convert( TDes &aDes )
       
   794     {   
       
   795     TLocale locale;
       
   796     locale.Refresh();
       
   797     const TDigitType digitType = locale.DigitType();
       
   798     TChar toArea = 0x030;
       
   799     switch( digitType )
       
   800         {
       
   801         case EDigitTypeWestern:
       
   802         case EDigitTypeArabicIndic:
       
   803         case EDigitTypeEasternArabicIndic:
       
   804         case EDigitTypeDevanagari:
       
   805         case EDigitTypeThai:
       
   806             toArea = digitType;
       
   807             break;
       
   808         case EDigitTypeUnknown:
       
   809         case EDigitTypeAllTypes:
       
   810             return;
       
   811         }
       
   812     
       
   813     const TInt length = aDes.Length();
       
   814     for( TInt i = 0; i < length; i++ )
       
   815         {
       
   816         TChar character = aDes[i];
       
   817         TChar fromArea = NumberToBase( character );
       
   818         TChar::TBdCategory cat = character.GetBdCategory();
       
   819         switch( cat )
       
   820             {
       
   821             case TChar::EArabicNumber:
       
   822             case TChar::EEuropeanNumber:
       
   823                 character += toArea;
       
   824                 character -= fromArea;
       
   825                 aDes[i] = TUint16( character );
       
   826                 break;
       
   827             default: 
       
   828                 break;
       
   829             }
       
   830         }
       
   831     }
       
   832 
       
   833 /**
       
   834 This routine is used to convert Arabic-Indic, Eastern Arabic-Indic
       
   835 or Devanagari digits to European digits. 
       
   836 
       
   837 @param aDes Parameter to change
       
   838 */
       
   839 void CResourceLoader::LanguageSpecificNumberConverter::ConvertToWesternNumbers( TDes &aDes )
       
   840     {   
       
   841     const TChar toArea = 0x030;
       
   842     const TInt KLastDevanagariDigit = 0x96F;
       
   843     const TInt KFirstDevanagariDigit = 0x966;
       
   844     const TInt length = aDes.Length();
       
   845 
       
   846     for( TInt i=0; i<length; i++ )
       
   847         {
       
   848         TChar character = aDes[i];
       
   849         TChar fromArea = NumberToBase( character );
       
   850         TChar::TBdCategory cat = character.GetBdCategory();
       
   851 
       
   852         if ( cat == TChar::EArabicNumber || cat == TChar::EEuropeanNumber ||
       
   853            ( KFirstDevanagariDigit <= character && character <= KLastDevanagariDigit ) )
       
   854             {
       
   855             character += toArea;
       
   856             character -= fromArea;
       
   857             aDes[i] = TUint16( character );    
       
   858             }        
       
   859         }
       
   860     }
       
   861 
       
   862 /**
       
   863 This routine is used to check if conversion of digits is needed.
       
   864 Conversion is needed if user language is   
       
   865 - Arabic, Urdu or Farsi and if digit type is Arabic-Indic
       
   866 - Urdu or Farsi and digit type is Eastern Arabic_indic
       
   867 - Hindi and digit type is Devanagari. 
       
   868 
       
   869 @return  ETrue if conversion is needed, EFalse if not
       
   870 */
       
   871 TBool CResourceLoader::LanguageSpecificNumberConverter::IsConversionNeeded()
       
   872     {
       
   873     TLocale locale;
       
   874     locale.Refresh();
       
   875     const TLanguage language = User::Language();
       
   876     const TDigitType digitType = locale.DigitType();
       
   877     
       
   878     if ( ( ( language == ELangArabic || language == ELangUrdu || language == ELangFarsi ) &&
       
   879          digitType == EDigitTypeArabicIndic ) 
       
   880          || ( ( language == ELangUrdu || language == ELangFarsi ) &&
       
   881          digitType == EDigitTypeEasternArabicIndic )
       
   882          || ( language == ELangHindi && digitType == EDigitTypeDevanagari )
       
   883         )
       
   884         {
       
   885         return ETrue;
       
   886         }
       
   887 
       
   888     return EFalse;
       
   889     }
       
   890