LibreOffice Module i18npool (master) 1
nativenumbersupplier.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
22#include <rtl/ustrbuf.hxx>
23#include <sal/macros.h>
25#include <localedata.hxx>
26#include "data/numberchar.h"
29#include <o3tl/string_view.hxx>
30#include <cstddef>
31#include <map>
32#include <mutex>
33#include <memory>
34#include <string_view>
35#include <unordered_map>
36#include <com/sun/star/i18n/CharacterClassification.hpp>
37#include <com/sun/star/i18n/NativeNumberMode.hpp>
38#include <com/sun/star/linguistic2/NumberText.hpp>
39
40using namespace ::com::sun::star::uno;
41using namespace ::com::sun::star::i18n;
42using namespace ::com::sun::star::lang;
43
44namespace {
45
46struct Number {
47 sal_Int16 number;
48 const sal_Unicode *multiplierChar;
49 sal_Int16 numberFlag;
50 sal_Int16 exponentCount;
51 const sal_Int16 *multiplierExponent;
52};
53
54}
55
56#define NUMBER_OMIT_ZERO (1 << 0)
57#define NUMBER_OMIT_ONLY_ZERO (1 << 1)
58#define NUMBER_OMIT_ONE_1 (1 << 2)
59#define NUMBER_OMIT_ONE_2 (1 << 3)
60#define NUMBER_OMIT_ONE_3 (1 << 4)
61#define NUMBER_OMIT_ONE_4 (1 << 5)
62#define NUMBER_OMIT_ONE_5 (1 << 6)
63#define NUMBER_OMIT_ONE_6 (1 << 7)
64#define NUMBER_OMIT_ONE_7 (1 << 8)
65#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)
66#define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit))
67#define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
68#define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
69#define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
70#define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
71
72namespace i18npool {
73
74namespace {
75
76std::mutex theNatNumMutex;
77
78}
79
80static OUString getHebrewNativeNumberString(const OUString& aNumberString, bool useGeresh);
81
82static OUString getCyrillicNativeNumberString(const OUString& aNumberString);
83
85static OUString AsciiToNativeChar( const OUString& inStr, sal_Int32 nCount,
86 Sequence< sal_Int32 >* pOffset, sal_Int16 number )
87{
88 const sal_Unicode *src = inStr.getStr();
89 rtl_uString *newStr = rtl_uString_alloc(nCount);
90 if (pOffset)
91 pOffset->realloc(nCount);
92 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
93
94 for (sal_Int32 i = 0; i < nCount; i++)
95 {
96 sal_Unicode ch = src[i];
97 if (isNumber(ch))
98 newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ];
99 else if (i+1 < nCount && isNumber(src[i+1])) {
100 if (i > 0 && isNumber(src[i-1]) && isSeparator(ch))
101 newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch;
102 else
103 newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) :
104 isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch;
105 }
106 else
107 newStr->buffer[i] = ch;
108 if (ppOffset)
109 ppOffset[i] = i;
110 }
111 return OUString(newStr, SAL_NO_ACQUIRE); // take ownership
112}
113
114static bool AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len,
115 sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >* pOffset, sal_Int32 startPos,
116 const Number *number, const sal_Unicode* numberChar)
117{
118 sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]);
119 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
120 if ( len <= number->multiplierExponent[number->exponentCount-1] ) {
121 if (number->multiplierExponent[number->exponentCount-1] > 1) {
122 bool bNotZero = false;
123 for (const sal_Int32 end = begin+len; begin < end; begin++) {
124 if (bNotZero || str[begin] != NUMBER_ZERO) {
125 dst[count] = numberChar[str[begin] - NUMBER_ZERO];
126 if (ppOffset)
127 ppOffset[count] = begin + startPos;
128 count++;
129 bNotZero = true;
130 }
131 }
132 if (bNotZero && multiChar > 0) {
133 dst[count] = multiChar;
134 if (ppOffset)
135 ppOffset[count] = begin + startPos;
136 count++;
137 }
138 return bNotZero;
139 } else if (str[begin] != NUMBER_ZERO) {
140 if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) {
141 dst[count] = numberChar[str[begin] - NUMBER_ZERO];
142 if (ppOffset)
143 ppOffset[count] = begin + startPos;
144 count++;
145 }
146 if (multiChar > 0) {
147 dst[count] = multiChar;
148 if (ppOffset)
149 ppOffset[count] = begin + startPos;
150 count++;
151 }
152 } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) {
153 dst[count] = numberChar[0];
154 if (ppOffset)
155 ppOffset[count] = begin + startPos;
156 count++;
157 }
158 return str[begin] != NUMBER_ZERO;
159 } else {
160 bool bPrintPower = false;
161 // sal_Int16 last = 0;
162 for (sal_Int16 i = 1; i <= number->exponentCount; i++) {
163 sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]);
164 if (tmp > 0) {
165 bPrintPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count,
166 (i == number->exponentCount ? -1 : i), pOffset, startPos, number, numberChar);
167 begin += tmp;
168 len -= tmp;
169 }
170 }
171 if (bPrintPower) {
172 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
173 dst[count-1] == numberChar[0])
174 count--;
175 if (multiChar > 0) {
176 dst[count] = multiChar;
177 if (ppOffset)
178 ppOffset[count] = begin + startPos;
179 count++;
180 }
181 }
182 return bPrintPower;
183 }
184}
185
187static OUString AsciiToNative( const OUString& inStr, sal_Int32 nCount,
188 Sequence< sal_Int32 >* pOffset, const Number* number )
189{
190 OUString aRet;
191
192 sal_Int32 strLen = inStr.getLength();
193 const sal_Unicode *numberChar = NumberChar[number->number];
194
195 if (nCount > strLen)
196 nCount = strLen;
197
198 if (nCount > 0)
199 {
200 const sal_Unicode *str = inStr.getStr();
201 std::unique_ptr<sal_Unicode[]> newStr(new sal_Unicode[nCount * 2 + 1]);
202 std::unique_ptr<sal_Unicode[]> srcStr(new sal_Unicode[nCount + 1]); // for keeping number without comma
203 sal_Int32 i, len = 0, count = 0;
204
205 if (pOffset)
206 pOffset->realloc( nCount * 2 );
207 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
208 bool bDoDecimal = false;
209
210 for (i = 0; i <= nCount; i++)
211 {
212 if (i < nCount && isNumber(str[i])) {
213 if (bDoDecimal) {
214 newStr[count] = numberChar[str[i] - NUMBER_ZERO];
215 if (ppOffset)
216 ppOffset[count] = i;
217 count++;
218 }
219 else
220 srcStr[len++] = str[i];
221 } else {
222 if (len > 0) {
223 if (i < nCount-1 && isSeparator(str[i]) && isNumber(str[i+1]))
224 continue; // skip comma inside number string
225 bool bNotZero = false;
226 for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0];
227 end <= len; begin = end, end += number->multiplierExponent[0]) {
228 if (end == 0) continue;
229 sal_Int32 _count = count;
230 bNotZero |= AsciiToNative_numberMaker(srcStr.get(), begin, end - begin, newStr.get(), count,
231 end == len ? -1 : 0, pOffset, i - len, number, numberChar);
232 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
233 newStr[count-1] == numberChar[0])
234 count--;
235 if (bNotZero && _count == count && end != len) {
236 newStr[count] = number->multiplierChar[0];
237 if (ppOffset)
238 ppOffset[count] = i - len;
239 count++;
240 }
241 }
242 if (! bNotZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) {
243 newStr[count] = numberChar[0];
244 if (ppOffset)
245 ppOffset[count] = i - len;
246 count++;
247 }
248 len = 0;
249 }
250 if (i < nCount) {
251 bDoDecimal = (!bDoDecimal && i < nCount-1 && isDecimal(str[i]) && isNumber(str[i+1]));
252 if (bDoDecimal)
253 newStr[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]);
254 else if (i < nCount-1 && isMinus(str[i]) && isNumber(str[i+1]))
255 newStr[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]);
256 else if (i < nCount-1 && isSeparator(str[i]) && isNumber(str[i+1]))
257 newStr[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]);
258 else
259 newStr[count] = str[i];
260 if (ppOffset)
261 ppOffset[count] = i;
262 count++;
263 }
264 }
265 }
266
267 if (pOffset)
268 pOffset->realloc(count);
269 aRet = OUString(newStr.get(), count);
270 }
271 return aRet;
272}
273
274namespace
275{
276void NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str,
277 sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >* pOffset,
278 OUString& numberChar, OUString& multiplierChar)
279{
280 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
281 sal_Int16 curr = 0, num = 0, end = 0, shift = 0;
282 while (++i < nCount) {
283 if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) {
284 if (num > 0)
285 break;
286 num = curr % 10;
287 } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) {
289 if (prev > curr && num == 0) num = 1; // One may be omitted in informal format
290 shift = end = 0;
291 if (curr >= max)
292 max = curr;
293 else if (curr > prev)
294 shift = max - curr;
295 else
296 end = curr;
297 while (end++ < prev) {
298 dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
299 if (ppOffset)
300 ppOffset[count] = i;
301 count++;
302 }
303 if (shift) {
304 count -= max;
305 for (const sal_Int32 countEnd = count+shift; count < countEnd; count++) {
306 dst[count] = dst[count + curr];
307 if (ppOffset)
308 ppOffset[count] = ppOffset[count + curr];
309 }
310 max = curr;
311 }
312 NativeToAscii_numberMaker(max, curr, str, i, nCount, dst,
313 count, pOffset, numberChar, multiplierChar);
314 return;
315 } else
316 break;
317 }
318 while (end++ < prev) {
319 dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
320 if (ppOffset)
321 ppOffset[count] = i - 1;
322 count++;
323 }
324}
325
327OUString NativeToAscii(const OUString& inStr,
328 sal_Int32 nCount, Sequence< sal_Int32 >* pOffset )
329{
330 OUString aRet;
331
332 sal_Int32 strLen = inStr.getLength();
333
334 if (nCount > strLen)
335 nCount = strLen;
336
337 if (nCount > 0) {
338 const sal_Unicode *str = inStr.getStr();
339 std::unique_ptr<sal_Unicode[]> newStr(new sal_Unicode[nCount * MultiplierExponent_7_CJK[0] + 2]);
340 if (pOffset)
341 pOffset->realloc( nCount * MultiplierExponent_7_CJK[0] + 1 );
342 auto ppOffset = pOffset ? pOffset->getArray() : nullptr;
343 sal_Int32 count = 0, index;
344 sal_Int32 i;
345
346 OUString numberChar, multiplierChar, decimalChar, separatorChar;
347 numberChar = OUString(NumberChar[0], 10*NumberChar_Count);
348 multiplierChar = OUString(MultiplierChar_7_CJK[0], ExponentCount_7_CJK*Multiplier_Count);
349 decimalChar = OUString(DecimalChar, NumberChar_Count);
350 std::u16string_view const minusChar(MinusChar, NumberChar_Count);
351 separatorChar = OUString(
352 reinterpret_cast<sal_Unicode *>(SeparatorChar), NumberChar_Count);
353
354 for ( i = 0; i < nCount; i++) {
355 if ((index = multiplierChar.indexOf(str[i])) >= 0) {
356 if (count == 0 || !isNumber(newStr[count-1])) { // add 1 in front of multiplier
357 newStr[count] = NUMBER_ONE;
358 if (ppOffset)
359 ppOffset[count] = i;
360 count++;
361 }
363 NativeToAscii_numberMaker(
364 sal::static_int_cast<sal_Int16>( index ), sal::static_int_cast<sal_Int16>( index ),
365 str, i, nCount, newStr.get(), count, pOffset,
366 numberChar, multiplierChar);
367 } else {
368 if ((index = numberChar.indexOf(str[i])) >= 0)
369 newStr[count] = sal::static_int_cast<sal_Unicode>( (index % 10) + NUMBER_ZERO );
370 else if (separatorChar.indexOf(str[i]) >= 0 &&
371 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
372 multiplierChar.indexOf(str[i+1]) >= 0)))
374 else if (decimalChar.indexOf(str[i]) >= 0 &&
375 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
376 multiplierChar.indexOf(str[i+1]) >= 0)))
377 // Only when decimal point is followed by numbers,
378 // it will be convert to ASCII decimal point
380 else if (minusChar.find(str[i]) != std::u16string_view::npos &&
381 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
382 multiplierChar.indexOf(str[i+1]) >= 0)))
383 // Only when minus is followed by numbers,
384 // it will be convert to ASCII minus sign
386 else
387 newStr[count] = str[i];
388 if (ppOffset)
389 ppOffset[count] = i;
390 count++;
391 }
392 }
393
394 if (pOffset) {
395 pOffset->realloc(count);
396 }
397 aRet = OUString(newStr.get(), count);
398 }
399 return aRet;
400}
401
402const Number natnum4[4] = {
411};
412
413const Number natnum5[4] = {
422};
423
424const Number natnum6[4] = {
433};
434
435const Number natnum7[4] = {
444};
445
446const Number natnum8[4] = {
455};
456
461
464const char *natnum1Locales[] = {
465 "zh_CN",
466 "zh_TW",
467 "ja",
468 "ko",
469 "he",
470 "ar",
471 "th",
472 "hi",
473 "or",
474 "mr",
475 "bn",
476 "pa",
477 "gu",
478 "ta",
479 "te",
480 "kn",
481 "ml",
482 "lo",
483 "bo",
484 "my",
485 "km",
486 "mn",
487 "ne",
488 "dz",
489 "fa",
490 "cu"
491};
492const sal_Int16 nbOfLocale = SAL_N_ELEMENTS(natnum1Locales);
493
496const sal_Int16 natnum1[] = {
523};
524const sal_Int16 sizeof_natnum1 = SAL_N_ELEMENTS(natnum1);
525
528const sal_Int16 natnum2[] = {
534};
535const sal_Int16 sizeof_natnum2 = SAL_N_ELEMENTS(natnum2);
536
537sal_Int16 getLanguageNumber( const Locale& rLocale)
538{
539 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
540 if (rLocale.Language == "zh") return MsLangId::isTraditionalChinese(rLocale) ? 1 : 0;
541
542 for (sal_Int16 i = 2; i < nbOfLocale; i++)
543 if (rLocale.Language.equalsAsciiL(natnum1Locales[i], 2))
544 return i;
545
546 return -1;
547}
548
549struct Separators
550{
553 Separators(const Locale& rLocale)
554 {
555 LocaleDataItem aLocaleItem = LocaleDataImpl::get()->getLocaleItem(rLocale);
556 DecimalSeparator = aLocaleItem.decimalSeparator.toChar();
557 ThousandSeparator = aLocaleItem.thousandSeparator.toChar();
558 }
559};
560
561Separators getLocaleSeparators(const Locale& rLocale, const OUString& rLocStr)
562{
563 // Guard the static variable below.
564 std::scoped_lock aGuard(theNatNumMutex);
565 // Maximum a couple hundred of pairs with 4-byte structs - so no need for smart managing
566 static std::unordered_map<OUString, Separators> aLocaleSeparatorsBuf;
567 auto it = aLocaleSeparatorsBuf.find(rLocStr);
568 if (it == aLocaleSeparatorsBuf.end())
569 {
570 it = aLocaleSeparatorsBuf.emplace(rLocStr, Separators(rLocale)).first;
571 }
572 return it->second;
573}
574
575OUString getNumberText(const Locale& rLocale, const OUString& rNumberString,
576 std::u16string_view sNumberTextParams)
577{
578 sal_Int32 i, count = 0;
579 const sal_Int32 len = rNumberString.getLength();
580 const sal_Unicode* src = rNumberString.getStr();
581
582 OUString aLoc = LanguageTag::convertToBcp47(rLocale);
583 Separators aSeparators = getLocaleSeparators(rLocale, aLoc);
584
585 OUStringBuffer sBuf(len);
586 for (i = 0; i < len; i++)
587 {
588 sal_Unicode ch = src[i];
589 if (isNumber(ch))
590 {
591 ++count;
592 sBuf.append(ch);
593 }
594 else if (ch == aSeparators.DecimalSeparator)
595 // Convert any decimal separator to point - in case libnumbertext has a different one
596 // for this locale (it seems that point is supported for all locales in libnumbertext)
597 sBuf.append('.');
598 else if (ch == aSeparators.ThousandSeparator && count > 0)
599 continue;
600 else if (isMinus(ch) && count == 0)
601 sBuf.append(ch);
602 else
603 break;
604 }
605
606 // Handle also month and day names for NatNum12 date formatting
607 const OUString& rNumberStr = (count == 0) ? rNumberString : sBuf.makeStringAndClear();
608
609 static auto xNumberText
610 = css::linguistic2::NumberText::create(comphelper::getProcessComponentContext());
611
612 // Guard the static variables below.
613 std::scoped_lock aGuard( theNatNumMutex );
614
615 OUString numbertext_prefix;
616 // default "cardinal" gets empty prefix
617 if (!sNumberTextParams.empty() && sNumberTextParams != u"cardinal")
618 numbertext_prefix = OUString::Concat(sNumberTextParams) + " ";
619 // Several hundreds of headings could result typing lags because
620 // of the continuous update of the multiple number names during typing.
621 // We fix this by buffering the result of the conversion.
622 static std::unordered_map<OUString, std::map<OUString, OUString>> aBuff;
623 auto& rItems = aBuff[rNumberStr];
624 auto& rItem = rItems[numbertext_prefix + aLoc];
625 if (rItem.isEmpty())
626 {
627 rItem = xNumberText->getNumberText(numbertext_prefix + rNumberStr, rLocale);
628 // use number at missing number to text conversion
629 if (rItem.isEmpty())
630 rItem = rNumberStr;
631 }
632 OUString sResult = rItem;
633 if (i != 0 && i < len)
634 sResult += rNumberString.subView(i);
635 return sResult;
636}
637}
638
639OUString NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
640 sal_Int16 nNativeNumberMode,
641 Sequence<sal_Int32>* pOffset,
642 std::u16string_view rNativeNumberParams)
643{
644 if (!isValidNatNumImpl(rLocale, nNativeNumberMode))
645 return aNumberString;
646
647 if (nNativeNumberMode == NativeNumberMode::NATNUM12)
648 {
649 // handle capitalization prefixes "capitalize", "upper", "lower" and "title"
650
651 enum WhichCasing
652 {
654 UPPER,
655 LOWER,
656 TITLE
657 };
658
659 struct CasingEntry
660 {
661 std::u16string_view aLiteral;
662 WhichCasing eCasing;
663 };
664
665 static const CasingEntry Casings[] =
666 {
667 { std::u16string_view(u"capitalize"), CAPITALIZE },
668 { std::u16string_view(u"upper"), UPPER },
669 { std::u16string_view(u"lower"), LOWER },
670 { std::u16string_view(u"title"), TITLE }
671 };
672
673 std::size_t nStripCase = 0;
674 size_t nCasing;
675 for (nCasing = 0; nCasing < SAL_N_ELEMENTS(Casings); ++nCasing)
676 {
677 if (o3tl::starts_with(rNativeNumberParams, Casings[nCasing].aLiteral))
678 {
679 nStripCase = Casings[nCasing].aLiteral.size();
680 break;
681 }
682 }
683
684 if (nStripCase > 0 && (rNativeNumberParams.size() == nStripCase ||
685 rNativeNumberParams[nStripCase++] == ' '))
686 {
687 OUString aStr = getNumberText(rLocale, aNumberString, rNativeNumberParams.substr(nStripCase));
688
689 if (!xCharClass.is())
690 xCharClass = CharacterClassification::create(comphelper::getProcessComponentContext());
691
692 switch (Casings[nCasing].eCasing)
693 {
694 case CAPITALIZE:
695 return xCharClass->toTitle(aStr, 0, 1, aLocale) +
696 (aStr.getLength() > 1 ? aStr.subView(1) : u"");
697 case UPPER:
698 return xCharClass->toUpper(aStr, 0, aStr.getLength(), aLocale);
699 case LOWER:
700 return xCharClass->toLower(aStr, 0, aStr.getLength(), aLocale);
701 case TITLE:
702 return xCharClass->toTitle(aStr, 0, aStr.getLength(), aLocale);
703 }
704 }
705 else
706 {
707 return getNumberText(rLocale, aNumberString, rNativeNumberParams);
708 }
709 }
710
711 sal_Int16 langnum = getLanguageNumber(rLocale);
712 if (langnum == -1)
713 return aNumberString;
714
715 const Number *number = nullptr;
716 sal_Int16 num = -1;
717
718 switch (nNativeNumberMode)
719 {
720 case NativeNumberMode::NATNUM0: // Ascii
721 return NativeToAscii(aNumberString, aNumberString.getLength(), pOffset);
722 case NativeNumberMode::NATNUM1: // Char, Lower
723 num = natnum1[langnum];
724 break;
725 case NativeNumberMode::NATNUM2: // Char, Upper
726 num = natnum2[langnum];
727 break;
728 case NativeNumberMode::NATNUM3: // Char, FullWidth
730 break;
731 case NativeNumberMode::NATNUM4: // Text, Lower, Long
732 number = &natnum4[langnum];
733 break;
734 case NativeNumberMode::NATNUM5: // Text, Upper, Long
735 number = &natnum5[langnum];
736 break;
737 case NativeNumberMode::NATNUM6: // Text, FullWidth
738 number = &natnum6[langnum];
739 break;
740 case NativeNumberMode::NATNUM7: // Text. Lower, Short
741 number = &natnum7[langnum];
742 break;
743 case NativeNumberMode::NATNUM8: // Text, Upper, Short
744 number = &natnum8[langnum];
745 break;
746 case NativeNumberMode::NATNUM9: // Char, Hangul
748 break;
749 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
750 number = &natnum10;
751 break;
752 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
753 number = &natnum11;
754 break;
755 default:
756 break;
757 }
758
759 if (number || num >= 0) {
760 if (aLocale.Language != rLocale.Language ||
761 aLocale.Country != rLocale.Country ||
762 aLocale.Variant != rLocale.Variant) {
763 LocaleDataItem item = LocaleDataImpl::get()->getLocaleItem( rLocale );
764 aLocale = rLocale;
765 DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar();
768 else
770 SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar();
773 else
775 }
776 if (number)
777 return AsciiToNative( aNumberString, aNumberString.getLength(), pOffset, number );
778 else if (num == NumberChar_he)
779 return getHebrewNativeNumberString(aNumberString,
780 nNativeNumberMode == NativeNumberMode::NATNUM2);
781 else if (num == NumberChar_cu)
782 return getCyrillicNativeNumberString(aNumberString);
783 else
784 return AsciiToNativeChar(aNumberString, aNumberString.getLength(), pOffset, num);
785 }
786 else
787 return aNumberString;
788}
789
790OUString SAL_CALL NativeNumberSupplierService::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
791 sal_Int16 nNativeNumberMode)
792{
793 return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, nullptr);
794}
795
797 const OUString& rNumberString, const css::lang::Locale& rLocale, sal_Int16 nNativeNumberMode,
798 const OUString& rNativeNumberParams)
799{
800 return getNativeNumberString(rNumberString, rLocale, nNativeNumberMode, nullptr, rNativeNumberParams);
801}
802
803sal_Unicode NativeNumberSupplierService::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode )
804{
805 if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii
806 for (const auto & i : NumberChar)
807 for (sal_Int16 j = 0; j < 10; j++)
808 if (inChar == i[j])
809 return j;
810 return inChar;
811 }
812
813 if (!isNumber(inChar))
814 return inChar;
815
816 if (!isValidNatNumImpl(rLocale, nNativeNumberMode))
817 return inChar;
818
819 sal_Int16 langnum = getLanguageNumber(rLocale);
820 if (langnum == -1)
821 return inChar;
822
823 switch (nNativeNumberMode)
824 {
825 case NativeNumberMode::NATNUM1: // Char, Lower
826 case NativeNumberMode::NATNUM4: // Text, Lower, Long
827 case NativeNumberMode::NATNUM7: // Text. Lower, Short
828 return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO];
829 case NativeNumberMode::NATNUM2: // Char, Upper
830 case NativeNumberMode::NATNUM5: // Text, Upper, Long
831 case NativeNumberMode::NATNUM8: // Text, Upper, Short
832 return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO];
833 case NativeNumberMode::NATNUM3: // Char, FullWidth
834 case NativeNumberMode::NATNUM6: // Text, FullWidth
836 case NativeNumberMode::NATNUM9: // Char, Hangul
837 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
838 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
840 default:
841 break;
842 }
843
844 return inChar;
845}
846
847bool NativeNumberSupplierService::isValidNatNumImpl( const Locale& rLocale, sal_Int16 nNativeNumberMode )
848{
849 sal_Int16 langnum = getLanguageNumber(rLocale);
850
851 switch (nNativeNumberMode) {
852 case NativeNumberMode::NATNUM0: // Ascii
853 case NativeNumberMode::NATNUM3: // Char, FullWidth
854 case NativeNumberMode::NATNUM12: // spell out numbers, dates and money amounts
855 return true;
856 case NativeNumberMode::NATNUM1: // Char, Lower
857 return (langnum >= 0);
858 case NativeNumberMode::NATNUM2: // Char, Upper
859 if (langnum == 4) // Hebrew numbering
860 return true;
861 [[fallthrough]];
862 case NativeNumberMode::NATNUM4: // Text, Lower, Long
863 case NativeNumberMode::NATNUM5: // Text, Upper, Long
864 case NativeNumberMode::NATNUM6: // Text, FullWidth
865 case NativeNumberMode::NATNUM7: // Text. Lower, Short
866 case NativeNumberMode::NATNUM8: // Text, Upper, Short
867 return (langnum >= 0 && langnum < 4); // CJK numbering
868 case NativeNumberMode::NATNUM9: // Char, Hangul
869 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
870 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
871 return (langnum == 3); // Korean numbering
872 }
873 return false;
874}
875
876NativeNumberXmlAttributes SAL_CALL NativeNumberSupplierService::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode )
877{
878 static const sal_Int16 attShort = 0;
879 static const sal_Int16 attMedium = 1;
880 static const sal_Int16 attLong = 2;
881 static const char *attType[] = { "short", "medium", "long" };
882
883 sal_Int16 number = NumberChar_HalfWidth, type = attShort;
884
885 sal_Int16 langnum = -1;
886 if (isValidNatNum(rLocale, nNativeNumberMode)) {
887 langnum = getLanguageNumber(rLocale);
888 }
889 if (langnum != -1) {
890 switch (nNativeNumberMode) {
891 case NativeNumberMode::NATNUM0: // Ascii
892 number = NumberChar_HalfWidth;
893 type = attShort;
894 break;
895 case NativeNumberMode::NATNUM1: // Char, Lower
896 number = natnum1[langnum];
897 type = attShort;
898 break;
899 case NativeNumberMode::NATNUM2: // Char, Upper
900 number = natnum2[langnum];
901 type = number == NumberChar_he ? attMedium : attShort;
902 break;
903 case NativeNumberMode::NATNUM3: // Char, FullWidth
904 number = NumberChar_FullWidth;
905 type = attShort;
906 break;
907 case NativeNumberMode::NATNUM4: // Text, Lower, Long
908 number = natnum1[langnum];
909 type = attLong;
910 break;
911 case NativeNumberMode::NATNUM5: // Text, Upper, Long
912 number = natnum2[langnum];
913 type = attLong;
914 break;
915 case NativeNumberMode::NATNUM6: // Text, FullWidth
916 number = NumberChar_FullWidth;
917 type = attLong;
918 break;
919 case NativeNumberMode::NATNUM7: // Text. Lower, Short
920 number = natnum1[langnum];
921 type = attMedium;
922 break;
923 case NativeNumberMode::NATNUM8: // Text, Upper, Short
924 number = natnum2[langnum];
925 type = attMedium;
926 break;
927 case NativeNumberMode::NATNUM9: // Char, Hangul
928 number = NumberChar_Hangul_ko;
929 type = attShort;
930 break;
931 case NativeNumberMode::NATNUM10: // Text, Hangul, Long
932 number = NumberChar_Hangul_ko;
933 type = attLong;
934 break;
935 case NativeNumberMode::NATNUM11: // Text, Hangul, Short
936 number = NumberChar_Hangul_ko;
937 type = attMedium;
938 break;
939 default:
940 break;
941 }
942 }
943 return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1),
944 OUString::createFromAscii(attType[type]));
945}
946
947static bool natNumIn(sal_Int16 num, const sal_Int16 natnum[], sal_Int16 len)
948{
949 for (sal_Int16 i = 0; i < len; i++)
950 if (natnum[i] == num)
951 return true;
952 return false;
953}
954
955sal_Int16 SAL_CALL NativeNumberSupplierService::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr )
956{
957 sal_Unicode numberChar[NumberChar_Count];
958 for (sal_Int16 i = 0; i < NumberChar_Count; i++)
959 numberChar[i] = NumberChar[i][1];
960 OUString number(numberChar, NumberChar_Count);
961
962 sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) );
963
964 if ( aAttr.Style == "short" ) {
965 if (num == NumberChar_FullWidth)
966 return NativeNumberMode::NATNUM3;
967 else if (num == NumberChar_Hangul_ko)
968 return NativeNumberMode::NATNUM9;
969 else if (natNumIn(num, natnum1, sizeof_natnum1))
970 return NativeNumberMode::NATNUM1;
971 else if (natNumIn(num, natnum2, sizeof_natnum2))
972 return NativeNumberMode::NATNUM2;
973 } else if ( aAttr.Style == "medium" ) {
974 if (num == NumberChar_Hangul_ko)
975 return NativeNumberMode::NATNUM11;
976 else if (num == NumberChar_he)
977 return NativeNumberMode::NATNUM2;
978 else if (natNumIn(num, natnum1, sizeof_natnum1))
979 return NativeNumberMode::NATNUM7;
980 else if (natNumIn(num, natnum2, sizeof_natnum2))
981 return NativeNumberMode::NATNUM8;
982 } else if ( aAttr.Style == "long" ) {
983 if (num == NumberChar_FullWidth)
984 return NativeNumberMode::NATNUM6;
985 else if (num == NumberChar_Hangul_ko)
986 return NativeNumberMode::NATNUM10;
987 else if (natNumIn(num, natnum1, sizeof_natnum1))
988 return NativeNumberMode::NATNUM4;
989 else if (natNumIn(num, natnum2, sizeof_natnum2))
990 return NativeNumberMode::NATNUM5;
991 } else {
992 throw RuntimeException();
993 }
994 return NativeNumberMode::NATNUM0;
995}
996
997
998// Following code generates Hebrew Number,
999// see numerical system in the Hebrew Numbering System in following link for details,
1000// http://smontagu.org/writings/HebrewNumbers.html
1001
1002namespace {
1003
1004struct HebrewNumberChar {
1006 sal_Int16 value;
1007};
1008
1009}
1010
1011HebrewNumberChar const HebrewNumberCharArray[] = {
1012 { 0x05ea, 400 },
1013 { 0x05ea, 400 },
1014 { 0x05e9, 300 },
1015 { 0x05e8, 200 },
1016 { 0x05e7, 100 },
1017 { 0x05e6, 90 },
1018 { 0x05e4, 80 },
1019 { 0x05e2, 70 },
1020 { 0x05e1, 60 },
1021 { 0x05e0, 50 },
1022 { 0x05de, 40 },
1023 { 0x05dc, 30 },
1024 { 0x05db, 20 },
1025 { 0x05d9, 10 },
1026 { 0x05d8, 9 },
1027 { 0x05d7, 8 },
1028 { 0x05d6, 7 },
1029 { 0x05d5, 6 },
1030 { 0x05d4, 5 },
1031 { 0x05d3, 4 },
1032 { 0x05d2, 3 },
1033 { 0x05d1, 2 },
1034 { 0x05d0, 1 }
1035};
1036
1037const sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
1038const sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
1039const sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
1040const sal_Unicode geresh = 0x05f3;
1041const sal_Unicode gershayim = 0x05f4;
1042
1043static void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, bool isLast, bool useGeresh)
1044{
1045 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
1046
1047 if (value > 1000) {
1048 makeHebrewNumber(value / 1000, output, num != 0, useGeresh);
1049 output.append(" ");
1050 }
1051 if (num == 0) {
1052 output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands);
1053 } else {
1054 sal_Int16 nbOfChar = 0;
1055 for (sal_Int32 j = 0; num > 0 && j < sal_Int32(SAL_N_ELEMENTS(HebrewNumberCharArray)); j++) {
1056 if (num - HebrewNumberCharArray[j].value >= 0) {
1057 nbOfChar++;
1058 // https://en.wikipedia.org/wiki/Hebrew_numerals#Key_exceptions
1059 // By convention, the numbers 15 and 16 are represented as 9 + 6 and 9 + 7
1060 if (num == 15 || num == 16) // substitution for 15 and 16
1061 j++;
1062 assert(j < sal_Int32(SAL_N_ELEMENTS(HebrewNumberCharArray)));
1063 num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value );
1064 output.append(HebrewNumberCharArray[j].code);
1065 }
1066 }
1067 if (useGeresh) {
1068 if (nbOfChar > 1) // a number is written as more than one character
1069 output.insert(output.getLength() - 1, gershayim);
1070 else if (nbOfChar == 1) // a number is written as a single character
1071 output.append(geresh);
1072 }
1073 }
1074}
1075
1076OUString getHebrewNativeNumberString(const OUString& aNumberString, bool useGeresh)
1077{
1078 sal_Int64 value = 0;
1079 sal_Int32 i, count = 0, len = aNumberString.getLength();
1080 const sal_Unicode *src = aNumberString.getStr();
1081
1082 for (i = 0; i < len; i++) {
1083 sal_Unicode ch = src[i];
1084 if (isNumber(ch)) {
1085 if (++count >= 20) // Number is too long, could not be handled.
1086 return aNumberString;
1087 value = value * 10 + (ch - NUMBER_ZERO);
1088 }
1089 else if (isSeparator(ch) && count > 0) continue;
1090 else if (isMinus(ch) && count == 0) continue;
1091 else break;
1092 }
1093
1094 if (value > 0) {
1095 OUStringBuffer output(count*2 + 2 + len - i);
1096
1097 makeHebrewNumber(value, output, true, useGeresh);
1098
1099 if (i < len)
1100 output.append(aNumberString.subView(i));
1101
1102 return output.makeStringAndClear();
1103 }
1104 else
1105 return aNumberString;
1106}
1107
1108// Support for Cyrillic Numerals
1109// See UTN 41 for implementation information
1110// http://www.unicode.org/notes/tn41/
1111
1115
1116namespace {
1117
1118struct CyrillicNumberChar {
1120 sal_Int16 value;
1121};
1122
1123}
1124
1125CyrillicNumberChar const CyrillicNumberCharArray[] = {
1126 { 0x0446, 900 },
1127 { 0x047f, 800 },
1128 { 0x0471, 700 },
1129 { 0x0445, 600 },
1130 { 0x0444, 500 },
1131 { 0x0443, 400 },
1132 { 0x0442, 300 },
1133 { 0x0441, 200 },
1134 { 0x0440, 100 },
1135 { 0x0447, 90 },
1136 { 0x043f, 80 },
1137 { 0x047b, 70 },
1138 { 0x046f, 60 },
1139 { 0x043d, 50 },
1140 { 0x043c, 40 },
1141 { 0x043b, 30 },
1142 { 0x043a, 20 },
1143 { 0x0456, 10 },
1144 { 0x0473, 9 },
1145 { 0x0438, 8 },
1146 { 0x0437, 7 },
1147 { 0x0455, 6 },
1148 { 0x0454, 5 },
1149 { 0x0434, 4 },
1150 { 0x0433, 3 },
1151 { 0x0432, 2 },
1152 { 0x0430, 1 }
1153};
1154
1155static void makeCyrillicNumber(sal_Int64 value, OUStringBuffer& output, bool addTitlo)
1156{
1157 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
1158 if (value >= 1000) {
1159 output.append(cyrillicThousandsMark);
1160 makeCyrillicNumber(value / 1000, output, false);
1161 if (value >= 10000 && (value - 10000) % 1000 != 0) {
1162 output.append(" ");
1163 }
1164 if (value % 1000 == 0)
1165 addTitlo = false;
1166 }
1167
1168 for (sal_Int32 j = 0; num > 0 && j < sal_Int32(SAL_N_ELEMENTS(CyrillicNumberCharArray)); j++) {
1169 if (num < 20 && num > 10) {
1170 num -= 10;
1171 makeCyrillicNumber(num, output, false);
1172 output.append(cyrillicTen);
1173 break;
1174 }
1175
1176 if (CyrillicNumberCharArray[j].value <= num) {
1177 output.append(CyrillicNumberCharArray[j].code);
1178 num = sal::static_int_cast<sal_Int16>( num - CyrillicNumberCharArray[j].value );
1179 }
1180 }
1181
1182 if (!addTitlo)
1183 return;
1184
1185 if (output.getLength() == 1) {
1186 output.append(cyrillicTitlo);
1187 } else if (output.getLength() == 2) {
1188 if (value > 800 && value < 900) {
1189 output.append(cyrillicTitlo);
1190 } else {
1191 output.insert(1, cyrillicTitlo);
1192 }
1193 } else if (output.getLength() > 2) {
1194 if (output.indexOf(" ") == output.getLength() - 2) {
1195 output.append(cyrillicTitlo);
1196 } else {
1197 output.insert(output.getLength() - 1, cyrillicTitlo);
1198 }
1199 }
1200}
1201
1202OUString getCyrillicNativeNumberString(const OUString& aNumberString)
1203{
1204 sal_Int64 value = 0;
1205 sal_Int32 i, count = 0, len = aNumberString.getLength();
1206 const sal_Unicode *src = aNumberString.getStr();
1207
1208 for (i = 0; i < len; i++) {
1209 sal_Unicode ch = src[i];
1210 if (isNumber(ch)) {
1211 if (++count >= 8) // Number is too long, could not be handled.
1212 return aNumberString;
1213 value = value * 10 + (ch - NUMBER_ZERO);
1214 }
1215 else if (isSeparator(ch) && count > 0) continue;
1216 else if (isMinus(ch) && count == 0) continue;
1217 else break;
1218 }
1219
1220 if (value > 0) {
1221 OUStringBuffer output(count*2 + 2 + len - i);
1222
1223 makeCyrillicNumber(value, output, true);
1224
1225 if (i < len)
1226 output.append(aNumberString.subView(i));
1227
1228 return output.makeStringAndClear();
1229 }
1230 else
1231 return aNumberString;
1232}
1233
1234constexpr OUStringLiteral implementationName = u"com.sun.star.i18n.NativeNumberSupplier";
1235
1237{
1238 return implementationName;
1239}
1240
1241sal_Bool SAL_CALL
1243{
1244 return cppu::supportsService(this, rServiceName);
1245}
1246
1247Sequence< OUString > SAL_CALL
1249{
1250 return {implementationName, "com.sun.star.i18n.NativeNumberSupplier2"};
1251}
1252
1253}
1254
1255extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1257 css::uno::XComponentContext *,
1258 css::uno::Sequence<css::uno::Any> const &)
1259{
1260 return cppu::acquire(new i18npool::NativeNumberSupplierService());
1261}
1262
1263/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static OUString convertToBcp47(LanguageType nLangID)
static bool isTraditionalChinese(LanguageType nLang)
static rtl::Reference< LocaleDataImpl > get()
Definition: localedata.hxx:77
css::uno::Reference< css::i18n::XCharacterClassification > xCharClass
virtual OUString SAL_CALL getNativeNumberStringParams(const OUString &rNumberString, const css::lang::Locale &rLocale, sal_Int16 nNativeNumberMode, const OUString &rNativeNumberParams) override
static bool isValidNatNumImpl(const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode)
virtual sal_Bool SAL_CALL isValidNatNum(const css::lang::Locale &rLocale, sal_Int16 nNativeNumberMode) override
virtual sal_Int16 SAL_CALL convertFromXmlAttributes(const css::i18n::NativeNumberXmlAttributes &aAttr) override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual OUString SAL_CALL getNativeNumberString(const OUString &aNumberString, const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode) override
virtual OUString SAL_CALL getImplementationName() override
static sal_Unicode getNativeNumberChar(const sal_Unicode inChar, const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode)
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual css::i18n::NativeNumberXmlAttributes SAL_CALL convertToXmlAttributes(const css::lang::Locale &aLocale, sal_Int16 nNativeNumberMode) override
int nCount
constexpr OUStringLiteral TITLE
float u
#define max(a, b)
#define SAL_N_ELEMENTS(arr)
aStr
Reference< XComponentContext > getProcessComponentContext()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
Constant values shared between i18npool and, for example, the number formatter.
const sal_Int16 Multiplier_Hangul_ko
Definition: numberchar.h:216
static sal_uInt16 SeparatorChar[]
Definition: numberchar.h:167
static bool natNumIn(sal_Int16 num, const sal_Int16 natnum[], sal_Int16 len)
const sal_Int16 Multiplier_Lower_zh_TW
Definition: numberchar.h:212
static void makeHebrewNumber(sal_Int64 value, OUStringBuffer &output, bool isLast, bool useGeresh)
const sal_Int16 NumberChar_Upper_zh_TW
Definition: numberchar.h:31
constexpr OUStringLiteral implementationName
const sal_Int16 ExponentCount_7_CJK
Definition: numberchar.h:256
const sal_Int16 ExponentCount_6_CJK
Definition: numberchar.h:221
const sal_Int16 NumberChar_lo
Definition: numberchar.h:50
static OUString AsciiToNative(const OUString &inStr, sal_Int32 nCount, Sequence< sal_Int32 > *pOffset, const Number *number)
const sal_Unicode MultiplierChar_7_CJK[][ExponentCount_7_CJK]
Definition: numberchar.h:261
const sal_Int16 NumberChar_bn
Definition: numberchar.h:43
const sal_Int16 NumberChar_or
Definition: numberchar.h:41
const sal_Int16 NumberChar_kn
Definition: numberchar.h:48
static bool AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len, sal_Unicode *dst, sal_Int32 &count, sal_Int16 multiChar_index, Sequence< sal_Int32 > *pOffset, sal_Int32 startPos, const Number *number, const sal_Unicode *numberChar)
const sal_Int16 Multiplier_Traditional_ja
Definition: numberchar.h:218
static void makeCyrillicNumber(sal_Int64 value, OUStringBuffer &output, bool addTitlo)
const sal_Unicode MinusChar[]
Definition: numberchar.h:132
const sal_Int16 NumberChar_ne
Definition: numberchar.h:56
static OUString getCyrillicNativeNumberString(const OUString &aNumberString)
static OUString getHebrewNativeNumberString(const OUString &aNumberString, bool useGeresh)
const sal_Int16 NumberChar_mr
Definition: numberchar.h:42
const sal_Int16 NumberChar_Traditional_ja
Definition: numberchar.h:33
const sal_Int16 NumberChar_bo
Definition: numberchar.h:51
const sal_Int16 NumberChar_cu
Definition: numberchar.h:58
const sal_Int16 NumberChar_dz
Definition: numberchar.h:57
const sal_Unicode MultiplierChar_2_CJK[][ExponentCount_2_CJK]
Definition: numberchar.h:244
const sal_Int16 NumberChar_Upper_zh
Definition: numberchar.h:30
const sal_Unicode geresh
const sal_Int16 Multiplier_Count
Definition: numberchar.h:219
const sal_Int16 NumberChar_gu
Definition: numberchar.h:45
static sal_Unicode DecimalChar[]
Definition: numberchar.h:97
const sal_Int16 NumberChar_ml
Definition: numberchar.h:49
static OUString AsciiToNativeChar(const OUString &inStr, sal_Int32 nCount, Sequence< sal_Int32 > *pOffset, sal_Int16 number)
const sal_Int16 MultiplierExponent_6_CJK[ExponentCount_6_CJK]
Definition: numberchar.h:223
const sal_Unicode thousands_last[]
const sal_Int16 ExponentCount_2_CJK
Definition: numberchar.h:238
const sal_Unicode cyrillicTitlo
const sal_Int16 NumberChar_my
Definition: numberchar.h:52
const sal_Int16 NumberChar_ta
Definition: numberchar.h:46
const sal_Int16 MultiplierExponent_7_CJK[ExponentCount_7_CJK]
Definition: numberchar.h:258
const sal_Int16 NumberChar_HalfWidth
Definition: numberchar.h:27
const sal_Unicode gershayim
const sal_Int16 Multiplier_Upper_zh_TW
Definition: numberchar.h:213
const sal_Int16 NumberChar_Indic_ar
Definition: numberchar.h:37
const sal_Int16 NumberChar_FullWidth
Definition: numberchar.h:28
const sal_Int16 NumberChar_Lower_zh
Definition: numberchar.h:29
const sal_Int16 NumberChar_Modern_ja
Definition: numberchar.h:32
const sal_Unicode cyrillicThousandsMark
const sal_Unicode thousand[]
const sal_Unicode cyrillicTen
const sal_Int16 Multiplier_Upper_zh
Definition: numberchar.h:211
const sal_Unicode MultiplierChar_6_CJK[][ExponentCount_6_CJK]
Definition: numberchar.h:226
const sal_Int16 Multiplier_Lower_zh
Definition: numberchar.h:210
const sal_Int16 MultiplierExponent_2_CJK[ExponentCount_2_CJK]
Definition: numberchar.h:240
const sal_Int16 Multiplier_Lower_ko
Definition: numberchar.h:214
const sal_Unicode thousands[]
const sal_Int16 NumberChar_te
Definition: numberchar.h:47
const sal_Int16 NumberChar_Count
Definition: numberchar.h:59
const sal_Int16 NumberChar_Upper_ko
Definition: numberchar.h:35
const sal_Int16 NumberChar_hi
Definition: numberchar.h:39
const sal_Unicode NumberChar[][10]
Definition: numberchar.h:61
HebrewNumberChar const HebrewNumberCharArray[]
CyrillicNumberChar const CyrillicNumberCharArray[]
const sal_Int16 NumberChar_Hangul_ko
Definition: numberchar.h:36
const sal_Int16 NumberChar_Lower_ko
Definition: numberchar.h:34
const sal_Int16 NumberChar_mn
Definition: numberchar.h:54
const sal_Int16 Multiplier_Modern_ja
Definition: numberchar.h:217
const sal_Int16 NumberChar_th
Definition: numberchar.h:40
const sal_Int16 NumberChar_he
Definition: numberchar.h:55
const sal_Int16 NumberChar_pa
Definition: numberchar.h:44
const sal_Int16 NumberChar_EastIndic_ar
Definition: numberchar.h:38
const sal_Int16 NumberChar_km
Definition: numberchar.h:53
const sal_Int16 Multiplier_Upper_ko
Definition: numberchar.h:215
index
int shift
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
enumrange< T >::Iterator begin(enumrange< T >)
end
#define NUMBER_OMIT_ONE_CHECK(bit)
sal_Unicode ThousandSeparator
#define NUMBER_OMIT_ZERO
#define NUMBER_OMIT_ZERO_ONE
sal_Unicode code
#define NUMBER_OMIT_ONLY_ZERO
#define NUMBER_OMIT_ALL
sal_Int16 value
#define NUMBER_OMIT_ZERO_ONE_67
sal_Unicode DecimalSeparator
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_i18n_NativeNumberSupplier_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
#define isMinus(n)
Definition: numberchar.h:207
#define isSeparator(n)
Definition: numberchar.h:208
#define NUMBER_ZERO
Definition: numberchar.h:202
#define isDecimal(n)
Definition: numberchar.h:206
#define isNumber(n)
Definition: numberchar.h:205
#define NUMBER_ONE
Definition: numberchar.h:203
unsigned char sal_Bool
sal_uInt16 sal_Unicode
ResultType type