1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/textrendering/numberformatting/src/NumberConversion.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,490 @@
1.4 +/*
1.5 +* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include "NumberConversion.h"
1.23 +#include "NumberConversionImp.h"
1.24 +
1.25 +enum TNumConvPanic
1.26 + {
1.27 + ENumConvPanicInvalidDigitType = 1,
1.28 + };
1.29 +
1.30 +#ifdef _DEBUG
1.31 +LOCAL_D void Panic(TNumConvPanic aPanicCode)
1.32 +//
1.33 +// Panic the thread with NumberConversion as the category
1.34 +//
1.35 + {
1.36 + _LIT(KPanicNumConv, "NumConv");
1.37 + User::Panic(KPanicNumConv, aPanicCode);
1.38 + }
1.39 +#endif //_DEBUG
1.40 +
1.41 +// TStandardDigitMatch
1.42 +
1.43 +/**
1.44 +Length required to format KMinTInt in the longest number format
1.45 +@internalComponent
1.46 +*/
1.47 +const TInt KMaxLengthOfFormattedNumber = 11;
1.48 +
1.49 +_LIT(KDefaultDigit,"0");
1.50 +_LIT(KFormatIdentifier,"%");
1.51 +
1.52 +TInt StandardDigitMatch::Match(const TDesC& aText, TInt& aLength,
1.53 + TDigitType& aDigitType, NumberConversion::TDigitMatchType aDigitMatchType)
1.54 + {
1.55 + TInt total = 0;
1.56 +
1.57 + aDigitType = EDigitTypeUnknown;
1.58 + TDigitType currentDigitType = EDigitTypeUnknown;
1.59 + aLength = 0;
1.60 + TInt textLength = aText.Length();
1.61 + while (aLength < textLength)
1.62 + {
1.63 + TChar currentChar = aText[aLength];
1.64 + currentDigitType = DigitType(currentChar);
1.65 + if (currentDigitType == EDigitTypeUnknown)
1.66 + {
1.67 + return total;
1.68 + }
1.69 + TInt digit = 0;
1.70 + TUint charValue = currentChar;
1.71 + digit = charValue - currentDigitType;
1.72 + if (aDigitType == EDigitTypeUnknown)
1.73 + {
1.74 + aDigitType = currentDigitType;
1.75 + }
1.76 + else
1.77 + {
1.78 + if (aDigitType != currentDigitType)
1.79 + {
1.80 + if (aDigitMatchType == NumberConversion::EMatchMultipleTypes)
1.81 + {
1.82 + aDigitType = EDigitTypeAllTypes;
1.83 + }
1.84 + else
1.85 + {
1.86 + return total;
1.87 + }
1.88 + }
1.89 + }
1.90 +
1.91 + total = (total * 10) + digit;
1.92 + aLength++;
1.93 + }
1.94 + return total;
1.95 + }
1.96 +
1.97 +TInt StandardDigitMatch::LeadingZeros(const TDesC& aText)
1.98 + {
1.99 + //Function to find the number of leading zeros
1.100 + TInt textLength = aText.Length();
1.101 + TInt numOfLeadingZeros = 0;
1.102 + TInt currentLength = 0;
1.103 + TDigitType currentDigitType = EDigitTypeUnknown;
1.104 + TBool leadingZeros = ETrue;
1.105 +
1.106 + if (textLength == 1)
1.107 + return numOfLeadingZeros; // No leading number, if only one number.
1.108 +
1.109 + while(currentLength < textLength)
1.110 + {
1.111 + TChar currentChar = aText[currentLength];
1.112 + currentDigitType = DigitType(currentChar);
1.113 + if (currentDigitType == EDigitTypeUnknown)
1.114 + {
1.115 + return numOfLeadingZeros;
1.116 + }
1.117 + TInt digit = 0;
1.118 + TUint charValue = currentChar;
1.119 + digit = charValue - currentDigitType;
1.120 +
1.121 + if (digit!=0 && leadingZeros)
1.122 + leadingZeros=EFalse;
1.123 + if(leadingZeros)
1.124 + numOfLeadingZeros++;
1.125 + currentLength++;
1.126 + }
1.127 + return numOfLeadingZeros;
1.128 +
1.129 + }
1.130 +
1.131 +TDigitType StandardDigitMatch::DigitType(TChar aChar)
1.132 + {
1.133 + if (aChar >= EDigitTypeWestern && aChar < EDigitTypeWestern+10)
1.134 + {
1.135 + return EDigitTypeWestern;
1.136 + }
1.137 + if (aChar >= EDigitTypeArabicIndic && aChar < EDigitTypeArabicIndic+10)
1.138 + {
1.139 + return EDigitTypeArabicIndic;
1.140 + }
1.141 + if (aChar >= EDigitTypeEasternArabicIndic
1.142 + && aChar < EDigitTypeEasternArabicIndic+10)
1.143 + {
1.144 + return EDigitTypeEasternArabicIndic;
1.145 + }
1.146 + if (aChar >= EDigitTypeDevanagari && aChar < EDigitTypeDevanagari+10)
1.147 + {
1.148 + return EDigitTypeDevanagari;
1.149 + }
1.150 + if (aChar >= EDigitTypeBengali && aChar < EDigitTypeBengali+10)
1.151 + {
1.152 + return EDigitTypeBengali;
1.153 + }
1.154 + if (aChar >= EDigitTypeGurmukhi && aChar < EDigitTypeGurmukhi+10)
1.155 + {
1.156 + return EDigitTypeGurmukhi;
1.157 + }
1.158 + if (aChar >= EDigitTypeGujarati && aChar < EDigitTypeGujarati+10)
1.159 + {
1.160 + return EDigitTypeGujarati;
1.161 + }
1.162 + if (aChar >= EDigitTypeOriya && aChar < EDigitTypeOriya+10)
1.163 + {
1.164 + return EDigitTypeOriya;
1.165 + }
1.166 + if (aChar >= EDigitTypeTamil && aChar < EDigitTypeTamil+10)
1.167 + {
1.168 + return EDigitTypeTamil;
1.169 + }
1.170 + if (aChar >= EDigitTypeTelugu && aChar < EDigitTypeTelugu+10)
1.171 + {
1.172 + return EDigitTypeTelugu;
1.173 + }
1.174 + if (aChar >= EDigitTypeKannada && aChar < EDigitTypeKannada+10)
1.175 + {
1.176 + return EDigitTypeKannada;
1.177 + }
1.178 + if (aChar >= EDigitTypeMalayalam && aChar < EDigitTypeMalayalam+10)
1.179 + {
1.180 + return EDigitTypeMalayalam;
1.181 + }
1.182 + if (aChar >= EDigitTypeThai && aChar < EDigitTypeThai+10)
1.183 + {
1.184 + return EDigitTypeThai;
1.185 + }
1.186 + if (aChar >= EDigitTypeLao && aChar < EDigitTypeLao+10)
1.187 + {
1.188 + return EDigitTypeLao;
1.189 + }
1.190 + if (aChar >= EDigitTypeTibetan && aChar < EDigitTypeTibetan+10)
1.191 + {
1.192 + return EDigitTypeTibetan;
1.193 + }
1.194 + if (aChar >= EDigitTypeTibetan && aChar < EDigitTypeTibetan+20)
1.195 + {
1.196 + return EDigitTypeTibetan;
1.197 + }
1.198 + if (aChar >= EDigitTypeMayanmar && aChar < EDigitTypeMayanmar+10)
1.199 + {
1.200 + return EDigitTypeMayanmar;
1.201 + }
1.202 + if (aChar >= EDigitTypeKhmer && aChar < EDigitTypeKhmer+10)
1.203 + {
1.204 + return EDigitTypeKhmer;
1.205 + }
1.206 + return EDigitTypeUnknown;
1.207 + }
1.208 +
1.209 +void StandardDigitMatch::AppendFormat(TDes& aText, TInt aNumber,
1.210 + TDigitType aDigitType)
1.211 + {
1.212 + TInt base = aDigitType;
1.213 +
1.214 + if (base != EDigitTypeUnknown)
1.215 + {
1.216 + TInt length = aText.Length();
1.217 + TInt number = aNumber;
1.218 + TBuf<1> digitText(KDefaultDigit);
1.219 + do
1.220 + {
1.221 + digitText[0] = (TUint16)((number % 10) + base);
1.222 + aText.Insert(length, digitText);
1.223 + number /= 10;
1.224 + } while (number > 0);
1.225 + }
1.226 + }
1.227 +
1.228 +TInt StandardDigitMatch::LengthOfFormattedNumber(TInt aNumber)
1.229 + {
1.230 + TInt length = 0;
1.231 + do
1.232 + {
1.233 + length++;
1.234 + aNumber /= 10;
1.235 + } while (aNumber > 0);
1.236 + return length;
1.237 + }
1.238 +
1.239 +
1.240 +
1.241 +
1.242 +// NumberConversion
1.243 +
1.244 +EXPORT_C TInt NumberConversion::ConvertFirstNumber(const TDesC& aText,
1.245 + TInt& aLength, TDigitType& aDigitType, TDigitMatchType aDigitMatchType)
1.246 +/**
1.247 +Converts the descriptor aText into an integer and returns it. Ignores any minus
1.248 +signs: only non-negative numbers are returned.
1.249 +
1.250 +@param aText Input text containing the integer to be converted.
1.251 +@param aLength On exit aLength is set to the number of characters converted
1.252 +from the descriptor.
1.253 +@param aDigitType Returns the digit type of the number converted. If no
1.254 +characters are matched, aDigitType will be set to EDigitTypeUnknown.
1.255 +@param aDigitMatchType If aDigitMatchType is set to EMatchMultipleTypes,
1.256 +different number types in the descriptor are matched and returned as a single
1.257 +number. In this case, aDigitType will be set to EDigitTypeAllTypes.
1.258 +@return The (non-negative) number found.
1.259 +*/
1.260 + {
1.261 + return StandardDigitMatch::Match(aText, aLength, aDigitType, aDigitMatchType);
1.262 + }
1.263 +
1.264 +EXPORT_C TInt NumberConversion::PositionAndTypeOfNextNumber(const TDesC& aText,
1.265 + TDigitType& aDigitType, TInt aStartFrom)
1.266 +/**
1.267 +Finds the position and type of the next number in the descriptor. If the number
1.268 +has a preceeding minus sign, it will be ignored and the position of the first
1.269 +digit will be returned.
1.270 +
1.271 +@param aText Text to be searched.
1.272 +@param aStartFrom First position within aText to be searched.
1.273 +@param aDigitType aDigitType is set to the digit type matched. If the
1.274 +descriptor doesn't contain a recognisable digit, aDigitType is set to
1.275 +EDigitTypeUnknown.
1.276 +@return The index of the first character.
1.277 +*/
1.278 + {
1.279 + TInt index = aStartFrom;
1.280 + TInt length = aText.Length();
1.281 + while (index < length)
1.282 + {
1.283 + TChar currentChar(aText[index]);
1.284 + aDigitType = StandardDigitMatch::DigitType(currentChar);
1.285 + if (aDigitType != EDigitTypeUnknown)
1.286 + {
1.287 + return index;
1.288 + }
1.289 + index++;
1.290 + }
1.291 + return KErrNotFound;
1.292 + }
1.293 +
1.294 +EXPORT_C void NumberConversion::FormatNumber(TDes& aText, TInt aNumber,
1.295 + TDigitType aDigitType)
1.296 +/**
1.297 +Converts a non-negative integer into localised text.
1.298 +@param aText Output for the converted number. aText must be long enough to
1.299 +accommodate the text or the descriptor will panic. Negative numbers are not
1.300 +supported.
1.301 +@param aNumber The number to be converted.
1.302 +@param aDigitType The type of digit to render the number in.
1.303 +@pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() && 0 <= aNumber
1.304 +*/
1.305 + {
1.306 + aText.Zero();
1.307 + AppendFormatNumber(aText, aNumber, aDigitType);
1.308 + }
1.309 +
1.310 +EXPORT_C void NumberConversion::FormatDigit(TDes& aText, TInt aNumber, TInt aLeadingZero,
1.311 + TDigitType aDigitType)
1.312 +/**
1.313 +Converts a non-negative integer into localised text.
1.314 +
1.315 +@param aText Output for the converted number. aText must be long enough to
1.316 +accommodate the text or the descriptor will panic. Negative numbers are not
1.317 +supported.
1.318 +@param aNumber The number to be converted.
1.319 +@param aDigitType The type of digit to render the number in.
1.320 +@param aLeadingZero The number of zeros that appear before the number to be
1.321 +converted to localised text.
1.322 +@pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() && 0 <= aNumber
1.323 +*/
1.324 + {
1.325 + aText.Zero();
1.326 + AppendFormatNumber(aText, aNumber, aDigitType);
1.327 +
1.328 + // Insert the zeros
1.329 + if(aLeadingZero)
1.330 + {
1.331 + TChar zero = aDigitType;
1.332 + TBuf<1> zeroBuf;
1.333 + zeroBuf.Append(zero);
1.334 + for (TInt i=0; i<aLeadingZero; i++)
1.335 + {
1.336 + aText.Insert(0,zeroBuf);
1.337 + }
1.338 + }
1.339 + }
1.340 +
1.341 +EXPORT_C void NumberConversion::AppendFormatNumber(TDes& aText, TInt aNumber,
1.342 + TDigitType aDigitType)
1.343 +/**
1.344 +Converts a non-negative integer into localised text, appending the result to a
1.345 +descriptor.
1.346 +
1.347 +@param aText Output for the converted number. aText must have enough free space
1.348 +after its current length to accommodate the text or the descriptor will panic.
1.349 +Negative numbers are not supported.
1.350 +@param aNumber The number to be converted.
1.351 +@param aDigitType The type of digit to render the number in.
1.352 +@pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() - aText.Length() && 0 <= aNumber
1.353 +*/
1.354 + {
1.355 + StandardDigitMatch::AppendFormat(aText, aNumber, aDigitType);
1.356 + }
1.357 +
1.358 +EXPORT_C void NumberConversion::ConvertDigits(TDes& aText,
1.359 + TDigitType aDigitType)
1.360 +/**
1.361 +Converts all of the digits in the descriptor aText into the format specified in
1.362 +aDigitType.
1.363 +
1.364 +@param aText The text that is to have its digits converted.
1.365 +@param aDigitType The digit type to be converted to.
1.366 +@pre NumberConversion::LengthOfConvertedText(aText, aDigitType) <= aText.MaxLength()
1.367 +@post All digits in the string will either conform to one of the constants
1.368 +defined in enum TDigitType or will match the digit type
1.369 +supplied in aDigitType.
1.370 +*/
1.371 + {
1.372 + TInt charValue;
1.373 + for (TInt i=0; i < aText.Length(); i++)
1.374 + {
1.375 + if ( (charValue = static_cast<TChar>(aText[i]).GetNumericValue()) >= 0)
1.376 + {
1.377 + TBuf<1> convertedNumber;
1.378 + FormatNumber(convertedNumber, charValue, aDigitType);
1.379 + aText.Delete(i, 1);
1.380 + aText.Insert(i, convertedNumber);
1.381 + }
1.382 + }
1.383 + }
1.384 +
1.385 +EXPORT_C TInt NumberConversion::LengthOfFormattedNumber(TInt aNumber,
1.386 + TDigitType /*aDigitType*/)
1.387 +/**
1.388 +Returns the number of characters required to format aNumber into text.
1.389 +@param aNumber The number to be converted.
1.390 +@param aDigitType The format for the number.
1.391 +@return The length of descriptor required to render the number as text.
1.392 +*/
1.393 + {
1.394 + return StandardDigitMatch::LengthOfFormattedNumber(aNumber);
1.395 + }
1.396 +
1.397 +EXPORT_C TInt NumberConversion::LengthOfConvertedText(const TDesC& aText,
1.398 + TDigitType aDigitType)
1.399 +/**
1.400 +Returns the length of the descriptor required to hold text with its digits
1.401 +converted.
1.402 +
1.403 +@param aText Input text for the conversion.
1.404 +@param aDigitType The type of digit that will be used for the conversion.
1.405 +@return The length of descriptor that would be required to convert the digits
1.406 +in aText into the type specified by aDigitType.
1.407 +*/
1.408 + {
1.409 + TDigitType digitType = EDigitTypeUnknown;
1.410 + TInt position = PositionAndTypeOfNextNumber(aText, digitType);
1.411 + TInt total = aText.Length();
1.412 + while (digitType != EDigitTypeUnknown)
1.413 + {
1.414 + // Convert this number into a different format
1.415 + TInt length = 0;
1.416 + TPtrC matchText = aText.Mid(position);
1.417 + TInt number = ConvertFirstNumber(matchText, length, digitType);
1.418 + total -= length;
1.419 + total += LengthOfFormattedNumber(number, aDigitType);
1.420 + position = PositionAndTypeOfNextNumber(aText, digitType,
1.421 + position + length);
1.422 + }
1.423 + return total;
1.424 + }
1.425 +
1.426 +EXPORT_C void NumberConversion::Format(TDigitType aDigitType,
1.427 + TRefByValue<TDes> aFmt,...)
1.428 +/**
1.429 +Formats the descriptor. Format specifiers are converted to values passed in the
1.430 +variable argument list. The following format specifiers are supported:
1.431 +
1.432 +%d - Interprets the argument as a TInt and formats it using the aDigitType
1.433 +format. Negative numbers are not supported.
1.434 +
1.435 +%S - Interprets the argument as a pointer to a TDesC and inserts it into the
1.436 +descriptor.
1.437 +
1.438 +@param aDigitType The digit type for all %d directives.
1.439 +*/
1.440 + {
1.441 + VA_LIST argument_list;
1.442 + VA_START(argument_list, aFmt);
1.443 +
1.444 + TDes& format = aFmt;
1.445 + TInt match = KErrNotFound;
1.446 + while ((match = format.Find(KFormatIdentifier)) != KErrNotFound)
1.447 + {
1.448 + TChar formatIdentifier = format[match+1];
1.449 + switch (formatIdentifier)
1.450 + {
1.451 + case 'd':
1.452 + {
1.453 + format.Delete(match,2);
1.454 + TInt number = VA_ARG(argument_list, int);
1.455 + TBuf<KMaxLengthOfFormattedNumber> convertedNumber;
1.456 + FormatNumber(convertedNumber, number, aDigitType);
1.457 + format.Insert(match, convertedNumber);
1.458 + }
1.459 + break;
1.460 + case 'S':
1.461 + {
1.462 + format.Delete(match,2);
1.463 + TDesC* des = VA_ARG(argument_list, TDesC*);
1.464 + format.Insert(match, *des);
1.465 + }
1.466 + break;
1.467 + default:
1.468 + // Remove format identifier
1.469 + format.Delete(match,1);
1.470 + };
1.471 + }
1.472 +
1.473 + VA_END(argument_list);
1.474 + }
1.475 +
1.476 +EXPORT_C TChar NumberConversion::ConvertDigit(TChar& aDigit, TDigitType aDigitType)
1.477 +/**
1.478 +converts aDigit (which could be arabic, western digit etc) into the form
1.479 +denoted by aDigitType.
1.480 +
1.481 +@param TChar& aDigit - contains the digit to be converted.
1.482 +@param TDigitType aDigitType - aDigit type: western, arabic, thai, ...
1.483 +@return Digit into the form, denoted by aDigitType.
1.484 +*/
1.485 + {
1.486 + __ASSERT_DEBUG(EDigitTypeUnknown != aDigitType && EDigitTypeAllTypes != aDigitType,
1.487 + Panic(ENumConvPanicInvalidDigitType));
1.488 + TBuf<1> buf;
1.489 + buf.Append(aDigit);
1.490 + NumberConversion::ConvertDigits(buf, aDigitType);
1.491 + return buf[0];
1.492 + }
1.493 +