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