diff -r a3a1ae9acec6 -r da5135c61bad emailservices/emailstore/base_plugin/src/basepluginresourceloader.cpp --- a/emailservices/emailstore/base_plugin/src/basepluginresourceloader.cpp Mon Mar 15 12:39:10 2010 +0200 +++ b/emailservices/emailstore/base_plugin/src/basepluginresourceloader.cpp Wed Mar 31 21:08:33 2010 +0300 @@ -17,10 +17,45 @@ */ + #include #include +#include +#include + #include "basepluginresourceloader.h" +// panic category constant +#ifdef _DEBUG +_LIT( KPanicCategory, "CResourceLoader" ); +#endif + +// CP1252 ellipsis character value. +#define KEllipsis 0x2026 // cp1252=133 + +// Key characters to format key strings. +const TText KKeyPrefix('%'); +const TText KSubStringSeparator(0x0001); // pipe ('|') character +const TText KDirNotFound( 0x0002 ); + +const TInt KExtraSpaceForMainStringDirMarker = 1; +const TInt KExtraSpaceForSubStringDirMarkers = 2; +const TText KLRMarker = 0x200E; +const TText KRLMarker = 0x200F; + +// 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 + +// Key strings for number and unicode data. +_LIT(KNumKeyBuf, "%N"); //Number data +_LIT(KStringKeyBuf, "%U"); //Unicode data + +// KUnknownCount is used as default value for param count in FormatStringL +const TInt KUnknownCount(-99); + EXPORT_C CResourceLoader* CResourceLoader::NewL( const TDesC& aName ) { CResourceLoader* temp = new( ELeave ) CResourceLoader(); @@ -54,7 +89,7 @@ return iFs; } -EXPORT_C HBufC* CResourceLoader::LoadLC(TInt aResourceId) +EXPORT_C HBufC* CResourceLoader::LoadLC( TInt aResourceId ) { TResourceReader reader; HBufC8* readBuffer = CreateResourceReaderLC( reader, aResourceId ); @@ -62,11 +97,136 @@ HBufC16* textBuffer = HBufC16::NewL( textdata.Length() ); *textBuffer = textdata; - CleanupStack::PopAndDestroy(readBuffer); + CleanupStack::PopAndDestroy( readBuffer ); CleanupStack::PushL( textBuffer ); return textBuffer; } +EXPORT_C HBufC* CResourceLoader::Load2L( TInt aResourceId ) + { + HBufC8* readBuffer = iResFile.AllocReadLC( aResourceId ); + const TPtrC16 ptrReadBuffer( ( TText16* ) readBuffer->Ptr(), ( readBuffer->Length()+1 )>>1 ); + HBufC16* textBuffer=HBufC16::NewL( ptrReadBuffer.Length() ); + *textBuffer=ptrReadBuffer; + CleanupStack::PopAndDestroy( readBuffer ); + return textBuffer; + } + +EXPORT_C HBufC* CResourceLoader::Load2LC( TInt aResourceId ) + { + HBufC* retbuf = Load2L( aResourceId ); + CleanupStack::PushL( retbuf ); + return retbuf; + } + +EXPORT_C HBufC* CResourceLoader::Load2L( TInt aResourceId, const TDesC& aString ) + { + HBufC* resbuf = Load2LC( aResourceId ); + 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; + } + } + +EXPORT_C HBufC* CResourceLoader::Load2LC( TInt aResourceId, const TDesC& aString ) + { + HBufC* retbuf = Load2L( aResourceId, aString ); + CleanupStack::PushL( retbuf ); + return retbuf; + } + +EXPORT_C HBufC* CResourceLoader::Load2L(TInt aResourceId, TInt aInt ) + { + HBufC* resbuf = Load2LC( aResourceId ); + TPtr retptr = resbuf->Des(); + // + //Converting input TInt to a descriptor. This way the size + //of the return string can be controlled. + // + TBuf intbuf; + intbuf.Num(aInt); + + if (LanguageSpecificNumberConverter::IsConversionNeeded()) + LanguageSpecificNumberConverter::Convert(intbuf); + // + // Get number of sub strings + TInt count = GetSubStringCount(retptr); + TBool marker(EFalse); + + if (count >= 1) + { + HBufC* buffer = ResolveSubStringDirsL(retptr, count, &marker); + CleanupStack::PushL(buffer); + + TBool found(EFalse); + TBidiText::TDirectionality mainDir = DirectionalityL(*buffer , &found); + + //Adding int + HBufC* retbuf = FormatStringL(*buffer, KNumKeyBuf, intbuf, mainDir); + + CleanupStack::PopAndDestroy(buffer); + CleanupStack::PopAndDestroy(resbuf); + + if (marker && retbuf->Length()) + { + TPtr ptr = retbuf->Des(); + RemoveNoDirMarkers(ptr); + } + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + else + { + CleanupStack::PopAndDestroy(resbuf); + HBufC* retbuf = HBufC::NewL(0); // return empty buffer + __ASSERT_DEBUG(retbuf->Length(), + User::Panic(KPanicCategory, EKeyStringNotFound)); + return retbuf; + } + } + +EXPORT_C HBufC* CResourceLoader::Load2LC( TInt aResourceId, TInt aInt ) + { + HBufC* retbuf = Load2L( aResourceId, aInt ); + CleanupStack::PushL( retbuf ); + return retbuf; + } + EXPORT_C HBufC8* CResourceLoader::CreateResourceReaderLC(TResourceReader& aReader,TInt aResourceId) const { HBufC8* readBuffer = iResFile.AllocReadLC( aResourceId ); @@ -74,3 +234,657 @@ return readBuffer; } +/** +Counts the number of substrings (separated by KSubStringSeparators) in the text. +Needed for correct memory allocations. +*/ +TInt CResourceLoader::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; + } + +HBufC* CResourceLoader::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; + } + +TBidiText::TDirectionality CResourceLoader::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; + } + +/** +Resolves directionality of the given source text. +Place-holder strings are removed so that they don't affect the result. +*/ +TBidiText::TDirectionality CResourceLoader::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); + } + +/** +Finds the keystring from the source string and replaces it with the +replacement string. +*/ +HBufC* CResourceLoader::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* CResourceLoader::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 keystring from the source string and replaces it with the +replacement string. The formated string is stored in the destination +descriptor. +*/ +TInt CResourceLoader::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; + } + +/** +Counts the number of parameters in the text. +Needed for correct memory allocations. +*/ +TInt CResourceLoader::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; + } + +/** +Resolves sub string and directionality of the sub string. +Adds no dir marker if directionality of the string not found. +*/ +HBufC* CResourceLoader::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; + } + +/** +Removes no dir markers from source text. +*/ +void CResourceLoader::RemoveNoDirMarkers(TDes& aText) + { + TInt nextkey(0); + while (nextkey < aText.Length()) + { + nextkey = aText.Locate(KDirNotFound); + if (nextkey != KErrNotFound) + { + aText.Delete(nextkey, 1); + nextkey++; + } + else + { + break; + } + } + } + +// ============================ MEMBER FUNCTIONS =============================== + +static TChar NumberToBase(const TChar& aCharacter ) + { + const TDigitType d[] = { EDigitTypeWestern, + EDigitTypeArabicIndic, + EDigitTypeEasternArabicIndic, + EDigitTypeDevanagari, + EDigitTypeThai }; + + const TInt num = sizeof( d ) / sizeof( d[0] ); + + TInt i = 0; + while( i < num ) + { + if (aCharacter > TChar( d[i] ) && aCharacter < TChar( d[i]+10 )) + return d[i]; + + i++; + } + + return aCharacter; + } + +/** +This routine is used to convert between European digits and +Arabic-Indic, Eastern Arabic-Indic, Devanagari or Thai digits +based on existing digit type setting. + +@param aDes Parameter to change +*/ +void CResourceLoader::LanguageSpecificNumberConverter::Convert( TDes &aDes ) + { + TLocale locale; + locale.Refresh(); + const TDigitType digitType = locale.DigitType(); + TChar toArea = 0x030; + switch( digitType ) + { + case EDigitTypeWestern: + case EDigitTypeArabicIndic: + case EDigitTypeEasternArabicIndic: + case EDigitTypeDevanagari: + case EDigitTypeThai: + toArea = digitType; + break; + case EDigitTypeUnknown: + case EDigitTypeAllTypes: + return; + } + + const TInt length = aDes.Length(); + for( TInt i = 0; i < length; i++ ) + { + TChar character = aDes[i]; + TChar fromArea = NumberToBase( character ); + TChar::TBdCategory cat = character.GetBdCategory(); + switch( cat ) + { + case TChar::EArabicNumber: + case TChar::EEuropeanNumber: + character += toArea; + character -= fromArea; + aDes[i] = TUint16( character ); + break; + default: + break; + } + } + } + +/** +This routine is used to convert Arabic-Indic, Eastern Arabic-Indic +or Devanagari digits to European digits. + +@param aDes Parameter to change +*/ +void CResourceLoader::LanguageSpecificNumberConverter::ConvertToWesternNumbers( TDes &aDes ) + { + const TChar toArea = 0x030; + const TInt KLastDevanagariDigit = 0x96F; + const TInt KFirstDevanagariDigit = 0x966; + const TInt length = aDes.Length(); + + for( TInt i=0; i