sl@0: /* sl@0: * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "NumberConversion.h" sl@0: #include "NumberConversionImp.h" sl@0: sl@0: enum TNumConvPanic sl@0: { sl@0: ENumConvPanicInvalidDigitType = 1, sl@0: }; sl@0: sl@0: #ifdef _DEBUG sl@0: LOCAL_D void Panic(TNumConvPanic aPanicCode) sl@0: // sl@0: // Panic the thread with NumberConversion as the category sl@0: // sl@0: { sl@0: _LIT(KPanicNumConv, "NumConv"); sl@0: User::Panic(KPanicNumConv, aPanicCode); sl@0: } sl@0: #endif //_DEBUG sl@0: sl@0: // TStandardDigitMatch sl@0: sl@0: /** sl@0: Length required to format KMinTInt in the longest number format sl@0: @internalComponent sl@0: */ sl@0: const TInt KMaxLengthOfFormattedNumber = 11; sl@0: sl@0: _LIT(KDefaultDigit,"0"); sl@0: _LIT(KFormatIdentifier,"%"); sl@0: sl@0: TInt StandardDigitMatch::Match(const TDesC& aText, TInt& aLength, sl@0: TDigitType& aDigitType, NumberConversion::TDigitMatchType aDigitMatchType) sl@0: { sl@0: TInt total = 0; sl@0: sl@0: aDigitType = EDigitTypeUnknown; sl@0: TDigitType currentDigitType = EDigitTypeUnknown; sl@0: aLength = 0; sl@0: TInt textLength = aText.Length(); sl@0: while (aLength < textLength) sl@0: { sl@0: TChar currentChar = aText[aLength]; sl@0: currentDigitType = DigitType(currentChar); sl@0: if (currentDigitType == EDigitTypeUnknown) sl@0: { sl@0: return total; sl@0: } sl@0: TInt digit = 0; sl@0: TUint charValue = currentChar; sl@0: digit = charValue - currentDigitType; sl@0: if (aDigitType == EDigitTypeUnknown) sl@0: { sl@0: aDigitType = currentDigitType; sl@0: } sl@0: else sl@0: { sl@0: if (aDigitType != currentDigitType) sl@0: { sl@0: if (aDigitMatchType == NumberConversion::EMatchMultipleTypes) sl@0: { sl@0: aDigitType = EDigitTypeAllTypes; sl@0: } sl@0: else sl@0: { sl@0: return total; sl@0: } sl@0: } sl@0: } sl@0: sl@0: total = (total * 10) + digit; sl@0: aLength++; sl@0: } sl@0: return total; sl@0: } sl@0: sl@0: TInt StandardDigitMatch::LeadingZeros(const TDesC& aText) sl@0: { sl@0: //Function to find the number of leading zeros sl@0: TInt textLength = aText.Length(); sl@0: TInt numOfLeadingZeros = 0; sl@0: TInt currentLength = 0; sl@0: TDigitType currentDigitType = EDigitTypeUnknown; sl@0: TBool leadingZeros = ETrue; sl@0: sl@0: if (textLength == 1) sl@0: return numOfLeadingZeros; // No leading number, if only one number. sl@0: sl@0: while(currentLength < textLength) sl@0: { sl@0: TChar currentChar = aText[currentLength]; sl@0: currentDigitType = DigitType(currentChar); sl@0: if (currentDigitType == EDigitTypeUnknown) sl@0: { sl@0: return numOfLeadingZeros; sl@0: } sl@0: TInt digit = 0; sl@0: TUint charValue = currentChar; sl@0: digit = charValue - currentDigitType; sl@0: sl@0: if (digit!=0 && leadingZeros) sl@0: leadingZeros=EFalse; sl@0: if(leadingZeros) sl@0: numOfLeadingZeros++; sl@0: currentLength++; sl@0: } sl@0: return numOfLeadingZeros; sl@0: sl@0: } sl@0: sl@0: TDigitType StandardDigitMatch::DigitType(TChar aChar) sl@0: { sl@0: if (aChar >= EDigitTypeWestern && aChar < EDigitTypeWestern+10) sl@0: { sl@0: return EDigitTypeWestern; sl@0: } sl@0: if (aChar >= EDigitTypeArabicIndic && aChar < EDigitTypeArabicIndic+10) sl@0: { sl@0: return EDigitTypeArabicIndic; sl@0: } sl@0: if (aChar >= EDigitTypeEasternArabicIndic sl@0: && aChar < EDigitTypeEasternArabicIndic+10) sl@0: { sl@0: return EDigitTypeEasternArabicIndic; sl@0: } sl@0: if (aChar >= EDigitTypeDevanagari && aChar < EDigitTypeDevanagari+10) sl@0: { sl@0: return EDigitTypeDevanagari; sl@0: } sl@0: if (aChar >= EDigitTypeBengali && aChar < EDigitTypeBengali+10) sl@0: { sl@0: return EDigitTypeBengali; sl@0: } sl@0: if (aChar >= EDigitTypeGurmukhi && aChar < EDigitTypeGurmukhi+10) sl@0: { sl@0: return EDigitTypeGurmukhi; sl@0: } sl@0: if (aChar >= EDigitTypeGujarati && aChar < EDigitTypeGujarati+10) sl@0: { sl@0: return EDigitTypeGujarati; sl@0: } sl@0: if (aChar >= EDigitTypeOriya && aChar < EDigitTypeOriya+10) sl@0: { sl@0: return EDigitTypeOriya; sl@0: } sl@0: if (aChar >= EDigitTypeTamil && aChar < EDigitTypeTamil+10) sl@0: { sl@0: return EDigitTypeTamil; sl@0: } sl@0: if (aChar >= EDigitTypeTelugu && aChar < EDigitTypeTelugu+10) sl@0: { sl@0: return EDigitTypeTelugu; sl@0: } sl@0: if (aChar >= EDigitTypeKannada && aChar < EDigitTypeKannada+10) sl@0: { sl@0: return EDigitTypeKannada; sl@0: } sl@0: if (aChar >= EDigitTypeMalayalam && aChar < EDigitTypeMalayalam+10) sl@0: { sl@0: return EDigitTypeMalayalam; sl@0: } sl@0: if (aChar >= EDigitTypeThai && aChar < EDigitTypeThai+10) sl@0: { sl@0: return EDigitTypeThai; sl@0: } sl@0: if (aChar >= EDigitTypeLao && aChar < EDigitTypeLao+10) sl@0: { sl@0: return EDigitTypeLao; sl@0: } sl@0: if (aChar >= EDigitTypeTibetan && aChar < EDigitTypeTibetan+10) sl@0: { sl@0: return EDigitTypeTibetan; sl@0: } sl@0: if (aChar >= EDigitTypeTibetan && aChar < EDigitTypeTibetan+20) sl@0: { sl@0: return EDigitTypeTibetan; sl@0: } sl@0: if (aChar >= EDigitTypeMayanmar && aChar < EDigitTypeMayanmar+10) sl@0: { sl@0: return EDigitTypeMayanmar; sl@0: } sl@0: if (aChar >= EDigitTypeKhmer && aChar < EDigitTypeKhmer+10) sl@0: { sl@0: return EDigitTypeKhmer; sl@0: } sl@0: return EDigitTypeUnknown; sl@0: } sl@0: sl@0: void StandardDigitMatch::AppendFormat(TDes& aText, TInt aNumber, sl@0: TDigitType aDigitType) sl@0: { sl@0: TInt base = aDigitType; sl@0: sl@0: if (base != EDigitTypeUnknown) sl@0: { sl@0: TInt length = aText.Length(); sl@0: TInt number = aNumber; sl@0: TBuf<1> digitText(KDefaultDigit); sl@0: do sl@0: { sl@0: digitText[0] = (TUint16)((number % 10) + base); sl@0: aText.Insert(length, digitText); sl@0: number /= 10; sl@0: } while (number > 0); sl@0: } sl@0: } sl@0: sl@0: TInt StandardDigitMatch::LengthOfFormattedNumber(TInt aNumber) sl@0: { sl@0: TInt length = 0; sl@0: do sl@0: { sl@0: length++; sl@0: aNumber /= 10; sl@0: } while (aNumber > 0); sl@0: return length; sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: // NumberConversion sl@0: sl@0: EXPORT_C TInt NumberConversion::ConvertFirstNumber(const TDesC& aText, sl@0: TInt& aLength, TDigitType& aDigitType, TDigitMatchType aDigitMatchType) sl@0: /** sl@0: Converts the descriptor aText into an integer and returns it. Ignores any minus sl@0: signs: only non-negative numbers are returned. sl@0: sl@0: @param aText Input text containing the integer to be converted. sl@0: @param aLength On exit aLength is set to the number of characters converted sl@0: from the descriptor. sl@0: @param aDigitType Returns the digit type of the number converted. If no sl@0: characters are matched, aDigitType will be set to EDigitTypeUnknown. sl@0: @param aDigitMatchType If aDigitMatchType is set to EMatchMultipleTypes, sl@0: different number types in the descriptor are matched and returned as a single sl@0: number. In this case, aDigitType will be set to EDigitTypeAllTypes. sl@0: @return The (non-negative) number found. sl@0: */ sl@0: { sl@0: return StandardDigitMatch::Match(aText, aLength, aDigitType, aDigitMatchType); sl@0: } sl@0: sl@0: EXPORT_C TInt NumberConversion::PositionAndTypeOfNextNumber(const TDesC& aText, sl@0: TDigitType& aDigitType, TInt aStartFrom) sl@0: /** sl@0: Finds the position and type of the next number in the descriptor. If the number sl@0: has a preceeding minus sign, it will be ignored and the position of the first sl@0: digit will be returned. sl@0: sl@0: @param aText Text to be searched. sl@0: @param aStartFrom First position within aText to be searched. sl@0: @param aDigitType aDigitType is set to the digit type matched. If the sl@0: descriptor doesn't contain a recognisable digit, aDigitType is set to sl@0: EDigitTypeUnknown. sl@0: @return The index of the first character. sl@0: */ sl@0: { sl@0: TInt index = aStartFrom; sl@0: TInt length = aText.Length(); sl@0: while (index < length) sl@0: { sl@0: TChar currentChar(aText[index]); sl@0: aDigitType = StandardDigitMatch::DigitType(currentChar); sl@0: if (aDigitType != EDigitTypeUnknown) sl@0: { sl@0: return index; sl@0: } sl@0: index++; sl@0: } sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: EXPORT_C void NumberConversion::FormatNumber(TDes& aText, TInt aNumber, sl@0: TDigitType aDigitType) sl@0: /** sl@0: Converts a non-negative integer into localised text. sl@0: @param aText Output for the converted number. aText must be long enough to sl@0: accommodate the text or the descriptor will panic. Negative numbers are not sl@0: supported. sl@0: @param aNumber The number to be converted. sl@0: @param aDigitType The type of digit to render the number in. sl@0: @pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() && 0 <= aNumber sl@0: */ sl@0: { sl@0: aText.Zero(); sl@0: AppendFormatNumber(aText, aNumber, aDigitType); sl@0: } sl@0: sl@0: EXPORT_C void NumberConversion::FormatDigit(TDes& aText, TInt aNumber, TInt aLeadingZero, sl@0: TDigitType aDigitType) sl@0: /** sl@0: Converts a non-negative integer into localised text. sl@0: sl@0: @param aText Output for the converted number. aText must be long enough to sl@0: accommodate the text or the descriptor will panic. Negative numbers are not sl@0: supported. sl@0: @param aNumber The number to be converted. sl@0: @param aDigitType The type of digit to render the number in. sl@0: @param aLeadingZero The number of zeros that appear before the number to be sl@0: converted to localised text. sl@0: @pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() && 0 <= aNumber sl@0: */ sl@0: { sl@0: aText.Zero(); sl@0: AppendFormatNumber(aText, aNumber, aDigitType); sl@0: sl@0: // Insert the zeros sl@0: if(aLeadingZero) sl@0: { sl@0: TChar zero = aDigitType; sl@0: TBuf<1> zeroBuf; sl@0: zeroBuf.Append(zero); sl@0: for (TInt i=0; i(aText[i]).GetNumericValue()) >= 0) sl@0: { sl@0: TBuf<1> convertedNumber; sl@0: FormatNumber(convertedNumber, charValue, aDigitType); sl@0: aText.Delete(i, 1); sl@0: aText.Insert(i, convertedNumber); sl@0: } sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TInt NumberConversion::LengthOfFormattedNumber(TInt aNumber, sl@0: TDigitType /*aDigitType*/) sl@0: /** sl@0: Returns the number of characters required to format aNumber into text. sl@0: @param aNumber The number to be converted. sl@0: @param aDigitType The format for the number. sl@0: @return The length of descriptor required to render the number as text. sl@0: */ sl@0: { sl@0: return StandardDigitMatch::LengthOfFormattedNumber(aNumber); sl@0: } sl@0: sl@0: EXPORT_C TInt NumberConversion::LengthOfConvertedText(const TDesC& aText, sl@0: TDigitType aDigitType) sl@0: /** sl@0: Returns the length of the descriptor required to hold text with its digits sl@0: converted. sl@0: sl@0: @param aText Input text for the conversion. sl@0: @param aDigitType The type of digit that will be used for the conversion. sl@0: @return The length of descriptor that would be required to convert the digits sl@0: in aText into the type specified by aDigitType. sl@0: */ sl@0: { sl@0: TDigitType digitType = EDigitTypeUnknown; sl@0: TInt position = PositionAndTypeOfNextNumber(aText, digitType); sl@0: TInt total = aText.Length(); sl@0: while (digitType != EDigitTypeUnknown) sl@0: { sl@0: // Convert this number into a different format sl@0: TInt length = 0; sl@0: TPtrC matchText = aText.Mid(position); sl@0: TInt number = ConvertFirstNumber(matchText, length, digitType); sl@0: total -= length; sl@0: total += LengthOfFormattedNumber(number, aDigitType); sl@0: position = PositionAndTypeOfNextNumber(aText, digitType, sl@0: position + length); sl@0: } sl@0: return total; sl@0: } sl@0: sl@0: EXPORT_C void NumberConversion::Format(TDigitType aDigitType, sl@0: TRefByValue aFmt,...) sl@0: /** sl@0: Formats the descriptor. Format specifiers are converted to values passed in the sl@0: variable argument list. The following format specifiers are supported: sl@0: sl@0: %d - Interprets the argument as a TInt and formats it using the aDigitType sl@0: format. Negative numbers are not supported. sl@0: sl@0: %S - Interprets the argument as a pointer to a TDesC and inserts it into the sl@0: descriptor. sl@0: sl@0: @param aDigitType The digit type for all %d directives. sl@0: */ sl@0: { sl@0: VA_LIST argument_list; sl@0: VA_START(argument_list, aFmt); sl@0: sl@0: TDes& format = aFmt; sl@0: TInt match = KErrNotFound; sl@0: while ((match = format.Find(KFormatIdentifier)) != KErrNotFound) sl@0: { sl@0: TChar formatIdentifier = format[match+1]; sl@0: switch (formatIdentifier) sl@0: { sl@0: case 'd': sl@0: { sl@0: format.Delete(match,2); sl@0: TInt number = VA_ARG(argument_list, int); sl@0: TBuf convertedNumber; sl@0: FormatNumber(convertedNumber, number, aDigitType); sl@0: format.Insert(match, convertedNumber); sl@0: } sl@0: break; sl@0: case 'S': sl@0: { sl@0: format.Delete(match,2); sl@0: TDesC* des = VA_ARG(argument_list, TDesC*); sl@0: format.Insert(match, *des); sl@0: } sl@0: break; sl@0: default: sl@0: // Remove format identifier sl@0: format.Delete(match,1); sl@0: }; sl@0: } sl@0: sl@0: VA_END(argument_list); sl@0: } sl@0: sl@0: EXPORT_C TChar NumberConversion::ConvertDigit(TChar& aDigit, TDigitType aDigitType) sl@0: /** sl@0: converts aDigit (which could be arabic, western digit etc) into the form sl@0: denoted by aDigitType. sl@0: sl@0: @param TChar& aDigit - contains the digit to be converted. sl@0: @param TDigitType aDigitType - aDigit type: western, arabic, thai, ... sl@0: @return Digit into the form, denoted by aDigitType. sl@0: */ sl@0: { sl@0: __ASSERT_DEBUG(EDigitTypeUnknown != aDigitType && EDigitTypeAllTypes != aDigitType, sl@0: Panic(ENumConvPanicInvalidDigitType)); sl@0: TBuf<1> buf; sl@0: buf.Append(aDigit); sl@0: NumberConversion::ConvertDigits(buf, aDigitType); sl@0: return buf[0]; sl@0: } sl@0: