|
1 /* |
|
2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "NumberConversion.h" |
|
20 #include "NumberConversionImp.h" |
|
21 |
|
22 enum TNumConvPanic |
|
23 { |
|
24 ENumConvPanicInvalidDigitType = 1, |
|
25 }; |
|
26 |
|
27 #ifdef _DEBUG |
|
28 LOCAL_D void Panic(TNumConvPanic aPanicCode) |
|
29 // |
|
30 // Panic the thread with NumberConversion as the category |
|
31 // |
|
32 { |
|
33 _LIT(KPanicNumConv, "NumConv"); |
|
34 User::Panic(KPanicNumConv, aPanicCode); |
|
35 } |
|
36 #endif //_DEBUG |
|
37 |
|
38 // TStandardDigitMatch |
|
39 |
|
40 /** |
|
41 Length required to format KMinTInt in the longest number format |
|
42 @internalComponent |
|
43 */ |
|
44 const TInt KMaxLengthOfFormattedNumber = 11; |
|
45 |
|
46 _LIT(KDefaultDigit,"0"); |
|
47 _LIT(KFormatIdentifier,"%"); |
|
48 |
|
49 TInt StandardDigitMatch::Match(const TDesC& aText, TInt& aLength, |
|
50 TDigitType& aDigitType, NumberConversion::TDigitMatchType aDigitMatchType) |
|
51 { |
|
52 TInt total = 0; |
|
53 |
|
54 aDigitType = EDigitTypeUnknown; |
|
55 TDigitType currentDigitType = EDigitTypeUnknown; |
|
56 aLength = 0; |
|
57 TInt textLength = aText.Length(); |
|
58 while (aLength < textLength) |
|
59 { |
|
60 TChar currentChar = aText[aLength]; |
|
61 currentDigitType = DigitType(currentChar); |
|
62 if (currentDigitType == EDigitTypeUnknown) |
|
63 { |
|
64 return total; |
|
65 } |
|
66 TInt digit = 0; |
|
67 TUint charValue = currentChar; |
|
68 digit = charValue - currentDigitType; |
|
69 if (aDigitType == EDigitTypeUnknown) |
|
70 { |
|
71 aDigitType = currentDigitType; |
|
72 } |
|
73 else |
|
74 { |
|
75 if (aDigitType != currentDigitType) |
|
76 { |
|
77 if (aDigitMatchType == NumberConversion::EMatchMultipleTypes) |
|
78 { |
|
79 aDigitType = EDigitTypeAllTypes; |
|
80 } |
|
81 else |
|
82 { |
|
83 return total; |
|
84 } |
|
85 } |
|
86 } |
|
87 |
|
88 total = (total * 10) + digit; |
|
89 aLength++; |
|
90 } |
|
91 return total; |
|
92 } |
|
93 |
|
94 TInt StandardDigitMatch::LeadingZeros(const TDesC& aText) |
|
95 { |
|
96 //Function to find the number of leading zeros |
|
97 TInt textLength = aText.Length(); |
|
98 TInt numOfLeadingZeros = 0; |
|
99 TInt currentLength = 0; |
|
100 TDigitType currentDigitType = EDigitTypeUnknown; |
|
101 TBool leadingZeros = ETrue; |
|
102 |
|
103 if (textLength == 1) |
|
104 return numOfLeadingZeros; // No leading number, if only one number. |
|
105 |
|
106 while(currentLength < textLength) |
|
107 { |
|
108 TChar currentChar = aText[currentLength]; |
|
109 currentDigitType = DigitType(currentChar); |
|
110 if (currentDigitType == EDigitTypeUnknown) |
|
111 { |
|
112 return numOfLeadingZeros; |
|
113 } |
|
114 TInt digit = 0; |
|
115 TUint charValue = currentChar; |
|
116 digit = charValue - currentDigitType; |
|
117 |
|
118 if (digit!=0 && leadingZeros) |
|
119 leadingZeros=EFalse; |
|
120 if(leadingZeros) |
|
121 numOfLeadingZeros++; |
|
122 currentLength++; |
|
123 } |
|
124 return numOfLeadingZeros; |
|
125 |
|
126 } |
|
127 |
|
128 TDigitType StandardDigitMatch::DigitType(TChar aChar) |
|
129 { |
|
130 if (aChar >= EDigitTypeWestern && aChar < EDigitTypeWestern+10) |
|
131 { |
|
132 return EDigitTypeWestern; |
|
133 } |
|
134 if (aChar >= EDigitTypeArabicIndic && aChar < EDigitTypeArabicIndic+10) |
|
135 { |
|
136 return EDigitTypeArabicIndic; |
|
137 } |
|
138 if (aChar >= EDigitTypeEasternArabicIndic |
|
139 && aChar < EDigitTypeEasternArabicIndic+10) |
|
140 { |
|
141 return EDigitTypeEasternArabicIndic; |
|
142 } |
|
143 if (aChar >= EDigitTypeDevanagari && aChar < EDigitTypeDevanagari+10) |
|
144 { |
|
145 return EDigitTypeDevanagari; |
|
146 } |
|
147 if (aChar >= EDigitTypeBengali && aChar < EDigitTypeBengali+10) |
|
148 { |
|
149 return EDigitTypeBengali; |
|
150 } |
|
151 if (aChar >= EDigitTypeGurmukhi && aChar < EDigitTypeGurmukhi+10) |
|
152 { |
|
153 return EDigitTypeGurmukhi; |
|
154 } |
|
155 if (aChar >= EDigitTypeGujarati && aChar < EDigitTypeGujarati+10) |
|
156 { |
|
157 return EDigitTypeGujarati; |
|
158 } |
|
159 if (aChar >= EDigitTypeOriya && aChar < EDigitTypeOriya+10) |
|
160 { |
|
161 return EDigitTypeOriya; |
|
162 } |
|
163 if (aChar >= EDigitTypeTamil && aChar < EDigitTypeTamil+10) |
|
164 { |
|
165 return EDigitTypeTamil; |
|
166 } |
|
167 if (aChar >= EDigitTypeTelugu && aChar < EDigitTypeTelugu+10) |
|
168 { |
|
169 return EDigitTypeTelugu; |
|
170 } |
|
171 if (aChar >= EDigitTypeKannada && aChar < EDigitTypeKannada+10) |
|
172 { |
|
173 return EDigitTypeKannada; |
|
174 } |
|
175 if (aChar >= EDigitTypeMalayalam && aChar < EDigitTypeMalayalam+10) |
|
176 { |
|
177 return EDigitTypeMalayalam; |
|
178 } |
|
179 if (aChar >= EDigitTypeThai && aChar < EDigitTypeThai+10) |
|
180 { |
|
181 return EDigitTypeThai; |
|
182 } |
|
183 if (aChar >= EDigitTypeLao && aChar < EDigitTypeLao+10) |
|
184 { |
|
185 return EDigitTypeLao; |
|
186 } |
|
187 if (aChar >= EDigitTypeTibetan && aChar < EDigitTypeTibetan+10) |
|
188 { |
|
189 return EDigitTypeTibetan; |
|
190 } |
|
191 if (aChar >= EDigitTypeTibetan && aChar < EDigitTypeTibetan+20) |
|
192 { |
|
193 return EDigitTypeTibetan; |
|
194 } |
|
195 if (aChar >= EDigitTypeMayanmar && aChar < EDigitTypeMayanmar+10) |
|
196 { |
|
197 return EDigitTypeMayanmar; |
|
198 } |
|
199 if (aChar >= EDigitTypeKhmer && aChar < EDigitTypeKhmer+10) |
|
200 { |
|
201 return EDigitTypeKhmer; |
|
202 } |
|
203 return EDigitTypeUnknown; |
|
204 } |
|
205 |
|
206 void StandardDigitMatch::AppendFormat(TDes& aText, TInt aNumber, |
|
207 TDigitType aDigitType) |
|
208 { |
|
209 TInt base = aDigitType; |
|
210 |
|
211 if (base != EDigitTypeUnknown) |
|
212 { |
|
213 TInt length = aText.Length(); |
|
214 TInt number = aNumber; |
|
215 TBuf<1> digitText(KDefaultDigit); |
|
216 do |
|
217 { |
|
218 digitText[0] = (TUint16)((number % 10) + base); |
|
219 aText.Insert(length, digitText); |
|
220 number /= 10; |
|
221 } while (number > 0); |
|
222 } |
|
223 } |
|
224 |
|
225 TInt StandardDigitMatch::LengthOfFormattedNumber(TInt aNumber) |
|
226 { |
|
227 TInt length = 0; |
|
228 do |
|
229 { |
|
230 length++; |
|
231 aNumber /= 10; |
|
232 } while (aNumber > 0); |
|
233 return length; |
|
234 } |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 // NumberConversion |
|
240 |
|
241 EXPORT_C TInt NumberConversion::ConvertFirstNumber(const TDesC& aText, |
|
242 TInt& aLength, TDigitType& aDigitType, TDigitMatchType aDigitMatchType) |
|
243 /** |
|
244 Converts the descriptor aText into an integer and returns it. Ignores any minus |
|
245 signs: only non-negative numbers are returned. |
|
246 |
|
247 @param aText Input text containing the integer to be converted. |
|
248 @param aLength On exit aLength is set to the number of characters converted |
|
249 from the descriptor. |
|
250 @param aDigitType Returns the digit type of the number converted. If no |
|
251 characters are matched, aDigitType will be set to EDigitTypeUnknown. |
|
252 @param aDigitMatchType If aDigitMatchType is set to EMatchMultipleTypes, |
|
253 different number types in the descriptor are matched and returned as a single |
|
254 number. In this case, aDigitType will be set to EDigitTypeAllTypes. |
|
255 @return The (non-negative) number found. |
|
256 */ |
|
257 { |
|
258 return StandardDigitMatch::Match(aText, aLength, aDigitType, aDigitMatchType); |
|
259 } |
|
260 |
|
261 EXPORT_C TInt NumberConversion::PositionAndTypeOfNextNumber(const TDesC& aText, |
|
262 TDigitType& aDigitType, TInt aStartFrom) |
|
263 /** |
|
264 Finds the position and type of the next number in the descriptor. If the number |
|
265 has a preceeding minus sign, it will be ignored and the position of the first |
|
266 digit will be returned. |
|
267 |
|
268 @param aText Text to be searched. |
|
269 @param aStartFrom First position within aText to be searched. |
|
270 @param aDigitType aDigitType is set to the digit type matched. If the |
|
271 descriptor doesn't contain a recognisable digit, aDigitType is set to |
|
272 EDigitTypeUnknown. |
|
273 @return The index of the first character. |
|
274 */ |
|
275 { |
|
276 TInt index = aStartFrom; |
|
277 TInt length = aText.Length(); |
|
278 while (index < length) |
|
279 { |
|
280 TChar currentChar(aText[index]); |
|
281 aDigitType = StandardDigitMatch::DigitType(currentChar); |
|
282 if (aDigitType != EDigitTypeUnknown) |
|
283 { |
|
284 return index; |
|
285 } |
|
286 index++; |
|
287 } |
|
288 return KErrNotFound; |
|
289 } |
|
290 |
|
291 EXPORT_C void NumberConversion::FormatNumber(TDes& aText, TInt aNumber, |
|
292 TDigitType aDigitType) |
|
293 /** |
|
294 Converts a non-negative integer into localised text. |
|
295 @param aText Output for the converted number. aText must be long enough to |
|
296 accommodate the text or the descriptor will panic. Negative numbers are not |
|
297 supported. |
|
298 @param aNumber The number to be converted. |
|
299 @param aDigitType The type of digit to render the number in. |
|
300 @pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() && 0 <= aNumber |
|
301 */ |
|
302 { |
|
303 aText.Zero(); |
|
304 AppendFormatNumber(aText, aNumber, aDigitType); |
|
305 } |
|
306 |
|
307 EXPORT_C void NumberConversion::FormatDigit(TDes& aText, TInt aNumber, TInt aLeadingZero, |
|
308 TDigitType aDigitType) |
|
309 /** |
|
310 Converts a non-negative integer into localised text. |
|
311 |
|
312 @param aText Output for the converted number. aText must be long enough to |
|
313 accommodate the text or the descriptor will panic. Negative numbers are not |
|
314 supported. |
|
315 @param aNumber The number to be converted. |
|
316 @param aDigitType The type of digit to render the number in. |
|
317 @param aLeadingZero The number of zeros that appear before the number to be |
|
318 converted to localised text. |
|
319 @pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() && 0 <= aNumber |
|
320 */ |
|
321 { |
|
322 aText.Zero(); |
|
323 AppendFormatNumber(aText, aNumber, aDigitType); |
|
324 |
|
325 // Insert the zeros |
|
326 if(aLeadingZero) |
|
327 { |
|
328 TChar zero = aDigitType; |
|
329 TBuf<1> zeroBuf; |
|
330 zeroBuf.Append(zero); |
|
331 for (TInt i=0; i<aLeadingZero; i++) |
|
332 { |
|
333 aText.Insert(0,zeroBuf); |
|
334 } |
|
335 } |
|
336 } |
|
337 |
|
338 EXPORT_C void NumberConversion::AppendFormatNumber(TDes& aText, TInt aNumber, |
|
339 TDigitType aDigitType) |
|
340 /** |
|
341 Converts a non-negative integer into localised text, appending the result to a |
|
342 descriptor. |
|
343 |
|
344 @param aText Output for the converted number. aText must have enough free space |
|
345 after its current length to accommodate the text or the descriptor will panic. |
|
346 Negative numbers are not supported. |
|
347 @param aNumber The number to be converted. |
|
348 @param aDigitType The type of digit to render the number in. |
|
349 @pre NumberConversion::LengthOfFormattedNumber(aNumber, aDigitType) <= aText.MaxLength() - aText.Length() && 0 <= aNumber |
|
350 */ |
|
351 { |
|
352 StandardDigitMatch::AppendFormat(aText, aNumber, aDigitType); |
|
353 } |
|
354 |
|
355 EXPORT_C void NumberConversion::ConvertDigits(TDes& aText, |
|
356 TDigitType aDigitType) |
|
357 /** |
|
358 Converts all of the digits in the descriptor aText into the format specified in |
|
359 aDigitType. |
|
360 |
|
361 @param aText The text that is to have its digits converted. |
|
362 @param aDigitType The digit type to be converted to. |
|
363 @pre NumberConversion::LengthOfConvertedText(aText, aDigitType) <= aText.MaxLength() |
|
364 @post All digits in the string will either conform to one of the constants |
|
365 defined in enum TDigitType or will match the digit type |
|
366 supplied in aDigitType. |
|
367 */ |
|
368 { |
|
369 TInt charValue; |
|
370 for (TInt i=0; i < aText.Length(); i++) |
|
371 { |
|
372 if ( (charValue = static_cast<TChar>(aText[i]).GetNumericValue()) >= 0) |
|
373 { |
|
374 TBuf<1> convertedNumber; |
|
375 FormatNumber(convertedNumber, charValue, aDigitType); |
|
376 aText.Delete(i, 1); |
|
377 aText.Insert(i, convertedNumber); |
|
378 } |
|
379 } |
|
380 } |
|
381 |
|
382 EXPORT_C TInt NumberConversion::LengthOfFormattedNumber(TInt aNumber, |
|
383 TDigitType /*aDigitType*/) |
|
384 /** |
|
385 Returns the number of characters required to format aNumber into text. |
|
386 @param aNumber The number to be converted. |
|
387 @param aDigitType The format for the number. |
|
388 @return The length of descriptor required to render the number as text. |
|
389 */ |
|
390 { |
|
391 return StandardDigitMatch::LengthOfFormattedNumber(aNumber); |
|
392 } |
|
393 |
|
394 EXPORT_C TInt NumberConversion::LengthOfConvertedText(const TDesC& aText, |
|
395 TDigitType aDigitType) |
|
396 /** |
|
397 Returns the length of the descriptor required to hold text with its digits |
|
398 converted. |
|
399 |
|
400 @param aText Input text for the conversion. |
|
401 @param aDigitType The type of digit that will be used for the conversion. |
|
402 @return The length of descriptor that would be required to convert the digits |
|
403 in aText into the type specified by aDigitType. |
|
404 */ |
|
405 { |
|
406 TDigitType digitType = EDigitTypeUnknown; |
|
407 TInt position = PositionAndTypeOfNextNumber(aText, digitType); |
|
408 TInt total = aText.Length(); |
|
409 while (digitType != EDigitTypeUnknown) |
|
410 { |
|
411 // Convert this number into a different format |
|
412 TInt length = 0; |
|
413 TPtrC matchText = aText.Mid(position); |
|
414 TInt number = ConvertFirstNumber(matchText, length, digitType); |
|
415 total -= length; |
|
416 total += LengthOfFormattedNumber(number, aDigitType); |
|
417 position = PositionAndTypeOfNextNumber(aText, digitType, |
|
418 position + length); |
|
419 } |
|
420 return total; |
|
421 } |
|
422 |
|
423 EXPORT_C void NumberConversion::Format(TDigitType aDigitType, |
|
424 TRefByValue<TDes> aFmt,...) |
|
425 /** |
|
426 Formats the descriptor. Format specifiers are converted to values passed in the |
|
427 variable argument list. The following format specifiers are supported: |
|
428 |
|
429 %d - Interprets the argument as a TInt and formats it using the aDigitType |
|
430 format. Negative numbers are not supported. |
|
431 |
|
432 %S - Interprets the argument as a pointer to a TDesC and inserts it into the |
|
433 descriptor. |
|
434 |
|
435 @param aDigitType The digit type for all %d directives. |
|
436 */ |
|
437 { |
|
438 VA_LIST argument_list; |
|
439 VA_START(argument_list, aFmt); |
|
440 |
|
441 TDes& format = aFmt; |
|
442 TInt match = KErrNotFound; |
|
443 while ((match = format.Find(KFormatIdentifier)) != KErrNotFound) |
|
444 { |
|
445 TChar formatIdentifier = format[match+1]; |
|
446 switch (formatIdentifier) |
|
447 { |
|
448 case 'd': |
|
449 { |
|
450 format.Delete(match,2); |
|
451 TInt number = VA_ARG(argument_list, int); |
|
452 TBuf<KMaxLengthOfFormattedNumber> convertedNumber; |
|
453 FormatNumber(convertedNumber, number, aDigitType); |
|
454 format.Insert(match, convertedNumber); |
|
455 } |
|
456 break; |
|
457 case 'S': |
|
458 { |
|
459 format.Delete(match,2); |
|
460 TDesC* des = VA_ARG(argument_list, TDesC*); |
|
461 format.Insert(match, *des); |
|
462 } |
|
463 break; |
|
464 default: |
|
465 // Remove format identifier |
|
466 format.Delete(match,1); |
|
467 }; |
|
468 } |
|
469 |
|
470 VA_END(argument_list); |
|
471 } |
|
472 |
|
473 EXPORT_C TChar NumberConversion::ConvertDigit(TChar& aDigit, TDigitType aDigitType) |
|
474 /** |
|
475 converts aDigit (which could be arabic, western digit etc) into the form |
|
476 denoted by aDigitType. |
|
477 |
|
478 @param TChar& aDigit - contains the digit to be converted. |
|
479 @param TDigitType aDigitType - aDigit type: western, arabic, thai, ... |
|
480 @return Digit into the form, denoted by aDigitType. |
|
481 */ |
|
482 { |
|
483 __ASSERT_DEBUG(EDigitTypeUnknown != aDigitType && EDigitTypeAllTypes != aDigitType, |
|
484 Panic(ENumConvPanicInvalidDigitType)); |
|
485 TBuf<1> buf; |
|
486 buf.Append(aDigit); |
|
487 NumberConversion::ConvertDigits(buf, aDigitType); |
|
488 return buf[0]; |
|
489 } |
|
490 |