1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: nativenumbersupplier.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_i18npool.hxx"
34 #include <rtl/ustrbuf.hxx>
35 #include <nativenumbersupplier.hxx>
36 #include <localedata.hxx>
37 #include <data/numberchar.h>
38 #include <i18nutil/x_rtl_ustring.h>
40 using namespace ::com::sun::star::uno
;
41 using namespace ::com::sun::star::lang
;
42 using namespace ::com::sun::star::lang
;
43 using namespace ::rtl
;
48 sal_Unicode
*multiplierChar
;
50 sal_Int16 exponentCount
;
51 sal_Int16
*multiplierExponent
;
55 #define NUMBER_OMIT_ZERO (1 << 0)
56 #define NUMBER_OMIT_ONLY_ZERO (1 << 1)
57 #define NUMBER_OMIT_ONE_1 (1 << 2)
58 #define NUMBER_OMIT_ONE_2 (1 << 3)
59 #define NUMBER_OMIT_ONE_3 (1 << 4)
60 #define NUMBER_OMIT_ONE_4 (1 << 5)
61 #define NUMBER_OMIT_ONE_5 (1 << 6)
62 #define NUMBER_OMIT_ONE_6 (1 << 7)
63 #define NUMBER_OMIT_ONE_7 (1 << 8)
64 #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)
65 #define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit))
66 #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
67 #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
68 #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
69 #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
72 #define MAX_SAL_UINT32 0xFFFFFFFF
73 #define MAX_VALUE (MAX_SAL_UINT32 - 9) / 10
75 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{
77 OUString SAL_CALL
getHebrewNativeNumberString(const OUString
& aNumberString
, sal_Bool useGeresh
);
79 OUString SAL_CALL
AsciiToNativeChar( const OUString
& inStr
, sal_Int32 startPos
, sal_Int32 nCount
,
80 Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
, sal_Int16 number
) throw(RuntimeException
)
82 const sal_Unicode
*src
= inStr
.getStr() + startPos
;
83 rtl_uString
*newStr
= x_rtl_uString_new_WithLength(nCount
);
85 offset
.realloc(nCount
);
87 for (sal_Int32 i
= 0; i
< nCount
; i
++) {
88 sal_Unicode ch
= src
[i
];
90 newStr
->buffer
[i
] = NumberChar
[number
][ ch
- NUMBER_ZERO
];
91 else if (i
+1 < nCount
&& isNumber(src
[i
+1])) {
92 if (i
> 0 && isNumber(src
[i
-1]) && isSeparator(ch
))
93 newStr
->buffer
[i
] = SeparatorChar
[number
] ? SeparatorChar
[number
] : ch
;
95 newStr
->buffer
[i
] = isDecimal(ch
) ? (DecimalChar
[number
] ? DecimalChar
[number
] : ch
) :
96 isMinus(ch
) ? (MinusChar
[number
] ? MinusChar
[number
] : ch
) : ch
;
99 newStr
->buffer
[i
] = ch
;
101 offset
[i
] = startPos
+ i
;
103 return OUString(newStr
->buffer
, nCount
);
106 sal_Bool SAL_CALL
AsciiToNative_numberMaker(const sal_Unicode
*str
, sal_Int32 begin
, sal_Int32 len
,
107 sal_Unicode
*dst
, sal_Int32
& count
, sal_Int16 multiChar_index
, Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
, sal_Int32 startPos
,
108 Number
*number
, sal_Unicode
* numberChar
)
110 sal_Unicode multiChar
= (multiChar_index
== -1 ? 0 : number
->multiplierChar
[multiChar_index
]);
111 if ( len
<= number
->multiplierExponent
[number
->exponentCount
-1] ) {
112 if (number
->multiplierExponent
[number
->exponentCount
-1] > 1) {
114 sal_Bool notZero
= false;
115 for (i
= 0; i
< len
; i
++, begin
++) {
116 if (notZero
|| str
[begin
] != NUMBER_ZERO
) {
117 dst
[count
] = numberChar
[str
[begin
] - NUMBER_ZERO
];
119 offset
[count
] = begin
+ startPos
;
124 if (notZero
&& multiChar
> 0) {
125 dst
[count
] = multiChar
;
127 offset
[count
] = begin
+ startPos
;
131 } else if (str
[begin
] != NUMBER_ZERO
) {
132 if (!(number
->numberFlag
& (multiChar_index
< 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index
))) || str
[begin
] != NUMBER_ONE
) {
133 dst
[count
] = numberChar
[str
[begin
] - NUMBER_ZERO
];
135 offset
[count
] = begin
+ startPos
;
139 dst
[count
] = multiChar
;
141 offset
[count
] = begin
+ startPos
;
144 } else if (!(number
->numberFlag
& NUMBER_OMIT_ZERO
) && count
> 0 && dst
[count
-1] != numberChar
[0]) {
145 dst
[count
] = numberChar
[0];
147 offset
[count
] = begin
+ startPos
;
150 return str
[begin
] != NUMBER_ZERO
;
152 sal_Bool printPower
= sal_False
;
153 // sal_Int16 last = 0;
154 for (sal_Int16 i
= 1; i
<= number
->exponentCount
; i
++) {
155 sal_Int32 tmp
= len
- (i
== number
->exponentCount
? 0 : number
->multiplierExponent
[i
]);
157 printPower
|= AsciiToNative_numberMaker(str
, begin
, tmp
, dst
, count
,
158 (i
== number
->exponentCount
? -1 : i
), offset
, useOffset
, startPos
, number
, numberChar
);
164 if (count
> 0 && number
->multiplierExponent
[number
->exponentCount
-1] == 1 &&
165 dst
[count
-1] == numberChar
[0])
168 dst
[count
] = multiChar
;
170 offset
[count
] = begin
+ startPos
;
178 OUString SAL_CALL
AsciiToNative( const OUString
& inStr
, sal_Int32 startPos
, sal_Int32 nCount
,
179 Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
, Number
* number
) throw(RuntimeException
)
181 sal_Int32 strLen
= inStr
.getLength() - startPos
;
182 sal_Unicode
*numberChar
= NumberChar
[number
->number
];
188 const sal_Unicode
*str
= inStr
.getStr() + startPos
;
189 rtl_uString
*newStr
= x_rtl_uString_new_WithLength(nCount
* 2);
190 rtl_uString
*srcStr
= x_rtl_uString_new_WithLength(nCount
); // for keeping number without comma
191 sal_Int32 i
, len
= 0, count
= 0;
194 offset
.realloc( nCount
* 2 );
195 sal_Bool doDecimal
= sal_False
;
197 for (i
= 0; i
<= nCount
; i
++) {
198 if (i
< nCount
&& isNumber(str
[i
])) {
200 newStr
->buffer
[count
] = numberChar
[str
[i
] - NUMBER_ZERO
];
202 offset
[count
] = i
+ startPos
;
206 srcStr
->buffer
[len
++] = str
[i
];
209 if (isSeparator(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))
210 continue; // skip comma inside number string
211 sal_Bool notZero
= sal_False
;
212 for (sal_Int32 begin
= 0, end
= len
% number
->multiplierExponent
[0];
213 end
<= len
; begin
= end
, end
+= number
->multiplierExponent
[0]) {
214 if (end
== 0) continue;
215 sal_Int32 _count
= count
;
216 notZero
|= AsciiToNative_numberMaker(srcStr
->buffer
, begin
, end
- begin
, newStr
->buffer
, count
,
217 end
== len
? -1 : 0, offset
, useOffset
, i
- len
+ startPos
, number
, numberChar
);
218 if (count
> 0 && number
->multiplierExponent
[number
->exponentCount
-1] == 1 &&
219 newStr
->buffer
[count
-1] == numberChar
[0])
221 if (notZero
&& _count
== count
) {
223 newStr
->buffer
[count
] = number
->multiplierChar
[0];
225 offset
[count
] = i
- len
+ startPos
;
230 if (! notZero
&& ! (number
->numberFlag
& NUMBER_OMIT_ONLY_ZERO
)) {
231 newStr
->buffer
[count
] = numberChar
[0];
233 offset
[count
] = i
- len
+ startPos
;
239 if ((doDecimal
= (!doDecimal
&& isDecimal(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))) != sal_False
)
240 newStr
->buffer
[count
] = (DecimalChar
[number
->number
] ? DecimalChar
[number
->number
] : str
[i
]);
241 else if (isMinus(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))
242 newStr
->buffer
[count
] = (MinusChar
[number
->number
] ? MinusChar
[number
->number
] : str
[i
]);
243 else if (isSeparator(str
[i
]) && i
< nCount
-1 && isNumber(str
[i
+1]))
244 newStr
->buffer
[count
] = (SeparatorChar
[number
->number
] ? SeparatorChar
[number
->number
] : str
[i
]);
246 newStr
->buffer
[count
] = str
[i
];
248 offset
[count
] = i
+ startPos
;
255 offset
.realloc(count
);
256 return OUString(newStr
->buffer
, count
);
260 static void SAL_CALL
NativeToAscii_numberMaker(sal_Int16 max
, sal_Int16 prev
, const sal_Unicode
*str
,
261 sal_Int32
& i
, sal_Int32 nCount
, sal_Unicode
*dst
, sal_Int32
& count
, Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
,
262 OUString
& numberChar
, OUString
& multiplierChar
)
264 sal_Int16 curr
= 0, num
= 0, end
= 0, shift
= 0;
265 while (++i
< nCount
) {
266 if ((curr
= sal::static_int_cast
<sal_Int16
>( numberChar
.indexOf(str
[i
]) )) >= 0) {
270 } else if ((curr
= sal::static_int_cast
<sal_Int16
>( multiplierChar
.indexOf(str
[i
]) )) >= 0) {
271 curr
= MultiplierExponent_7_CJK
[curr
% ExponentCount_7_CJK
];
272 if (prev
> curr
&& num
== 0) num
= 1; // One may be omitted in informal format
276 else if (curr
> prev
)
280 while (end
++ < prev
) {
281 dst
[count
] = NUMBER_ZERO
+ (end
== prev
? num
: 0);
288 for (sal_Int16 j
= 0; j
< shift
; j
++, count
++) {
289 dst
[count
] = dst
[count
+ curr
];
291 offset
[count
] = offset
[count
+ curr
];
295 NativeToAscii_numberMaker(max
, curr
, str
, i
, nCount
, dst
,
296 count
, offset
, useOffset
, numberChar
, multiplierChar
);
301 while (end
++ < prev
) {
302 dst
[count
] = NUMBER_ZERO
+ (end
== prev
? num
: 0);
304 offset
[count
] = i
- 1;
309 static OUString SAL_CALL
NativeToAscii(const OUString
& inStr
,
310 sal_Int32 startPos
, sal_Int32 nCount
, Sequence
< sal_Int32
>& offset
, sal_Bool useOffset
) throw(RuntimeException
)
312 sal_Int32 strLen
= inStr
.getLength() - startPos
;
318 const sal_Unicode
*str
= inStr
.getStr() + startPos
;
319 rtl_uString
*newStr
= x_rtl_uString_new_WithLength(nCount
* MultiplierExponent_7_CJK
[0] + 1);
321 offset
.realloc( nCount
* MultiplierExponent_7_CJK
[0] + 1 );
322 sal_Int32 count
= 0, index
;
325 OUString numberChar
, multiplierChar
, decimalChar
, minusChar
, separatorChar
;
326 numberChar
= OUString((sal_Unicode
*)NumberChar
, 10*NumberChar_Count
);
327 multiplierChar
= OUString((sal_Unicode
*) MultiplierChar_7_CJK
, ExponentCount_7_CJK
*Multiplier_Count
);
328 decimalChar
= OUString(DecimalChar
, NumberChar_Count
);
329 minusChar
= OUString(MinusChar
, NumberChar_Count
);
330 separatorChar
= OUString(SeparatorChar
, NumberChar_Count
);
332 for ( i
= 0; i
< nCount
; i
++) {
333 if ((index
= multiplierChar
.indexOf(str
[i
])) >= 0) {
334 if (count
== 0 || !isNumber(newStr
->buffer
[count
-1])) { // add 1 in front of multiplier
335 newStr
->buffer
[count
] = NUMBER_ONE
;
340 index
= MultiplierExponent_7_CJK
[index
% ExponentCount_7_CJK
];
341 NativeToAscii_numberMaker(
342 sal::static_int_cast
<sal_Int16
>( index
), sal::static_int_cast
<sal_Int16
>( index
),
343 str
, i
, nCount
, newStr
->buffer
, count
, offset
, useOffset
,
344 numberChar
, multiplierChar
);
346 if ((index
= numberChar
.indexOf(str
[i
])) >= 0)
347 newStr
->buffer
[count
] = sal::static_int_cast
<sal_Unicode
>( (index
% 10) + NUMBER_ZERO
);
348 else if ((index
= separatorChar
.indexOf(str
[i
])) >= 0 &&
349 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
350 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
351 newStr
->buffer
[count
] = SeparatorChar
[NumberChar_HalfWidth
];
352 else if ((index
= decimalChar
.indexOf(str
[i
])) >= 0 &&
353 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
354 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
355 // Only when decimal point is followed by numbers,
356 // it will be convert to ASCII decimal point
357 newStr
->buffer
[count
] = DecimalChar
[NumberChar_HalfWidth
];
358 else if ((index
= minusChar
.indexOf(str
[i
])) >= 0 &&
359 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
360 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
361 // Only when minus is followed by numbers,
362 // it will be convert to ASCII minus sign
363 newStr
->buffer
[count
] = MinusChar
[NumberChar_HalfWidth
];
365 newStr
->buffer
[count
] = str
[i
];
373 offset
.realloc(count
);
374 for (i
= 0; i
< count
; i
++)
375 offset
[i
] += startPos
;
377 return OUString(newStr
->buffer
, count
);
382 static Number natnum4
[4] = {
383 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh
], 0,
384 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
385 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh_TW
], 0,
386 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
387 { NumberChar_Modern_ja
, MultiplierChar_7_CJK
[Multiplier_Modern_ja
], NUMBER_OMIT_ZERO_ONE_67
,
388 ExponentCount_7_CJK
, MultiplierExponent_7_CJK
},
389 { NumberChar_Lower_ko
, MultiplierChar_6_CJK
[Multiplier_Lower_ko
], NUMBER_OMIT_ZERO
,
390 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
393 static Number natnum5
[4] = {
394 { NumberChar_Upper_zh
, MultiplierChar_6_CJK
[Multiplier_Upper_zh
], 0,
395 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
396 { NumberChar_Upper_zh_TW
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], 0,
397 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
398 { NumberChar_Traditional_ja
, MultiplierChar_7_CJK
[Multiplier_Traditional_ja
], NUMBER_OMIT_ZERO_ONE_67
,
399 ExponentCount_7_CJK
, MultiplierExponent_7_CJK
},
400 { NumberChar_Upper_ko
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], NUMBER_OMIT_ZERO
,
401 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
404 static Number natnum6
[4] = {
405 { NumberChar_FullWidth
, MultiplierChar_6_CJK
[Multiplier_Lower_zh
], 0,
406 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
407 { NumberChar_FullWidth
, MultiplierChar_6_CJK
[Multiplier_Lower_zh_TW
], 0,
408 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
409 { NumberChar_FullWidth
, MultiplierChar_7_CJK
[Multiplier_Modern_ja
], NUMBER_OMIT_ZERO_ONE_67
,
410 ExponentCount_7_CJK
, MultiplierExponent_7_CJK
},
411 { NumberChar_FullWidth
, MultiplierChar_6_CJK
[Multiplier_Hangul_ko
], NUMBER_OMIT_ZERO
,
412 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
415 static Number natnum7
[4] = {
416 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh
], NUMBER_OMIT_ALL
,
417 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
418 { NumberChar_Lower_zh
, MultiplierChar_6_CJK
[Multiplier_Lower_zh_TW
], NUMBER_OMIT_ALL
,
419 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
420 { NumberChar_Modern_ja
, MultiplierChar_2_CJK
[Multiplier_Modern_ja
], NUMBER_OMIT_ZERO_ONE
,
421 ExponentCount_2_CJK
, MultiplierExponent_2_CJK
},
422 { NumberChar_Lower_ko
, MultiplierChar_6_CJK
[Multiplier_Lower_ko
], NUMBER_OMIT_ALL
,
423 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
426 static Number natnum8
[4] = {
427 { NumberChar_Upper_zh
, MultiplierChar_6_CJK
[Multiplier_Upper_zh
], NUMBER_OMIT_ALL
,
428 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
429 { NumberChar_Upper_zh_TW
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], NUMBER_OMIT_ALL
,
430 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
431 { NumberChar_Traditional_ja
, MultiplierChar_2_CJK
[Multiplier_Traditional_ja
], NUMBER_OMIT_ZERO_ONE
,
432 ExponentCount_2_CJK
, MultiplierExponent_2_CJK
},
433 { NumberChar_Upper_ko
, MultiplierChar_6_CJK
[Multiplier_Upper_zh_TW
], NUMBER_OMIT_ALL
,
434 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
},
437 static Number natnum10
= { NumberChar_Hangul_ko
, MultiplierChar_6_CJK
[Multiplier_Hangul_ko
], NUMBER_OMIT_ZERO
,
438 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
};
439 static Number natnum11
= { NumberChar_Hangul_ko
, MultiplierChar_6_CJK
[Multiplier_Hangul_ko
], NUMBER_OMIT_ALL
,
440 ExponentCount_6_CJK
, MultiplierExponent_6_CJK
};
442 //! ATTENTION: Do not change order of elements!
443 //! Append new languages to the end of the list!
444 static const sal_Char
*natnum1Locales
[] = {
471 static sal_Int16 nbOfLocale
= sizeof(natnum1Locales
)/sizeof(natnum1Locales
[0]);
473 //! ATTENTION: Do not change order of elements!
474 //! Number and order must match elements of natnum1Locales!
475 static sal_Int16 natnum1
[] = {
478 NumberChar_Modern_ja
,
500 NumberChar_EastIndic_ar
502 static sal_Int16 sizeof_natnum1
= sizeof(natnum1
)/sizeof(natnum1
[0]);
504 //! ATTENTION: Do not change order of elements!
505 //! Order must match first elements of natnum1Locales!
506 static sal_Int16 natnum2
[] = {
508 NumberChar_Upper_zh_TW
,
509 NumberChar_Traditional_ja
,
513 static sal_Int16 sizeof_natnum2
= sizeof(natnum2
)/sizeof(natnum2
[0]);
515 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2)
516 #define isCtry(ctry) rLocale.Country.equalsAsciiL(ctry, 2)
518 static sal_Int16 SAL_CALL
getLanguageNumber( const Locale
& rLocale
)
520 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
521 if (isLang("zh")) return (isCtry("TW") || isCtry("HK") || isCtry("MO")) ? 1 : 0;
523 for (sal_Int16 i
= 2; i
< nbOfLocale
; i
++)
524 if (isLang(natnum1Locales
[i
]))
530 OUString SAL_CALL
NativeNumberSupplier::getNativeNumberString(const OUString
& aNumberString
, const Locale
& rLocale
,
531 sal_Int16 nNativeNumberMode
, Sequence
< sal_Int32
>& offset
) throw (RuntimeException
)
536 if (isValidNatNum(rLocale
, nNativeNumberMode
)) {
537 sal_Int16 langnum
= getLanguageNumber(rLocale
);
538 switch (nNativeNumberMode
) {
539 case NativeNumberMode::NATNUM0
: // Ascii
540 return NativeToAscii(aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
);
541 case NativeNumberMode::NATNUM1
: // Char, Lower
542 num
= natnum1
[langnum
];
544 case NativeNumberMode::NATNUM2
: // Char, Upper
545 num
= natnum2
[langnum
];
547 case NativeNumberMode::NATNUM3
: // Char, FullWidth
548 num
= NumberChar_FullWidth
;
550 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
551 number
= &natnum4
[langnum
];
553 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
554 number
= &natnum5
[langnum
];
556 case NativeNumberMode::NATNUM6
: // Text, FullWidth
557 number
= &natnum6
[langnum
];
559 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
560 number
= &natnum7
[langnum
];
562 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
563 number
= &natnum8
[langnum
];
565 case NativeNumberMode::NATNUM9
: // Char, Hangul
566 num
= NumberChar_Hangul_ko
;
568 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
571 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
579 if (number
|| num
>= 0) {
580 if (!aLocale
.Language
.equals(rLocale
.Language
) ||
581 !aLocale
.Country
.equals(rLocale
.Country
) ||
582 !aLocale
.Variant
.equals(rLocale
.Variant
)) {
583 LocaleDataItem item
= LocaleData().getLocaleItem( rLocale
);
585 DecimalChar
[NumberChar_HalfWidth
]=item
.decimalSeparator
.toChar();
586 if (DecimalChar
[NumberChar_HalfWidth
] > 0x7E || DecimalChar
[NumberChar_HalfWidth
] < 0x21)
587 DecimalChar
[NumberChar_FullWidth
]=0xFF0E;
589 DecimalChar
[NumberChar_FullWidth
]=DecimalChar
[NumberChar_HalfWidth
]+0xFEE0;
590 SeparatorChar
[NumberChar_HalfWidth
]=item
.thousandSeparator
.toChar();
591 if (SeparatorChar
[NumberChar_HalfWidth
] > 0x7E || SeparatorChar
[NumberChar_HalfWidth
] < 0x21)
592 SeparatorChar
[NumberChar_FullWidth
]=0xFF0C;
594 SeparatorChar
[NumberChar_FullWidth
]=SeparatorChar
[NumberChar_HalfWidth
]+0xFEE0;
597 return AsciiToNative( aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
, number
);
598 else if (num
== NumberChar_he
)
599 return getHebrewNativeNumberString(aNumberString
,
600 nNativeNumberMode
== NativeNumberMode::NATNUM2
);
602 return AsciiToNativeChar(aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
, num
);
605 return aNumberString
;
608 OUString SAL_CALL
NativeNumberSupplier::getNativeNumberString(const OUString
& aNumberString
, const Locale
& rLocale
,
609 sal_Int16 nNativeNumberMode
) throw (RuntimeException
)
611 Sequence
< sal_Int32
> offset
;
612 return getNativeNumberString(aNumberString
, rLocale
, nNativeNumberMode
, offset
);
615 sal_Unicode SAL_CALL
NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar
, const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw(com::sun::star::uno::RuntimeException
)
617 if (nNativeNumberMode
== NativeNumberMode::NATNUM0
) { // Ascii
618 for (sal_Int16 i
= 0; i
< NumberChar_Count
; i
++)
619 for (sal_Int16 j
= 0; j
< 10; j
++)
620 if (inChar
== NumberChar
[i
][j
])
624 else if (isNumber(inChar
) && isValidNatNum(rLocale
, nNativeNumberMode
)) {
625 sal_Int16 langnum
= getLanguageNumber(rLocale
);
626 switch (nNativeNumberMode
) {
627 case NativeNumberMode::NATNUM1
: // Char, Lower
628 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
629 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
630 return NumberChar
[natnum1
[langnum
]][inChar
- NUMBER_ZERO
];
631 case NativeNumberMode::NATNUM2
: // Char, Upper
632 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
633 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
634 return NumberChar
[natnum2
[langnum
]][inChar
- NUMBER_ZERO
];
635 case NativeNumberMode::NATNUM3
: // Char, FullWidth
636 case NativeNumberMode::NATNUM6
: // Text, FullWidth
637 return NumberChar
[NumberChar_FullWidth
][inChar
- NUMBER_ZERO
];
638 case NativeNumberMode::NATNUM9
: // Char, Hangul
639 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
640 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
641 return NumberChar
[NumberChar_Hangul_ko
][inChar
- NUMBER_ZERO
];
649 sal_Bool SAL_CALL
NativeNumberSupplier::isValidNatNum( const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw (RuntimeException
)
651 sal_Int16 langnum
= getLanguageNumber(rLocale
);
653 switch (nNativeNumberMode
) {
654 case NativeNumberMode::NATNUM0
: // Ascii
655 case NativeNumberMode::NATNUM3
: // Char, FullWidth
657 case NativeNumberMode::NATNUM1
: // Char, Lower
658 return (langnum
>= 0);
659 case NativeNumberMode::NATNUM2
: // Char, Upper
660 if (langnum
== 4) // Hebrew numbering
662 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
663 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
664 case NativeNumberMode::NATNUM6
: // Text, FullWidth
665 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
666 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
667 return (langnum
>= 0 && langnum
< 4); // CJK numbering
668 case NativeNumberMode::NATNUM9
: // Char, Hangul
669 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
670 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
671 return (langnum
== 3); // Korean numbering
676 NativeNumberXmlAttributes SAL_CALL
NativeNumberSupplier::convertToXmlAttributes( const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw (RuntimeException
)
678 static const sal_Int16 attShort
= 0;
679 static const sal_Int16 attMedium
= 1;
680 static const sal_Int16 attLong
= 2;
681 static const sal_Char
*attType
[] = { "short", "medium", "long" };
683 sal_Int16 number
= NumberChar_HalfWidth
, type
= attShort
;
685 if (isValidNatNum(rLocale
, nNativeNumberMode
)) {
686 sal_Int16 langnum
= getLanguageNumber(rLocale
);
687 switch (nNativeNumberMode
) {
688 case NativeNumberMode::NATNUM0
: // Ascii
689 number
= NumberChar_HalfWidth
;
692 case NativeNumberMode::NATNUM1
: // Char, Lower
693 number
= natnum1
[langnum
];
696 case NativeNumberMode::NATNUM2
: // Char, Upper
697 number
= natnum2
[langnum
];
698 type
= number
== NumberChar_he
? attMedium
: attShort
;
700 case NativeNumberMode::NATNUM3
: // Char, FullWidth
701 number
= NumberChar_FullWidth
;
704 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
705 number
= natnum1
[langnum
];
708 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
709 number
= natnum2
[langnum
];
712 case NativeNumberMode::NATNUM6
: // Text, FullWidth
713 number
= NumberChar_FullWidth
;
716 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
717 number
= natnum1
[langnum
];
720 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
721 number
= natnum2
[langnum
];
724 case NativeNumberMode::NATNUM9
: // Char, Hangul
725 number
= NumberChar_Hangul_ko
;
728 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
729 number
= NumberChar_Hangul_ko
;
732 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
733 number
= NumberChar_Hangul_ko
;
740 return NativeNumberXmlAttributes(rLocale
, OUString(&NumberChar
[number
][1], 1),
741 OUString::createFromAscii(attType
[type
]));
744 static sal_Bool
natNumIn(sal_Int16 num
, sal_Int16 natnum
[], sal_Int16 len
)
746 for (sal_Int16 i
= 0; i
< len
; i
++)
747 if (natnum
[i
] == num
)
752 sal_Int16 SAL_CALL
NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes
& aAttr
) throw (RuntimeException
)
754 sal_Unicode numberChar
[NumberChar_Count
];
755 for (sal_Int16 i
= 0; i
< NumberChar_Count
; i
++)
756 numberChar
[i
] = NumberChar
[i
][1];
757 OUString
number(numberChar
, NumberChar_Count
);
759 sal_Int16 num
= sal::static_int_cast
<sal_Int16
>( number
.indexOf(aAttr
.Format
) );
761 if (aAttr
.Style
.equalsAscii("short")) {
762 if (num
== NumberChar_FullWidth
)
763 return NativeNumberMode::NATNUM3
;
764 else if (num
== NumberChar_Hangul_ko
)
765 return NativeNumberMode::NATNUM9
;
766 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
767 return NativeNumberMode::NATNUM1
;
768 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
769 return NativeNumberMode::NATNUM2
;
770 } else if (aAttr
.Style
.equalsAscii("medium")) {
771 if (num
== NumberChar_Hangul_ko
)
772 return NativeNumberMode::NATNUM11
;
773 else if (num
== NumberChar_he
)
774 return NativeNumberMode::NATNUM2
;
775 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
776 return NativeNumberMode::NATNUM7
;
777 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
778 return NativeNumberMode::NATNUM8
;
779 } else if (aAttr
.Style
.equalsAscii("long")) {
780 if (num
== NumberChar_FullWidth
)
781 return NativeNumberMode::NATNUM6
;
782 else if (num
== NumberChar_Hangul_ko
)
783 return NativeNumberMode::NATNUM10
;
784 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
785 return NativeNumberMode::NATNUM4
;
786 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
787 return NativeNumberMode::NATNUM5
;
789 throw RuntimeException();
791 return NativeNumberMode::NATNUM0
;
795 // Following code generates Hebrew Number,
796 // see numerical system in the Hebrew Numbering System in following link for details,
797 // http://people.netscape.com/smontagu/writings/HebrewNumbers.html
799 struct HebrewNumberChar
{
802 } HebrewNumberCharArray
[] = {
828 static sal_Int16 nbOfHebrewNumberChar
= sizeof(HebrewNumberCharArray
)/sizeof(HebrewNumberChar
);
830 static sal_Unicode thousand
[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
831 static sal_Unicode thousands
[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
832 static sal_Unicode thousands_last
[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
833 static sal_Unicode geresh
= 0x05f3;
834 static sal_Unicode gershayim
= 0x05f4;
836 void makeHebrewNumber(sal_Int64 value
, OUStringBuffer
& output
, sal_Bool isLast
, sal_Bool useGeresh
)
838 sal_Int16 num
= sal::static_int_cast
<sal_Int16
>(value
% 1000);
841 makeHebrewNumber(value
/ 1000, output
, num
!= 0, useGeresh
);
842 output
.appendAscii(" ");
845 output
.append(value
== 1000 ? thousand
: isLast
? thousands_last
: thousands
);
847 sal_Int16 nbOfChar
= 0;
848 for (sal_Int32 j
= 0; num
> 0 && j
< nbOfHebrewNumberChar
; j
++) {
849 if (num
- HebrewNumberCharArray
[j
].value
>= 0) {
851 if (num
== 15 || num
== 16) // substitution for 15 and 16
853 num
= sal::static_int_cast
<sal_Int16
>( num
- HebrewNumberCharArray
[j
].value
);
854 output
.append(HebrewNumberCharArray
[j
].code
);
858 if (nbOfChar
> 1) // a number is written as more than one character
859 output
.insert(output
.getLength() - 1, gershayim
);
860 else if (nbOfChar
== 1) // a number is written as a single character
861 output
.append(geresh
);
866 OUString SAL_CALL
getHebrewNativeNumberString(const OUString
& aNumberString
, sal_Bool useGeresh
)
869 sal_Int32 i
, count
= 0, len
= aNumberString
.getLength();
870 const sal_Unicode
*src
= aNumberString
.getStr();
871 sal_Bool neg
= sal_False
;
873 for (i
= 0; i
< len
; i
++) {
874 sal_Unicode ch
= src
[i
];
876 if (++count
>= 20) // Number is too long, could not be handled.
877 return aNumberString
;
878 value
= value
* 10 + (ch
- NUMBER_ZERO
);
880 else if (isSeparator(ch
) && count
> 0) continue;
881 else if (isMinus(ch
) && count
== 0) neg
= sal_True
;
886 OUStringBuffer
output(count
*2 + 2 + len
- i
);
888 makeHebrewNumber(value
, output
, sal_True
, useGeresh
);
891 output
.append(aNumberString
.copy(i
));
893 return output
.makeStringAndClear();
896 return aNumberString
;
899 static const sal_Char
* implementationName
= "com.sun.star.i18n.NativeNumberSupplier";
901 OUString SAL_CALL
NativeNumberSupplier::getImplementationName() throw( RuntimeException
)
903 return OUString::createFromAscii( implementationName
);
907 NativeNumberSupplier::supportsService(const OUString
& rServiceName
) throw( RuntimeException
)
909 return rServiceName
.compareToAscii(implementationName
) == 0;
912 Sequence
< OUString
> SAL_CALL
913 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException
)
915 Sequence
< OUString
> aRet(1);
916 aRet
[0] = OUString::createFromAscii( implementationName
);