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