1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <i18nlangtag/mslangid.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <sal/macros.h>
23 #include <nativenumbersupplier.hxx>
24 #include <localedata.hxx>
25 #include <data/numberchar.h>
26 #include <comphelper/string.hxx>
28 using namespace ::com::sun::star::uno
;
29 using namespace ::com::sun::star::lang
;
30 using namespace ::rtl
;
35 sal_Unicode
*multiplierChar
;
37 sal_Int16 exponentCount
;
38 sal_Int16
*multiplierExponent
;
42 #define NUMBER_OMIT_ZERO (1 << 0)
43 #define NUMBER_OMIT_ONLY_ZERO (1 << 1)
44 #define NUMBER_OMIT_ONE_1 (1 << 2)
45 #define NUMBER_OMIT_ONE_2 (1 << 3)
46 #define NUMBER_OMIT_ONE_3 (1 << 4)
47 #define NUMBER_OMIT_ONE_4 (1 << 5)
48 #define NUMBER_OMIT_ONE_5 (1 << 6)
49 #define NUMBER_OMIT_ONE_6 (1 << 7)
50 #define NUMBER_OMIT_ONE_7 (1 << 8)
51 #define NUMBER_OMIT_ONE (NUMBER_OMIT_ONE_1|NUMBER_OMIT_ONE_2|NUMBER_OMIT_ONE_3|NUMBER_OMIT_ONE_4|NUMBER_OMIT_ONE_5|NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
52 #define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit))
53 #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
54 #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
55 #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
56 #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
58 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{
60 OUString SAL_CALL
getHebrewNativeNumberString(const OUString
& aNumberString
, sal_Bool useGeresh
);
62 OUString SAL_CALL
AsciiToNativeChar( const OUString
& inStr
, sal_Int32 startPos
, sal_Int32 nCount
,
63 Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
, sal_Int16 number
) throw(RuntimeException
)
65 const sal_Unicode
*src
= inStr
.getStr() + startPos
;
66 rtl_uString
*newStr
= rtl_uString_alloc(nCount
);
68 offset
.realloc(nCount
);
70 for (sal_Int32 i
= 0; i
< nCount
; i
++)
72 sal_Unicode ch
= src
[i
];
74 newStr
->buffer
[i
] = NumberChar
[number
][ ch
- NUMBER_ZERO
];
75 else if (i
+1 < nCount
&& isNumber(src
[i
+1])) {
76 if (i
> 0 && isNumber(src
[i
-1]) && isSeparator(ch
))
77 newStr
->buffer
[i
] = SeparatorChar
[number
] ? SeparatorChar
[number
] : ch
;
79 newStr
->buffer
[i
] = isDecimal(ch
) ? (DecimalChar
[number
] ? DecimalChar
[number
] : ch
) :
80 isMinus(ch
) ? (MinusChar
[number
] ? MinusChar
[number
] : ch
) : ch
;
83 newStr
->buffer
[i
] = ch
;
85 offset
[i
] = startPos
+ i
;
87 return OUString(newStr
, SAL_NO_ACQUIRE
); // take ownership
90 sal_Bool SAL_CALL
AsciiToNative_numberMaker(const sal_Unicode
*str
, sal_Int32 begin
, sal_Int32 len
,
91 sal_Unicode
*dst
, sal_Int32
& count
, sal_Int16 multiChar_index
, Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
, sal_Int32 startPos
,
92 Number
*number
, sal_Unicode
* numberChar
)
94 sal_Unicode multiChar
= (multiChar_index
== -1 ? 0 : number
->multiplierChar
[multiChar_index
]);
95 if ( len
<= number
->multiplierExponent
[number
->exponentCount
-1] ) {
96 if (number
->multiplierExponent
[number
->exponentCount
-1] > 1) {
98 sal_Bool notZero
= false;
99 for (i
= 0; i
< len
; i
++, begin
++) {
100 if (notZero
|| str
[begin
] != NUMBER_ZERO
) {
101 dst
[count
] = numberChar
[str
[begin
] - NUMBER_ZERO
];
103 offset
[count
] = begin
+ startPos
;
108 if (notZero
&& multiChar
> 0) {
109 dst
[count
] = multiChar
;
111 offset
[count
] = begin
+ startPos
;
115 } else if (str
[begin
] != NUMBER_ZERO
) {
116 if (!(number
->numberFlag
& (multiChar_index
< 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index
))) || str
[begin
] != NUMBER_ONE
) {
117 dst
[count
] = numberChar
[str
[begin
] - NUMBER_ZERO
];
119 offset
[count
] = begin
+ startPos
;
123 dst
[count
] = multiChar
;
125 offset
[count
] = begin
+ startPos
;
128 } else if (!(number
->numberFlag
& NUMBER_OMIT_ZERO
) && count
> 0 && dst
[count
-1] != numberChar
[0]) {
129 dst
[count
] = numberChar
[0];
131 offset
[count
] = begin
+ startPos
;
134 return str
[begin
] != NUMBER_ZERO
;
136 sal_Bool printPower
= sal_False
;
137 // sal_Int16 last = 0;
138 for (sal_Int16 i
= 1; i
<= number
->exponentCount
; i
++) {
139 sal_Int32 tmp
= len
- (i
== number
->exponentCount
? 0 : number
->multiplierExponent
[i
]);
141 printPower
|= AsciiToNative_numberMaker(str
, begin
, tmp
, dst
, count
,
142 (i
== number
->exponentCount
? -1 : i
), offset
, useOffset
, startPos
, number
, numberChar
);
148 if (count
> 0 && number
->multiplierExponent
[number
->exponentCount
-1] == 1 &&
149 dst
[count
-1] == numberChar
[0])
152 dst
[count
] = multiChar
;
154 offset
[count
] = begin
+ startPos
;
162 OUString SAL_CALL
AsciiToNative( const OUString
& inStr
, sal_Int32 startPos
, sal_Int32 nCount
,
163 Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
, Number
* number
) throw(RuntimeException
)
167 sal_Int32 strLen
= inStr
.getLength() - startPos
;
168 sal_Unicode
*numberChar
= NumberChar
[number
->number
];
175 const sal_Unicode
*str
= inStr
.getStr() + startPos
;
176 sal_Unicode
*newStr
= new sal_Unicode
[nCount
* 2 + 1];
177 sal_Unicode
*srcStr
= new sal_Unicode
[nCount
+ 1]; // for keeping number without comma
178 sal_Int32 i
, len
= 0, count
= 0;
181 offset
.realloc( nCount
* 2 );
182 sal_Bool doDecimal
= sal_False
;
184 for (i
= 0; i
<= nCount
; i
++)
186 if (i
< nCount
&& isNumber(str
[i
])) {
188 newStr
[count
] = numberChar
[str
[i
] - NUMBER_ZERO
];
190 offset
[count
] = i
+ startPos
;
194 srcStr
[len
++] = str
[i
];
197 if (isSeparator(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))
198 continue; // skip comma inside number string
199 sal_Bool notZero
= sal_False
;
200 for (sal_Int32 begin
= 0, end
= len
% number
->multiplierExponent
[0];
201 end
<= len
; begin
= end
, end
+= number
->multiplierExponent
[0]) {
202 if (end
== 0) continue;
203 sal_Int32 _count
= count
;
204 notZero
|= AsciiToNative_numberMaker(srcStr
, begin
, end
- begin
, newStr
, count
,
205 end
== len
? -1 : 0, offset
, useOffset
, i
- len
+ startPos
, number
, numberChar
);
206 if (count
> 0 && number
->multiplierExponent
[number
->exponentCount
-1] == 1 &&
207 newStr
[count
-1] == numberChar
[0])
209 if (notZero
&& _count
== count
) {
211 newStr
[count
] = number
->multiplierChar
[0];
213 offset
[count
] = i
- len
+ startPos
;
218 if (! notZero
&& ! (number
->numberFlag
& NUMBER_OMIT_ONLY_ZERO
)) {
219 newStr
[count
] = numberChar
[0];
221 offset
[count
] = i
- len
+ startPos
;
227 if ((doDecimal
= (!doDecimal
&& isDecimal(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))) != sal_False
)
228 newStr
[count
] = (DecimalChar
[number
->number
] ? DecimalChar
[number
->number
] : str
[i
]);
229 else if (isMinus(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))
230 newStr
[count
] = (MinusChar
[number
->number
] ? MinusChar
[number
->number
] : str
[i
]);
231 else if (isSeparator(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))
232 newStr
[count
] = (SeparatorChar
[number
->number
] ? SeparatorChar
[number
->number
] : str
[i
]);
234 newStr
[count
] = str
[i
];
236 offset
[count
] = i
+ startPos
;
245 offset
.realloc(count
);
246 aRet
= OUString(newStr
, count
);
251 static void SAL_CALL
NativeToAscii_numberMaker(sal_Int16 max
, sal_Int16 prev
, const sal_Unicode
*str
,
252 sal_Int32
& i
, sal_Int32 nCount
, sal_Unicode
*dst
, sal_Int32
& count
, Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
,
253 OUString
& numberChar
, OUString
& multiplierChar
)
255 sal_Int16 curr
= 0, num
= 0, end
= 0, shift
= 0;
256 while (++i
< nCount
) {
257 if ((curr
= sal::static_int_cast
<sal_Int16
>( numberChar
.indexOf(str
[i
]) )) >= 0) {
261 } else if ((curr
= sal::static_int_cast
<sal_Int16
>( multiplierChar
.indexOf(str
[i
]) )) >= 0) {
262 curr
= MultiplierExponent_7_CJK
[curr
% ExponentCount_7_CJK
];
263 if (prev
> curr
&& num
== 0) num
= 1; // One may be omitted in informal format
267 else if (curr
> prev
)
271 while (end
++ < prev
) {
272 dst
[count
] = NUMBER_ZERO
+ (end
== prev
? num
: 0);
279 for (sal_Int16 j
= 0; j
< shift
; j
++, count
++) {
280 dst
[count
] = dst
[count
+ curr
];
282 offset
[count
] = offset
[count
+ curr
];
286 NativeToAscii_numberMaker(max
, curr
, str
, i
, nCount
, dst
,
287 count
, offset
, useOffset
, numberChar
, multiplierChar
);
292 while (end
++ < prev
) {
293 dst
[count
] = NUMBER_ZERO
+ (end
== prev
? num
: 0);
295 offset
[count
] = i
- 1;
300 static OUString SAL_CALL
NativeToAscii(const OUString
& inStr
,
301 sal_Int32 startPos
, sal_Int32 nCount
, Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
) throw(RuntimeException
)
305 sal_Int32 strLen
= inStr
.getLength() - startPos
;
311 const sal_Unicode
*str
= inStr
.getStr() + startPos
;
312 sal_Unicode
*newStr
= new sal_Unicode
[nCount
* MultiplierExponent_7_CJK
[0] + 2];
314 offset
.realloc( nCount
* MultiplierExponent_7_CJK
[0] + 1 );
315 sal_Int32 count
= 0, index
;
318 OUString numberChar
, multiplierChar
, decimalChar
, minusChar
, separatorChar
;
319 numberChar
= OUString((sal_Unicode
*)NumberChar
, 10*NumberChar_Count
);
320 multiplierChar
= OUString((sal_Unicode
*) MultiplierChar_7_CJK
, ExponentCount_7_CJK
*Multiplier_Count
);
321 decimalChar
= OUString(DecimalChar
, NumberChar_Count
);
322 minusChar
= OUString(MinusChar
, NumberChar_Count
);
323 separatorChar
= OUString(SeparatorChar
, NumberChar_Count
);
325 for ( i
= 0; i
< nCount
; i
++) {
326 if ((index
= multiplierChar
.indexOf(str
[i
])) >= 0) {
327 if (count
== 0 || !isNumber(newStr
[count
-1])) { // add 1 in front of multiplier
328 newStr
[count
] = NUMBER_ONE
;
333 index
= MultiplierExponent_7_CJK
[index
% ExponentCount_7_CJK
];
334 NativeToAscii_numberMaker(
335 sal::static_int_cast
<sal_Int16
>( index
), sal::static_int_cast
<sal_Int16
>( index
),
336 str
, i
, nCount
, newStr
, count
, offset
, useOffset
,
337 numberChar
, multiplierChar
);
339 if ((index
= numberChar
.indexOf(str
[i
])) >= 0)
340 newStr
[count
] = sal::static_int_cast
<sal_Unicode
>( (index
% 10) + NUMBER_ZERO
);
341 else if ((index
= separatorChar
.indexOf(str
[i
])) >= 0 &&
342 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
343 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
344 newStr
[count
] = SeparatorChar
[NumberChar_HalfWidth
];
345 else if ((index
= decimalChar
.indexOf(str
[i
])) >= 0 &&
346 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
347 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
348 // Only when decimal point is followed by numbers,
349 // it will be convert to ASCII decimal point
350 newStr
[count
] = DecimalChar
[NumberChar_HalfWidth
];
351 else if ((index
= minusChar
.indexOf(str
[i
])) >= 0 &&
352 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
353 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
354 // Only when minus is followed by numbers,
355 // it will be convert to ASCII minus sign
356 newStr
[count
] = MinusChar
[NumberChar_HalfWidth
];
358 newStr
[count
] = str
[i
];
366 offset
.realloc(count
);
367 for (i
= 0; i
< count
; i
++)
368 offset
[i
] += startPos
;
370 aRet
= OUString(newStr
, count
);
376 static Number natnum4
[4] = {
377 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh
], 0,
378 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
379 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh_TW
], 0,
380 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
381 { NumberChar_Modern_ja
, MultiplierChar_7_CJK
[Multiplier_Modern_ja
], NUMBER_OMIT_ZERO_ONE_67
,
382 ExponentCount_7_CJK
, MultiplierExponent_7_CJK
},
383 { NumberChar_Lower_ko
, MultiplierChar_6_CJK
[Multiplier_Lower_ko
], NUMBER_OMIT_ZERO
,
384 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
387 static Number natnum5
[4] = {
388 { NumberChar_Upper_zh
, MultiplierChar_6_CJK
[Multiplier_Upper_zh
], 0,
389 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
390 { NumberChar_Upper_zh_TW
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], 0,
391 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
392 { NumberChar_Traditional_ja
, MultiplierChar_7_CJK
[Multiplier_Traditional_ja
], NUMBER_OMIT_ZERO_ONE_67
,
393 ExponentCount_7_CJK
, MultiplierExponent_7_CJK
},
394 { NumberChar_Upper_ko
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], NUMBER_OMIT_ZERO
,
395 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
398 static Number natnum6
[4] = {
399 { NumberChar_FullWidth
, MultiplierChar_6_CJK
[Multiplier_Lower_zh
], 0,
400 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
401 { NumberChar_FullWidth
, MultiplierChar_6_CJK
[Multiplier_Lower_zh_TW
], 0,
402 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
403 { NumberChar_FullWidth
, MultiplierChar_7_CJK
[Multiplier_Modern_ja
], NUMBER_OMIT_ZERO_ONE_67
,
404 ExponentCount_7_CJK
, MultiplierExponent_7_CJK
},
405 { NumberChar_FullWidth
, MultiplierChar_6_CJK
[Multiplier_Hangul_ko
], NUMBER_OMIT_ZERO
,
406 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
409 static Number natnum7
[4] = {
410 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh
], NUMBER_OMIT_ALL
,
411 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
412 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh_TW
], NUMBER_OMIT_ALL
,
413 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
414 { NumberChar_Modern_ja
, MultiplierChar_2_CJK
[Multiplier_Modern_ja
], NUMBER_OMIT_ZERO_ONE
,
415 ExponentCount_2_CJK
, MultiplierExponent_2_CJK
},
416 { NumberChar_Lower_ko
, MultiplierChar_6_CJK
[Multiplier_Lower_ko
], NUMBER_OMIT_ALL
,
417 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
420 static Number natnum8
[4] = {
421 { NumberChar_Upper_zh
, MultiplierChar_6_CJK
[Multiplier_Upper_zh
], NUMBER_OMIT_ALL
,
422 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
423 { NumberChar_Upper_zh_TW
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], NUMBER_OMIT_ALL
,
424 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
425 { NumberChar_Traditional_ja
, MultiplierChar_2_CJK
[Multiplier_Traditional_ja
], NUMBER_OMIT_ZERO_ONE
,
426 ExponentCount_2_CJK
, MultiplierExponent_2_CJK
},
427 { NumberChar_Upper_ko
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], NUMBER_OMIT_ALL
,
428 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
431 static Number natnum10
= { NumberChar_Hangul_ko
, MultiplierChar_6_CJK
[Multiplier_Hangul_ko
], NUMBER_OMIT_ZERO
,
432 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
};
433 static Number natnum11
= { NumberChar_Hangul_ko
, MultiplierChar_6_CJK
[Multiplier_Hangul_ko
], NUMBER_OMIT_ALL
,
434 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
};
436 //! ATTENTION: Do not change order of elements!
437 //! Append new languages to the end of the list!
438 static const sal_Char
*natnum1Locales
[] = {
465 static sal_Int16 nbOfLocale
= SAL_N_ELEMENTS(natnum1Locales
);
467 //! ATTENTION: Do not change order of elements!
468 //! Number and order must match elements of natnum1Locales!
469 static sal_Int16 natnum1
[] = {
472 NumberChar_Modern_ja
,
494 NumberChar_EastIndic_ar
496 static sal_Int16 sizeof_natnum1
= SAL_N_ELEMENTS(natnum1
);
498 //! ATTENTION: Do not change order of elements!
499 //! Order must match first elements of natnum1Locales!
500 static sal_Int16 natnum2
[] = {
502 NumberChar_Upper_zh_TW
,
503 NumberChar_Traditional_ja
,
507 static sal_Int16 sizeof_natnum2
= SAL_N_ELEMENTS(natnum2
);
509 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2)
511 static sal_Int16 SAL_CALL
getLanguageNumber( const Locale
& rLocale
)
513 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
514 if (isLang("zh")) return MsLangId::isTraditionalChinese(rLocale
) ? 1 : 0;
516 for (sal_Int16 i
= 2; i
< nbOfLocale
; i
++)
517 if (isLang(natnum1Locales
[i
]))
523 OUString SAL_CALL
NativeNumberSupplier::getNativeNumberString(const OUString
& aNumberString
, const Locale
& rLocale
,
524 sal_Int16 nNativeNumberMode
, Sequence
< sal_Int32
>& offset
) throw (RuntimeException
)
529 if (isValidNatNum(rLocale
, nNativeNumberMode
)) {
530 sal_Int16 langnum
= getLanguageNumber(rLocale
);
531 switch (nNativeNumberMode
) {
532 case NativeNumberMode::NATNUM0
: // Ascii
533 return NativeToAscii(aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
);
534 case NativeNumberMode::NATNUM1
: // Char, Lower
535 num
= natnum1
[langnum
];
537 case NativeNumberMode::NATNUM2
: // Char, Upper
538 num
= natnum2
[langnum
];
540 case NativeNumberMode::NATNUM3
: // Char, FullWidth
541 num
= NumberChar_FullWidth
;
543 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
544 number
= &natnum4
[langnum
];
546 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
547 number
= &natnum5
[langnum
];
549 case NativeNumberMode::NATNUM6
: // Text, FullWidth
550 number
= &natnum6
[langnum
];
552 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
553 number
= &natnum7
[langnum
];
555 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
556 number
= &natnum8
[langnum
];
558 case NativeNumberMode::NATNUM9
: // Char, Hangul
559 num
= NumberChar_Hangul_ko
;
561 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
564 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
572 if (number
|| num
>= 0) {
573 if (!aLocale
.Language
.equals(rLocale
.Language
) ||
574 !aLocale
.Country
.equals(rLocale
.Country
) ||
575 !aLocale
.Variant
.equals(rLocale
.Variant
)) {
576 LocaleDataItem item
= LocaleData().getLocaleItem( rLocale
);
578 DecimalChar
[NumberChar_HalfWidth
]=item
.decimalSeparator
.toChar();
579 if (DecimalChar
[NumberChar_HalfWidth
] > 0x7E || DecimalChar
[NumberChar_HalfWidth
] < 0x21)
580 DecimalChar
[NumberChar_FullWidth
]=0xFF0E;
582 DecimalChar
[NumberChar_FullWidth
]=DecimalChar
[NumberChar_HalfWidth
]+0xFEE0;
583 SeparatorChar
[NumberChar_HalfWidth
]=item
.thousandSeparator
.toChar();
584 if (SeparatorChar
[NumberChar_HalfWidth
] > 0x7E || SeparatorChar
[NumberChar_HalfWidth
] < 0x21)
585 SeparatorChar
[NumberChar_FullWidth
]=0xFF0C;
587 SeparatorChar
[NumberChar_FullWidth
]=SeparatorChar
[NumberChar_HalfWidth
]+0xFEE0;
590 return AsciiToNative( aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
, number
);
591 else if (num
== NumberChar_he
)
592 return getHebrewNativeNumberString(aNumberString
,
593 nNativeNumberMode
== NativeNumberMode::NATNUM2
);
595 return AsciiToNativeChar(aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
, num
);
598 return aNumberString
;
601 OUString SAL_CALL
NativeNumberSupplier::getNativeNumberString(const OUString
& aNumberString
, const Locale
& rLocale
,
602 sal_Int16 nNativeNumberMode
) throw (RuntimeException
)
604 Sequence
< sal_Int32
> offset
;
605 return getNativeNumberString(aNumberString
, rLocale
, nNativeNumberMode
, offset
);
608 sal_Unicode SAL_CALL
NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar
, const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw(com::sun::star::uno::RuntimeException
)
610 if (nNativeNumberMode
== NativeNumberMode::NATNUM0
) { // Ascii
611 for (sal_Int16 i
= 0; i
< NumberChar_Count
; i
++)
612 for (sal_Int16 j
= 0; j
< 10; j
++)
613 if (inChar
== NumberChar
[i
][j
])
617 else if (isNumber(inChar
) && isValidNatNum(rLocale
, nNativeNumberMode
)) {
618 sal_Int16 langnum
= getLanguageNumber(rLocale
);
619 switch (nNativeNumberMode
) {
620 case NativeNumberMode::NATNUM1
: // Char, Lower
621 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
622 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
623 return NumberChar
[natnum1
[langnum
]][inChar
- NUMBER_ZERO
];
624 case NativeNumberMode::NATNUM2
: // Char, Upper
625 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
626 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
627 return NumberChar
[natnum2
[langnum
]][inChar
- NUMBER_ZERO
];
628 case NativeNumberMode::NATNUM3
: // Char, FullWidth
629 case NativeNumberMode::NATNUM6
: // Text, FullWidth
630 return NumberChar
[NumberChar_FullWidth
][inChar
- NUMBER_ZERO
];
631 case NativeNumberMode::NATNUM9
: // Char, Hangul
632 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
633 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
634 return NumberChar
[NumberChar_Hangul_ko
][inChar
- NUMBER_ZERO
];
642 sal_Bool SAL_CALL
NativeNumberSupplier::isValidNatNum( const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw (RuntimeException
)
644 sal_Int16 langnum
= getLanguageNumber(rLocale
);
646 switch (nNativeNumberMode
) {
647 case NativeNumberMode::NATNUM0
: // Ascii
648 case NativeNumberMode::NATNUM3
: // Char, FullWidth
650 case NativeNumberMode::NATNUM1
: // Char, Lower
651 return (langnum
>= 0);
652 case NativeNumberMode::NATNUM2
: // Char, Upper
653 if (langnum
== 4) // Hebrew numbering
655 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
656 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
657 case NativeNumberMode::NATNUM6
: // Text, FullWidth
658 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
659 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
660 return (langnum
>= 0 && langnum
< 4); // CJK numbering
661 case NativeNumberMode::NATNUM9
: // Char, Hangul
662 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
663 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
664 return (langnum
== 3); // Korean numbering
669 NativeNumberXmlAttributes SAL_CALL
NativeNumberSupplier::convertToXmlAttributes( const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw (RuntimeException
)
671 static const sal_Int16 attShort
= 0;
672 static const sal_Int16 attMedium
= 1;
673 static const sal_Int16 attLong
= 2;
674 static const sal_Char
*attType
[] = { "short", "medium", "long" };
676 sal_Int16 number
= NumberChar_HalfWidth
, type
= attShort
;
678 if (isValidNatNum(rLocale
, nNativeNumberMode
)) {
679 sal_Int16 langnum
= getLanguageNumber(rLocale
);
680 switch (nNativeNumberMode
) {
681 case NativeNumberMode::NATNUM0
: // Ascii
682 number
= NumberChar_HalfWidth
;
685 case NativeNumberMode::NATNUM1
: // Char, Lower
686 number
= natnum1
[langnum
];
689 case NativeNumberMode::NATNUM2
: // Char, Upper
690 number
= natnum2
[langnum
];
691 type
= number
== NumberChar_he
? attMedium
: attShort
;
693 case NativeNumberMode::NATNUM3
: // Char, FullWidth
694 number
= NumberChar_FullWidth
;
697 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
698 number
= natnum1
[langnum
];
701 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
702 number
= natnum2
[langnum
];
705 case NativeNumberMode::NATNUM6
: // Text, FullWidth
706 number
= NumberChar_FullWidth
;
709 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
710 number
= natnum1
[langnum
];
713 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
714 number
= natnum2
[langnum
];
717 case NativeNumberMode::NATNUM9
: // Char, Hangul
718 number
= NumberChar_Hangul_ko
;
721 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
722 number
= NumberChar_Hangul_ko
;
725 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
726 number
= NumberChar_Hangul_ko
;
733 return NativeNumberXmlAttributes(rLocale
, OUString(&NumberChar
[number
][1], 1),
734 OUString::createFromAscii(attType
[type
]));
737 static sal_Bool
natNumIn(sal_Int16 num
, sal_Int16 natnum
[], sal_Int16 len
)
739 for (sal_Int16 i
= 0; i
< len
; i
++)
740 if (natnum
[i
] == num
)
745 sal_Int16 SAL_CALL
NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes
& aAttr
) throw (RuntimeException
)
747 sal_Unicode numberChar
[NumberChar_Count
];
748 for (sal_Int16 i
= 0; i
< NumberChar_Count
; i
++)
749 numberChar
[i
] = NumberChar
[i
][1];
750 OUString
number(numberChar
, NumberChar_Count
);
752 sal_Int16 num
= sal::static_int_cast
<sal_Int16
>( number
.indexOf(aAttr
.Format
) );
754 if ( aAttr
.Style
== "short" ) {
755 if (num
== NumberChar_FullWidth
)
756 return NativeNumberMode::NATNUM3
;
757 else if (num
== NumberChar_Hangul_ko
)
758 return NativeNumberMode::NATNUM9
;
759 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
760 return NativeNumberMode::NATNUM1
;
761 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
762 return NativeNumberMode::NATNUM2
;
763 } else if ( aAttr
.Style
== "medium" ) {
764 if (num
== NumberChar_Hangul_ko
)
765 return NativeNumberMode::NATNUM11
;
766 else if (num
== NumberChar_he
)
767 return NativeNumberMode::NATNUM2
;
768 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
769 return NativeNumberMode::NATNUM7
;
770 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
771 return NativeNumberMode::NATNUM8
;
772 } else if ( aAttr
.Style
== "long" ) {
773 if (num
== NumberChar_FullWidth
)
774 return NativeNumberMode::NATNUM6
;
775 else if (num
== NumberChar_Hangul_ko
)
776 return NativeNumberMode::NATNUM10
;
777 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
778 return NativeNumberMode::NATNUM4
;
779 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
780 return NativeNumberMode::NATNUM5
;
782 throw RuntimeException();
784 return NativeNumberMode::NATNUM0
;
788 // Following code generates Hebrew Number,
789 // see numerical system in the Hebrew Numbering System in following link for details,
790 // http://smontagu.org/writings/HebrewNumbers.html
792 struct HebrewNumberChar
{
795 } HebrewNumberCharArray
[] = {
821 static sal_Int16 nbOfHebrewNumberChar
= sizeof(HebrewNumberCharArray
)/sizeof(HebrewNumberChar
);
823 static sal_Unicode thousand
[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
824 static sal_Unicode thousands
[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
825 static sal_Unicode thousands_last
[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
826 static sal_Unicode geresh
= 0x05f3;
827 static sal_Unicode gershayim
= 0x05f4;
829 void makeHebrewNumber(sal_Int64 value
, OUStringBuffer
& output
, sal_Bool isLast
, sal_Bool useGeresh
)
831 sal_Int16 num
= sal::static_int_cast
<sal_Int16
>(value
% 1000);
834 makeHebrewNumber(value
/ 1000, output
, num
!= 0, useGeresh
);
835 output
.appendAscii(" ");
838 output
.append(value
== 1000 ? thousand
: isLast
? thousands_last
: thousands
);
840 sal_Int16 nbOfChar
= 0;
841 for (sal_Int32 j
= 0; num
> 0 && j
< nbOfHebrewNumberChar
; j
++) {
842 if (num
- HebrewNumberCharArray
[j
].value
>= 0) {
844 if (num
== 15 || num
== 16) // substitution for 15 and 16
846 num
= sal::static_int_cast
<sal_Int16
>( num
- HebrewNumberCharArray
[j
].value
);
847 output
.append(HebrewNumberCharArray
[j
].code
);
851 if (nbOfChar
> 1) // a number is written as more than one character
852 output
.insert(output
.getLength() - 1, gershayim
);
853 else if (nbOfChar
== 1) // a number is written as a single character
854 output
.append(geresh
);
859 OUString SAL_CALL
getHebrewNativeNumberString(const OUString
& aNumberString
, sal_Bool useGeresh
)
862 sal_Int32 i
, count
= 0, len
= aNumberString
.getLength();
863 const sal_Unicode
*src
= aNumberString
.getStr();
865 for (i
= 0; i
< len
; i
++) {
866 sal_Unicode ch
= src
[i
];
868 if (++count
>= 20) // Number is too long, could not be handled.
869 return aNumberString
;
870 value
= value
* 10 + (ch
- NUMBER_ZERO
);
872 else if (isSeparator(ch
) && count
> 0) continue;
873 else if (isMinus(ch
) && count
== 0) continue;
878 OUStringBuffer
output(count
*2 + 2 + len
- i
);
880 makeHebrewNumber(value
, output
, sal_True
, useGeresh
);
883 output
.append(aNumberString
.copy(i
));
885 return output
.makeStringAndClear();
888 return aNumberString
;
891 static const sal_Char
* implementationName
= "com.sun.star.i18n.NativeNumberSupplier";
893 OUString SAL_CALL
NativeNumberSupplier::getImplementationName() throw( RuntimeException
)
895 return OUString::createFromAscii( implementationName
);
899 NativeNumberSupplier::supportsService(const OUString
& rServiceName
) throw( RuntimeException
)
901 return rServiceName
.compareToAscii(implementationName
) == 0;
904 Sequence
< OUString
> SAL_CALL
905 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException
)
907 Sequence
< OUString
> aRet(1);
908 aRet
[0] = OUString::createFromAscii( implementationName
);
914 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */