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 
20 #include <sal/config.h>
21 
22 #include <sal/log.hxx>
23 #include <svl/zforlist.hxx>
24 #include <svl/currencytable.hxx>
25 
26 #include <comphelper/string.hxx>
27 #include <tools/debug.hxx>
28 #include <unotools/charclass.hxx>
29 #include <unotools/configmgr.hxx>
30 #include <i18nlangtag/mslangid.hxx>
31 #include <unotools/localedatawrapper.hxx>
32 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
33 #include <com/sun/star/i18n/KNumberFormatType.hpp>
34 #include <com/sun/star/i18n/FormatElement.hpp>
35 #include <com/sun/star/i18n/Currency2.hpp>
36 #include <com/sun/star/i18n/NumberFormatCode.hpp>
37 #include <com/sun/star/i18n/XNumberFormatCode.hpp>
38 #include <com/sun/star/i18n/NumberFormatMapper.hpp>
39 #include <comphelper/processfactory.hxx>
40 #include <unotools/misccfg.hxx>
41 
42 
43 #include <osl/mutex.hxx>
44 
45 #include "zforscan.hxx"
46 #include "zforfind.hxx"
47 #include <svl/zformat.hxx>
48 #include <i18npool/reservedconstants.hxx>
49 
50 #include <unotools/syslocaleoptions.hxx>
51 #include <unotools/digitgroupingiterator.hxx>
52 #include <rtl/instance.hxx>
53 #include <rtl/strbuf.hxx>
54 
55 #include <math.h>
56 #include <limits>
57 #include <memory>
58 
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::i18n;
62 using namespace ::com::sun::star::lang;
63 using namespace ::std;
64 
65 // Constants for type offsets per Country/Language (CL)
66 #define ZF_STANDARD              0
67 #define ZF_STANDARD_PERCENT     10
68 #define ZF_STANDARD_CURRENCY    20
69 #define ZF_STANDARD_DATE        30
70 #define ZF_STANDARD_TIME        40
71 #define ZF_STANDARD_DURATION    (ZF_STANDARD_TIME + 4)
72 #define ZF_STANDARD_DATETIME    50
73 #define ZF_STANDARD_SCIENTIFIC  60
74 #define ZF_STANDARD_FRACTION    65
75 
76 // Additional builtin formats not fitting into the first 10 of a category (TLOT
77 // = The Legacy Of Templin; unfortunately TLOT intended only 10 builtin formats
78 // per category, more would overwrite the next category):
79 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY 75
80 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY 76
81 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY 77
82 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY 78
83 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY 79
84 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY 80
85 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY 81
86 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD 82
87 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD 83
88 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD 84
89 #define ZF_STANDARD_NEWEXTENDED_DATE_WW 85
90 
91 #define ZF_STANDARD_LOGICAL     SV_MAX_COUNT_STANDARD_FORMATS-1 //  99
92 #define ZF_STANDARD_TEXT        SV_MAX_COUNT_STANDARD_FORMATS   // 100
93 
94 static_assert( ZF_STANDARD_TEXT == NF_STANDARD_FORMAT_TEXT, "definition mismatch" );
95 
96 static_assert( NF_INDEX_TABLE_ENTRIES <= i18npool::nFirstFreeFormatIndex,
97         "NfIndexTableOffset crosses i18npool's locale data reserved format code index bounds.\n"
98         "You will need to adapt all locale data files defining index values "
99         "(formatIndex=\"...\") in that range and increment those and when done "
100         "adjust nFirstFreeFormatIndex in i18npool/reservedconstants.hxx");
101 
102 /* Locale that is set if an unknown locale (from another system) is loaded of
103  * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
104  * (old currency) is recognized as a date (#53155#). */
105 #define UNKNOWN_SUBSTITUTE      LANGUAGE_ENGLISH_US
106 
107 // Same order as in include/svl/zforlist.hxx enum NfIndexTableOffset
108 static sal_uInt32 const indexTable[NF_INDEX_TABLE_ENTRIES] = {
109     ZF_STANDARD, // NF_NUMBER_STANDARD
110     ZF_STANDARD + 1, // NF_NUMBER_INT
111     ZF_STANDARD + 2, // NF_NUMBER_DEC2
112     ZF_STANDARD + 3, // NF_NUMBER_1000INT
113     ZF_STANDARD + 4, // NF_NUMBER_1000DEC2
114     ZF_STANDARD + 5, // NF_NUMBER_SYSTEM
115     ZF_STANDARD_SCIENTIFIC, // NF_SCIENTIFIC_000E000
116     ZF_STANDARD_SCIENTIFIC + 1, // NF_SCIENTIFIC_000E00
117     ZF_STANDARD_PERCENT, // NF_PERCENT_INT
118     ZF_STANDARD_PERCENT + 1, // NF_PERCENT_DEC2
119     ZF_STANDARD_FRACTION, // NF_FRACTION_1D
120     ZF_STANDARD_FRACTION + 1, // NF_FRACTION_2D
121     ZF_STANDARD_CURRENCY, // NF_CURRENCY_1000INT
122     ZF_STANDARD_CURRENCY + 1, // NF_CURRENCY_1000DEC2
123     ZF_STANDARD_CURRENCY + 2, // NF_CURRENCY_1000INT_RED
124     ZF_STANDARD_CURRENCY + 3, // NF_CURRENCY_1000DEC2_RED
125     ZF_STANDARD_CURRENCY + 4, // NF_CURRENCY_1000DEC2_CCC
126     ZF_STANDARD_CURRENCY + 5, // NF_CURRENCY_1000DEC2_DASHED
127     ZF_STANDARD_DATE, // NF_DATE_SYSTEM_SHORT
128     ZF_STANDARD_DATE + 8, // NF_DATE_SYSTEM_LONG
129     ZF_STANDARD_DATE + 7, // NF_DATE_SYS_DDMMYY
130     ZF_STANDARD_DATE + 6, // NF_DATE_SYS_DDMMYYYY
131     ZF_STANDARD_DATE + 9, // NF_DATE_SYS_DMMMYY
132     ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY, // NF_DATE_SYS_DMMMYYYY
133     ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY, // NF_DATE_DIN_DMMMYYYY
134     ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY, // NF_DATE_SYS_DMMMMYYYY
135     ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY, // NF_DATE_DIN_DMMMMYYYY
136     ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY, // NF_DATE_SYS_NNDMMMYY
137     ZF_STANDARD_DATE + 1, // NF_DATE_DEF_NNDDMMMYY
138     ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY, // NF_DATE_SYS_NNDMMMMYYYY
139     ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY, // NF_DATE_SYS_NNNNDMMMMYYYY
140     ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD, // NF_DATE_DIN_MMDD
141     ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD, // NF_DATE_DIN_YYMMDD
142     ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD, // NF_DATE_DIN_YYYYMMDD
143     ZF_STANDARD_DATE + 2, // NF_DATE_SYS_MMYY
144     ZF_STANDARD_DATE + 3, // NF_DATE_SYS_DDMMM
145     ZF_STANDARD_DATE + 4, // NF_DATE_MMMM
146     ZF_STANDARD_DATE + 5, // NF_DATE_QQJJ
147     ZF_STANDARD_NEWEXTENDED_DATE_WW, // NF_DATE_WW
148     ZF_STANDARD_TIME, // NF_TIME_HHMM
149     ZF_STANDARD_TIME + 1, // NF_TIME_HHMMSS
150     ZF_STANDARD_TIME + 2, // NF_TIME_HHMMAMPM
151     ZF_STANDARD_TIME + 3, // NF_TIME_HHMMSSAMPM
152     ZF_STANDARD_TIME + 4, // NF_TIME_HH_MMSS
153     ZF_STANDARD_TIME + 5, // NF_TIME_MMSS00
154     ZF_STANDARD_TIME + 6, // NF_TIME_HH_MMSS00
155     ZF_STANDARD_DATETIME, // NF_DATETIME_SYSTEM_SHORT_HHMM
156     ZF_STANDARD_DATETIME + 1, // NF_DATETIME_SYS_DDMMYYYY_HHMMSS
157     ZF_STANDARD_LOGICAL, // NF_BOOLEAN
158     ZF_STANDARD_TEXT, // NF_TEXT
159     ZF_STANDARD_FRACTION + 2, // NF_FRACTION_3D
160     ZF_STANDARD_FRACTION + 3, // NF_FRACTION_2
161     ZF_STANDARD_FRACTION + 4, // NF_FRACTION_4
162     ZF_STANDARD_FRACTION + 5, // NF_FRACTION_8
163     ZF_STANDARD_FRACTION + 6, // NF_FRACTION_16
164     ZF_STANDARD_FRACTION + 7, // NF_FRACTION_10
165     ZF_STANDARD_FRACTION + 8, // NF_FRACTION_100
166     ZF_STANDARD_DATETIME + 2, // NF_DATETIME_ISO_YYYYMMDD_HHMMSS
167     ZF_STANDARD_DATETIME + 3  // NF_DATETIME_ISO_YYYYMMDDTHHMMSS
168 };
169 
170 /**
171     instead of every number formatter being a listener we have a registry which
172     also handles one instance of the SysLocale options
173  */
174 
175 typedef ::std::vector< SvNumberFormatter* > SvNumberFormatterList_impl;
176 
177 class SvNumberFormatterRegistry_Impl : public utl::ConfigurationListener
178 {
179     SvNumberFormatterList_impl  aFormatters;
180     SvtSysLocaleOptions         aSysLocaleOptions;
181     LanguageType                eSysLanguage;
182 
183 public:
184                             SvNumberFormatterRegistry_Impl();
185     virtual                 ~SvNumberFormatterRegistry_Impl() override;
186 
Insert(SvNumberFormatter * pThis)187     void                    Insert( SvNumberFormatter* pThis )
188                                 { aFormatters.push_back( pThis ); }
189 
190     void                    Remove( SvNumberFormatter const * pThis );
191 
Count() const192     size_t                  Count() const
193                                 { return aFormatters.size(); }
194 
195     virtual void            ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override;
196 };
197 
SvNumberFormatterRegistry_Impl()198 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
199 {
200     eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
201     aSysLocaleOptions.AddListener( this );
202 }
203 
204 
~SvNumberFormatterRegistry_Impl()205 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
206 {
207     aSysLocaleOptions.RemoveListener( this );
208 }
209 
210 
Remove(SvNumberFormatter const * pThis)211 void SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter const * pThis )
212 {
213     auto it = std::find(aFormatters.begin(), aFormatters.end(), pThis);
214     if (it != aFormatters.end())
215         aFormatters.erase( it );
216 }
217 
ConfigurationChanged(utl::ConfigurationBroadcaster *,ConfigurationHints nHint)218 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*,
219                                                            ConfigurationHints nHint)
220 {
221     ::osl::MutexGuard aGuard( SvNumberFormatter::GetGlobalMutex() );
222 
223     if ( nHint & ConfigurationHints::Locale )
224     {
225         for(SvNumberFormatter* pFormatter : aFormatters)
226             pFormatter->ReplaceSystemCL( eSysLanguage );
227         eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
228     }
229     if ( nHint & ConfigurationHints::Currency )
230     {
231         for(SvNumberFormatter* pFormatter : aFormatters)
232             pFormatter->ResetDefaultSystemCurrency();
233     }
234     if ( nHint & ConfigurationHints::DatePatterns )
235     {
236         for(SvNumberFormatter* pFormatter : aFormatters)
237             pFormatter->InvalidateDateAcceptancePatterns();
238     }
239 }
240 
241 
242 SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = nullptr;
243 volatile bool SvNumberFormatter::bCurrencyTableInitialized = false;
244 namespace
245 {
246     struct theCurrencyTable :
247         public rtl::Static< NfCurrencyTable, theCurrencyTable > {};
248 
249     struct theLegacyOnlyCurrencyTable :
250         public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {};
251 
252     /** THE set of installed locales. */
253     struct theInstalledLocales :
254         public rtl::Static< NfInstalledLocales, theInstalledLocales> {};
255 
256 }
257 sal_uInt16 SvNumberFormatter::nSystemCurrencyPosition = 0;
258 
259 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
260 // language dependent.
261 #define NF_BANKSYMBOL_FIX_POSITION 1
262 
263 const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION   = ::std::numeric_limits<sal_uInt16>::max();
264 const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
265 
SvNumberFormatter(const Reference<XComponentContext> & rxContext,LanguageType eLang)266 SvNumberFormatter::SvNumberFormatter( const Reference< XComponentContext >& rxContext,
267                                       LanguageType eLang )
268     : m_xContext( rxContext )
269     , maLanguageTag( eLang)
270 {
271     ImpConstruct( eLang );
272 }
273 
~SvNumberFormatter()274 SvNumberFormatter::~SvNumberFormatter()
275 {
276     {
277         ::osl::MutexGuard aGuard( GetGlobalMutex() );
278         pFormatterRegistry->Remove( this );
279         if ( !pFormatterRegistry->Count() )
280         {
281             delete pFormatterRegistry;
282             pFormatterRegistry = nullptr;
283         }
284     }
285 
286     aFTable.clear();
287     ClearMergeTable();
288 }
289 
290 
ImpConstruct(LanguageType eLang)291 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
292 {
293     if ( eLang == LANGUAGE_DONTKNOW )
294     {
295         eLang = UNKNOWN_SUBSTITUTE;
296     }
297     IniLnge = eLang;
298     ActLnge = eLang;
299     eEvalDateFormat = NF_EVALDATEFORMAT_INTL;
300     nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
301 
302     maLanguageTag.reset( eLang );
303     pCharClass.reset( new CharClass( m_xContext, maLanguageTag ) );
304     xLocaleData.init( m_xContext, maLanguageTag );
305     xCalendar.init( m_xContext, maLanguageTag.getLocale() );
306     xTransliteration.init( m_xContext, eLang );
307     xNatNum.init( m_xContext );
308 
309     // cached locale data items
310     const LocaleDataWrapper* pLoc = GetLocaleData();
311     aDecimalSep = pLoc->getNumDecimalSep();
312     aDecimalSepAlt = pLoc->getNumDecimalSepAlt();
313     aThousandSep = pLoc->getNumThousandSep();
314     aDateSep = pLoc->getDateSep();
315 
316     pStringScanner.reset( new ImpSvNumberInputScan( this ) );
317     pFormatScanner.reset( new ImpSvNumberformatScan( this ) );
318     pFormatTable = nullptr;
319     MaxCLOffset = 0;
320     ImpGenerateFormats( 0, false );     // 0 .. 999 for initialized language formats
321     pMergeTable = nullptr;
322     bNoZero = false;
323 
324     ::osl::MutexGuard aGuard( GetGlobalMutex() );
325     GetFormatterRegistry().Insert( this );
326 }
327 
328 
ChangeIntl(LanguageType eLnge)329 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
330 {
331     ::osl::MutexGuard aGuard( GetInstanceMutex() );
332     if (ActLnge == eLnge)
333         return;
334 
335     ActLnge = eLnge;
336 
337     maLanguageTag.reset( eLnge );
338     pCharClass->setLanguageTag( maLanguageTag );
339     xLocaleData.changeLocale( maLanguageTag );
340     xCalendar.changeLocale( maLanguageTag.getLocale() );
341     xTransliteration.changeLocale( eLnge );
342 
343     // cached locale data items, initialize BEFORE calling ChangeIntl below
344     const LocaleDataWrapper* pLoc = GetLocaleData();
345     aDecimalSep = pLoc->getNumDecimalSep();
346     aDecimalSepAlt = pLoc->getNumDecimalSepAlt();
347     aThousandSep = pLoc->getNumThousandSep();
348     aDateSep = pLoc->getDateSep();
349 
350     pFormatScanner->ChangeIntl();
351     pStringScanner->ChangeIntl();
352 }
353 
354 
355 // static
GetGlobalMutex()356 ::osl::Mutex& SvNumberFormatter::GetGlobalMutex()
357 {
358     // #i77768# Due to a static reference in the toolkit lib
359     // we need a mutex that lives longer than the svl library.
360     // Otherwise the dtor would use a destructed mutex!!
361     static osl::Mutex* persistentMutex(new osl::Mutex);
362 
363     return *persistentMutex;
364 }
365 
366 
367 // static
GetFormatterRegistry()368 SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry()
369 {
370     ::osl::MutexGuard aGuard( GetGlobalMutex() );
371     if ( !pFormatterRegistry )
372     {
373         pFormatterRegistry = new SvNumberFormatterRegistry_Impl;
374     }
375     return *pFormatterRegistry;
376 }
377 
SetColorLink(const Link<sal_uInt16,Color * > & rColorTableCallBack)378 void SvNumberFormatter::SetColorLink( const Link<sal_uInt16,Color*>& rColorTableCallBack )
379 {
380     ::osl::MutexGuard aGuard( GetInstanceMutex() );
381     aColorLink = rColorTableCallBack;
382 }
383 
GetUserDefColor(sal_uInt16 nIndex)384 Color* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex)
385 {
386     ::osl::MutexGuard aGuard( GetInstanceMutex() );
387     if( aColorLink.IsSet() )
388     {
389         return aColorLink.Call(nIndex);
390     }
391     else
392     {
393         return nullptr;
394     }
395 }
396 
ChangeNullDate(sal_uInt16 nDay,sal_uInt16 nMonth,sal_Int16 nYear)397 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay,
398                                        sal_uInt16 nMonth,
399                                        sal_Int16 nYear)
400 {
401     ::osl::MutexGuard aGuard( GetInstanceMutex() );
402     pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
403     pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
404 }
405 
GetNullDate() const406 const Date& SvNumberFormatter::GetNullDate() const
407 {
408     ::osl::MutexGuard aGuard( GetInstanceMutex() );
409     return pFormatScanner->GetNullDate();
410 }
411 
ChangeStandardPrec(short nPrec)412 void SvNumberFormatter::ChangeStandardPrec(short nPrec)
413 {
414     ::osl::MutexGuard aGuard( GetInstanceMutex() );
415     pFormatScanner->ChangeStandardPrec(nPrec);
416 }
417 
SetNoZero(bool bNZ)418 void SvNumberFormatter::SetNoZero(bool bNZ)
419 {
420     ::osl::MutexGuard aGuard( GetInstanceMutex() );
421     bNoZero = bNZ;
422 }
423 
GetStandardPrec() const424 sal_uInt16 SvNumberFormatter::GetStandardPrec() const
425 {
426     ::osl::MutexGuard aGuard( GetInstanceMutex() );
427     return pFormatScanner->GetStandardPrec();
428 }
429 
GetNoZero() const430 bool SvNumberFormatter::GetNoZero() const
431 {
432     ::osl::MutexGuard aGuard( GetInstanceMutex() );
433     return bNoZero;
434 }
435 
ReplaceSystemCL(LanguageType eOldLanguage)436 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage )
437 {
438     sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
439     if ( nCLOffset > MaxCLOffset )
440     {
441         return ;    // no SYSTEM entries to replace
442     }
443     const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_COUNT_STANDARD_FORMATS;
444     const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
445     sal_uInt32 nKey;
446 
447     // remove old builtin formats
448     auto it = aFTable.find( nCLOffset );
449     while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey <= nMaxBuiltin )
450     {
451         it = aFTable.erase(it);
452     }
453 
454     // move additional and user defined to temporary table
455     SvNumberFormatTable aOldTable;
456     while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey < nNextCL )
457     {
458         aOldTable[ nKey ] = it->second.release();
459         it = aFTable.erase(it);
460     }
461 
462     // generate new old builtin formats
463     // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
464     ActLnge = LANGUAGE_DONTKNOW;
465     ChangeIntl( LANGUAGE_SYSTEM );
466     ImpGenerateFormats( nCLOffset, true );
467 
468     // convert additional and user defined from old system to new system
469     SvNumberformat* pStdFormat = GetFormatEntry( nCLOffset + ZF_STANDARD );
470     sal_uInt32 nLastKey = nMaxBuiltin;
471     pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, true , true);
472     while ( !aOldTable.empty() )
473     {
474         nKey = aOldTable.begin()->first;
475         if ( nLastKey < nKey )
476         {
477             nLastKey = nKey;
478         }
479         std::unique_ptr<SvNumberformat> pOldEntry(aOldTable.begin()->second);
480         aOldTable.erase( nKey );
481         OUString aString( pOldEntry->GetFormatstring() );
482 
483         // Same as PutEntry() but assures key position even if format code is
484         // a duplicate. Also won't mix up any LastInsertKey.
485         ChangeIntl( eOldLanguage );
486         LanguageType eLge = eOldLanguage;   // ConvertMode changes this
487         bool bCheck = false;
488         sal_Int32 nCheckPos = -1;
489         std::unique_ptr<SvNumberformat> pNewEntry(new SvNumberformat( aString, pFormatScanner.get(),
490                                                                       pStringScanner.get(), nCheckPos, eLge ));
491         if ( nCheckPos == 0 )
492         {
493             SvNumFormatType eCheckType = pNewEntry->GetType();
494             if ( eCheckType != SvNumFormatType::UNDEFINED )
495             {
496                 pNewEntry->SetType( eCheckType | SvNumFormatType::DEFINED );
497             }
498             else
499             {
500                 pNewEntry->SetType( SvNumFormatType::DEFINED );
501             }
502 
503             if ( aFTable.emplace( nKey, std::move(pNewEntry) ).second )
504             {
505                 bCheck = true;
506             }
507         }
508         DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
509     }
510     pFormatScanner->SetConvertMode(false);
511     pStdFormat->SetLastInsertKey( sal_uInt16(nLastKey - nCLOffset), SvNumberformat::FormatterPrivateAccess() );
512 
513     // append new system additional formats
514     css::uno::Reference< css::i18n::XNumberFormatCode > xNFC = i18n::NumberFormatMapper::create( m_xContext );
515     ImpGenerateAdditionalFormats( nCLOffset, xNFC, true );
516 }
517 
GetComponentContext() const518 const css::uno::Reference<css::uno::XComponentContext>& SvNumberFormatter::GetComponentContext() const
519 {
520     return m_xContext;
521 }
522 
GetFormatScanner() const523 const ImpSvNumberformatScan* SvNumberFormatter::GetFormatScanner() const { return pFormatScanner.get(); }
524 
GetLanguageTag() const525 const LanguageTag& SvNumberFormatter::GetLanguageTag() const { return maLanguageTag; }
526 
GetTransliteration() const527 const ::utl::TransliterationWrapper* SvNumberFormatter::GetTransliteration() const
528 {
529     return xTransliteration.get();
530 }
531 
GetCharClass() const532 const CharClass* SvNumberFormatter::GetCharClass() const { return pCharClass.get(); }
533 
GetLocaleData() const534 const LocaleDataWrapper* SvNumberFormatter::GetLocaleData() const { return xLocaleData.get(); }
535 
GetCalendar() const536 CalendarWrapper* SvNumberFormatter::GetCalendar() const { return xCalendar.get(); }
537 
GetNatNum() const538 const NativeNumberWrapper* SvNumberFormatter::GetNatNum() const { return xNatNum.get(); }
539 
GetNumDecimalSep() const540 const OUString& SvNumberFormatter::GetNumDecimalSep() const { return aDecimalSep; }
541 
GetNumDecimalSepAlt() const542 const OUString& SvNumberFormatter::GetNumDecimalSepAlt() const { return aDecimalSepAlt; }
543 
GetNumThousandSep() const544 const OUString& SvNumberFormatter::GetNumThousandSep() const { return aThousandSep; }
545 
GetDateSep() const546 const OUString& SvNumberFormatter::GetDateSep() const { return aDateSep; }
547 
IsDecimalSep(const OUString & rStr) const548 bool SvNumberFormatter::IsDecimalSep( const OUString& rStr ) const
549 {
550     if (rStr == GetNumDecimalSep())
551         return true;
552     if (GetNumDecimalSepAlt().isEmpty())
553         return false;
554     return rStr == GetNumDecimalSepAlt();
555 }
556 
IsTextFormat(sal_uInt32 F_Index) const557 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
558 {
559     ::osl::MutexGuard aGuard( GetInstanceMutex() );
560     const SvNumberformat* pFormat = GetFormatEntry(F_Index);
561 
562     return pFormat && pFormat->IsTextFormat();
563 }
564 
PutEntry(OUString & rString,sal_Int32 & nCheckPos,SvNumFormatType & nType,sal_uInt32 & nKey,LanguageType eLnge)565 bool SvNumberFormatter::PutEntry(OUString& rString,
566                                  sal_Int32& nCheckPos,
567                                  SvNumFormatType& nType,
568                                  sal_uInt32& nKey,      // format key
569                                  LanguageType eLnge)
570 {
571     ::osl::MutexGuard aGuard( GetInstanceMutex() );
572     nKey = 0;
573     if (rString.isEmpty())                             // empty string
574     {
575         nCheckPos = 1;                                  // -> Error
576         return false;
577     }
578     if (eLnge == LANGUAGE_DONTKNOW)
579     {
580         eLnge = IniLnge;
581     }
582     ChangeIntl(eLnge);                                  // change locale if necessary
583     LanguageType eLge = eLnge;                          // non-const for ConvertMode
584     bool bCheck = false;
585     std::unique_ptr<SvNumberformat> p_Entry(new SvNumberformat(rString,
586                                                                pFormatScanner.get(),
587                                                                pStringScanner.get(),
588                                                                nCheckPos,
589                                                                eLge));
590 
591     if (nCheckPos == 0)                         // Format ok
592     {                                           // Type comparison:
593         SvNumFormatType eCheckType = p_Entry->GetType();
594         if ( eCheckType != SvNumFormatType::UNDEFINED)
595         {
596             p_Entry->SetType(eCheckType | SvNumFormatType::DEFINED);
597             nType = eCheckType;
598         }
599         else
600         {
601             p_Entry->SetType(SvNumFormatType::DEFINED);
602             nType = SvNumFormatType::DEFINED;
603         }
604 
605         sal_uInt32 CLOffset = ImpGenerateCL(eLge);  // create new standard formats if necessary
606 
607         nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
608         if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND) // only in not yet present
609         {
610             SvNumberformat* pStdFormat = GetFormatEntry(CLOffset + ZF_STANDARD);
611             sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
612             if (nPos+1 - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
613             {
614                 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
615             }
616             else if (!aFTable.emplace( nPos+1, std::move(p_Entry)).second)
617             {
618                 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
619             }
620             else
621             {
622                 bCheck = true;
623                 nKey = nPos+1;
624                 pStdFormat->SetLastInsertKey(static_cast<sal_uInt16>(nKey-CLOffset), SvNumberformat::FormatterPrivateAccess());
625             }
626         }
627     }
628     return bCheck;
629 }
630 
PutandConvertEntry(OUString & rString,sal_Int32 & nCheckPos,SvNumFormatType & nType,sal_uInt32 & nKey,LanguageType eLnge,LanguageType eNewLnge,bool bConvertDateOrder)631 bool SvNumberFormatter::PutandConvertEntry(OUString& rString,
632                                            sal_Int32& nCheckPos,
633                                            SvNumFormatType& nType,
634                                            sal_uInt32& nKey,
635                                            LanguageType eLnge,
636                                            LanguageType eNewLnge,
637                                            bool bConvertDateOrder )
638 {
639     ::osl::MutexGuard aGuard( GetInstanceMutex() );
640     bool bRes;
641     if (eNewLnge == LANGUAGE_DONTKNOW)
642     {
643         eNewLnge = IniLnge;
644     }
645     pFormatScanner->SetConvertMode(eLnge, eNewLnge, false, bConvertDateOrder);
646     bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
647     pFormatScanner->SetConvertMode(false);
648     return bRes;
649 }
650 
PutandConvertEntrySystem(OUString & rString,sal_Int32 & nCheckPos,SvNumFormatType & nType,sal_uInt32 & nKey,LanguageType eLnge,LanguageType eNewLnge)651 bool SvNumberFormatter::PutandConvertEntrySystem(OUString& rString,
652                                                  sal_Int32& nCheckPos,
653                                                  SvNumFormatType& nType,
654                                                  sal_uInt32& nKey,
655                                                  LanguageType eLnge,
656                                                  LanguageType eNewLnge)
657 {
658     ::osl::MutexGuard aGuard( GetInstanceMutex() );
659     bool bRes;
660     if (eNewLnge == LANGUAGE_DONTKNOW)
661     {
662         eNewLnge = IniLnge;
663     }
664     pFormatScanner->SetConvertMode(eLnge, eNewLnge, true, true);
665     bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
666     pFormatScanner->SetConvertMode(false);
667     return bRes;
668 }
669 
GetIndexPuttingAndConverting(OUString & rString,LanguageType eLnge,LanguageType eSysLnge,SvNumFormatType & rType,bool & rNewInserted,sal_Int32 & rCheckPos)670 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( OUString & rString, LanguageType eLnge,
671                                                             LanguageType eSysLnge, SvNumFormatType & rType,
672                                                             bool & rNewInserted, sal_Int32 & rCheckPos )
673 {
674     ::osl::MutexGuard aGuard( GetInstanceMutex() );
675     sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
676     rNewInserted = false;
677     rCheckPos = 0;
678 
679     // #62389# empty format string (of Writer) => General standard format
680     if (rString.isEmpty())
681     {
682         // nothing
683     }
684     else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguageTag().getLanguageType())
685     {
686         sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
687         if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
688         {
689             nKey = nOrig;   // none available, maybe user-defined
690         }
691         else
692         {
693             nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguageTag().getLanguageType() );
694         }
695         if (nKey == nOrig)
696         {
697             // Not a builtin format, convert.
698             // The format code string may get modified and adapted to the real
699             // language and wouldn't match eSysLnge anymore, do that on a copy.
700             OUString aTmp( rString);
701             rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
702                                                      nKey, eLnge, SvtSysLocale().GetLanguageTag().getLanguageType());
703             if (rCheckPos > 0)
704             {
705                 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
706                 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
707             }
708         }
709     }
710     else
711     {
712         nKey = GetEntryKey( rString, eLnge);
713         if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
714         {
715             rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
716             if (rCheckPos > 0)
717             {
718                 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
719                 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
720             }
721         }
722     }
723     if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
724     {
725         nKey = GetStandardIndex( eLnge);
726     }
727     rType = GetType( nKey);
728     // Convert any (!) old "automatic" currency format to new fixed currency
729     // default format.
730     if (rType & SvNumFormatType::CURRENCY)
731     {
732         const SvNumberformat* pFormat = GetEntry( nKey);
733         if (!pFormat->HasNewCurrency())
734         {
735             if (rNewInserted)
736             {
737                 DeleteEntry( nKey);     // don't leave trails of rubbish
738                 rNewInserted = false;
739             }
740             nKey = GetStandardFormat( SvNumFormatType::CURRENCY, eLnge);
741         }
742     }
743     return nKey;
744 }
745 
DeleteEntry(sal_uInt32 nKey)746 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
747 {
748     ::osl::MutexGuard aGuard( GetInstanceMutex() );
749     aFTable.erase(nKey);
750 }
751 
GetUsedLanguages(std::vector<LanguageType> & rList)752 void SvNumberFormatter::GetUsedLanguages( std::vector<LanguageType>& rList )
753 {
754     ::osl::MutexGuard aGuard( GetInstanceMutex() );
755     rList.clear();
756 
757     sal_uInt32 nOffset = 0;
758     while (nOffset <= MaxCLOffset)
759     {
760         SvNumberformat* pFormat = GetFormatEntry(nOffset);
761         if (pFormat)
762         {
763             rList.push_back( pFormat->GetLanguage() );
764         }
765         nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
766     }
767 }
768 
769 
FillKeywordTable(NfKeywordTable & rKeywords,LanguageType eLang)770 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
771                                           LanguageType eLang )
772 {
773     ::osl::MutexGuard aGuard( GetInstanceMutex() );
774     ChangeIntl( eLang );
775     const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
776     for ( sal_uInt16 i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
777     {
778         rKeywords[i] = rTable[i];
779     }
780 }
781 
782 
FillKeywordTableForExcel(NfKeywordTable & rKeywords)783 void SvNumberFormatter::FillKeywordTableForExcel( NfKeywordTable& rKeywords )
784 {
785     ::osl::MutexGuard aGuard( GetInstanceMutex() );
786     FillKeywordTable( rKeywords, LANGUAGE_ENGLISH_US );
787 
788     // Replace upper case "GENERAL" with proper case "General".
789     rKeywords[ NF_KEY_GENERAL ] = GetStandardName( LANGUAGE_ENGLISH_US );
790 
791     // Excel or OOXML do not specify format code keywords case sensitivity,
792     // but given and writes them lower case. Using upper case even lead to an
793     // odd misrepresentation in iOS viewer and OSX Quicklook viewer that
794     // strangely use "D" and "DD" for "days since beginning of year", which is
795     // nowhere defined. See tdf#126773
796     // Use lower case for all date and time keywords where known. See OOXML
797     // ECMA-376-1:2016 18.8.31 numFmts (Number Formats)
798     rKeywords[ NF_KEY_MI ]    = "m";
799     rKeywords[ NF_KEY_MMI ]   = "mm";
800     rKeywords[ NF_KEY_M ]     = "m";
801     rKeywords[ NF_KEY_MM ]    = "mm";
802     rKeywords[ NF_KEY_MMM ]   = "mmm";
803     rKeywords[ NF_KEY_MMMM ]  = "mmmm";
804     rKeywords[ NF_KEY_MMMMM ] = "mmmmm";
805     rKeywords[ NF_KEY_H ]     = "h";
806     rKeywords[ NF_KEY_HH ]    = "hh";
807     rKeywords[ NF_KEY_S ]     = "s";
808     rKeywords[ NF_KEY_SS ]    = "ss";
809     /* XXX: not defined in OOXML: rKeywords[ NF_KEY_Q ]     = "q"; */
810     /* XXX: not defined in OOXML: rKeywords[ NF_KEY_QQ ]    = "qq"; */
811     rKeywords[ NF_KEY_D ]     = "d";
812     rKeywords[ NF_KEY_DD ]    = "dd";
813     rKeywords[ NF_KEY_DDD ]   = "ddd";
814     rKeywords[ NF_KEY_DDDD ]  = "dddd";
815     rKeywords[ NF_KEY_YY ]    = "yy";
816     rKeywords[ NF_KEY_YYYY ]  = "yyyy";
817     /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAA ]   = "aaa"; */
818     /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAAA ]  = "aaaa"; */
819     rKeywords[ NF_KEY_EC ]    = "e";
820     rKeywords[ NF_KEY_EEC ]   = "ee";
821     rKeywords[ NF_KEY_G ]     = "g";
822     rKeywords[ NF_KEY_GG ]    = "gg";
823     rKeywords[ NF_KEY_GGG ]   = "ggg";
824     rKeywords[ NF_KEY_R ]     = "r";
825     rKeywords[ NF_KEY_RR ]    = "rr";
826     /* XXX: not defined in OOXML: rKeywords[ NF_KEY_WW ]    = "ww"; */
827 
828     // Remap codes unknown to Excel.
829     rKeywords[ NF_KEY_NN ] = "ddd";
830     rKeywords[ NF_KEY_NNN ] = "dddd";
831     // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
832     rKeywords[ NF_KEY_NNNN ] = "dddd";
833     // Export the Thai T NatNum modifier. This must be uppercase for internal reasons.
834     rKeywords[ NF_KEY_THAI_T ] = "T";
835 }
836 
837 
GetFormatStringForExcel(sal_uInt32 nKey,const NfKeywordTable & rKeywords,SvNumberFormatter & rTempFormatter) const838 OUString SvNumberFormatter::GetFormatStringForExcel( sal_uInt32 nKey, const NfKeywordTable& rKeywords,
839         SvNumberFormatter& rTempFormatter ) const
840 {
841     ::osl::MutexGuard aGuard( GetInstanceMutex() );
842     OUString aFormatStr;
843     if (const SvNumberformat* pEntry = GetEntry( nKey))
844     {
845         if (pEntry->GetType() == SvNumFormatType::LOGICAL)
846         {
847             // Build Boolean number format, which needs non-zero and zero
848             // subformat codes with TRUE and FALSE strings.
849             Color* pColor = nullptr;
850             OUString aTemp;
851             const_cast< SvNumberformat* >( pEntry )->GetOutputString( 1.0, aTemp, &pColor );
852             aFormatStr += "\"" + aTemp + "\";\"" + aTemp + "\";\"";
853             const_cast< SvNumberformat* >( pEntry )->GetOutputString( 0.0, aTemp, &pColor );
854             aFormatStr += aTemp + "\"";
855         }
856         else
857         {
858             bool bSystemLanguage = false;
859             LanguageType nLang = pEntry->GetLanguage();
860             if (nLang == LANGUAGE_SYSTEM)
861             {
862                 bSystemLanguage = true;
863                 nLang = SvtSysLocale().GetLanguageTag().getLanguageType();
864             }
865             if (nLang != LANGUAGE_ENGLISH_US)
866             {
867                 sal_Int32 nCheckPos;
868                 SvNumFormatType nType = SvNumFormatType::DEFINED;
869                 sal_uInt32 nTempKey;
870                 OUString aTemp( pEntry->GetFormatstring());
871                 rTempFormatter.PutandConvertEntry( aTemp, nCheckPos, nType, nTempKey, nLang, LANGUAGE_ENGLISH_US, false);
872                 SAL_WARN_IF( nCheckPos != 0, "svl.numbers",
873                         "SvNumberFormatter::GetFormatStringForExcel - format code not convertible");
874                 if (nTempKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
875                     pEntry = rTempFormatter.GetEntry( nTempKey);
876             }
877 
878             if (pEntry)
879             {
880                 // GetLocaleData() returns the current locale's data, so switch
881                 // before (which doesn't do anything if it was the same locale
882                 // already).
883                 rTempFormatter.ChangeIntl( LANGUAGE_ENGLISH_US);
884                 aFormatStr = pEntry->GetMappedFormatstring( rKeywords, *rTempFormatter.GetLocaleData(), nLang,
885                         bSystemLanguage);
886             }
887         }
888     }
889     else
890     {
891         SAL_WARN("svl.numbers","SvNumberFormatter::GetFormatStringForExcel - format not found: " << nKey);
892     }
893 
894     if (aFormatStr.isEmpty())
895         aFormatStr = "General";
896     return aFormatStr;
897 }
898 
899 
GetKeyword(LanguageType eLnge,sal_uInt16 nIndex)900 OUString SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
901 {
902     ::osl::MutexGuard aGuard( GetInstanceMutex() );
903     ChangeIntl(eLnge);
904     const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
905     if ( nIndex < NF_KEYWORD_ENTRIES_COUNT )
906     {
907         return rTable[nIndex];
908     }
909     SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
910     return OUString();
911 }
912 
913 
GetStandardName(LanguageType eLnge)914 OUString SvNumberFormatter::GetStandardName( LanguageType eLnge )
915 {
916     ::osl::MutexGuard aGuard( GetInstanceMutex() );
917     ChangeIntl( eLnge );
918     return pFormatScanner->GetStandardName();
919 }
920 
921 
ImpGetCLOffset(LanguageType eLnge) const922 sal_uInt32 SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge) const
923 {
924     sal_uInt32 nOffset = 0;
925     while (nOffset <= MaxCLOffset)
926     {
927         const SvNumberformat* pFormat = GetFormatEntry(nOffset);
928         if (pFormat && pFormat->GetLanguage() == eLnge)
929         {
930             return nOffset;
931         }
932         nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
933     }
934     return nOffset;
935 }
936 
ImpIsEntry(const OUString & rString,sal_uInt32 nCLOffset,LanguageType eLnge)937 sal_uInt32 SvNumberFormatter::ImpIsEntry(const OUString& rString,
938                                          sal_uInt32 nCLOffset,
939                                          LanguageType eLnge)
940 {
941     sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND;
942     auto it = aFTable.find( nCLOffset);
943     while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND &&
944             it != aFTable.end() && it->second->GetLanguage() == eLnge )
945     {
946         if ( rString == it->second->GetFormatstring() )
947         {
948             res = it->first;
949         }
950         else
951         {
952             ++it;
953         }
954     }
955     return res;
956 }
957 
958 
GetFirstEntryTable(SvNumFormatType & eType,sal_uInt32 & FIndex,LanguageType & rLnge)959 SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable(
960                                                       SvNumFormatType& eType,
961                                                       sal_uInt32& FIndex,
962                                                       LanguageType& rLnge)
963 {
964     ::osl::MutexGuard aGuard( GetInstanceMutex() );
965     SvNumFormatType eTypetmp = eType;
966     if (eType == SvNumFormatType::ALL)                  // empty cell or don't care
967     {
968         rLnge = IniLnge;
969     }
970     else
971     {
972         SvNumberformat* pFormat = GetFormatEntry(FIndex);
973         if (!pFormat)
974         {
975             rLnge = IniLnge;
976             eType = SvNumFormatType::ALL;
977             eTypetmp = eType;
978         }
979         else
980         {
981             rLnge = pFormat->GetLanguage();
982             eType = pFormat->GetMaskedType();
983             if (eType == SvNumFormatType::ALL)
984             {
985                 eType = SvNumFormatType::DEFINED;
986                 eTypetmp = eType;
987             }
988             else if (eType == SvNumFormatType::DATETIME)
989             {
990                 eTypetmp = eType;
991                 eType = SvNumFormatType::DATE;
992             }
993             else
994             {
995                 eTypetmp = eType;
996             }
997         }
998     }
999     ChangeIntl(rLnge);
1000     return GetEntryTable(eTypetmp, FIndex, rLnge);
1001 }
1002 
ImpGenerateCL(LanguageType eLnge)1003 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge )
1004 {
1005     ChangeIntl(eLnge);
1006     sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1007     if (CLOffset > MaxCLOffset)
1008     {
1009         // new CL combination
1010         if (LocaleDataWrapper::areChecksEnabled())
1011         {
1012             const LanguageTag& rLoadedLocale = xLocaleData->getLoadedLanguageTag();
1013             if ( !rLoadedLocale.equals( maLanguageTag ) )
1014             {
1015                 OUString const aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
1016                 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg ));
1017             }
1018             // test XML locale data FormatElement entries
1019             {
1020                 uno::Sequence< i18n::FormatElement > xSeq = xLocaleData->getAllFormats();
1021                 // A test for completeness of formatindex="0" ...
1022                 // formatindex="47" is not needed here since it is done in
1023                 // ImpGenerateFormats().
1024 
1025                 // Test for dupes of formatindex="..."
1026                 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
1027                 {
1028                     sal_Int16 nIdx = xSeq[j].formatIndex;
1029                     OUStringBuffer aDupes;
1030                     for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
1031                     {
1032                         if ( i != j && xSeq[i].formatIndex == nIdx )
1033                         {
1034                             aDupes.append(OUString::number( i ));
1035                             aDupes.append("(");
1036                             aDupes.append(xSeq[i].formatKey);
1037                             aDupes.append( ") ");
1038                         }
1039                     }
1040                     if ( !aDupes.isEmpty() )
1041                     {
1042                         OUString aMsg = "XML locale data FormatElement formatindex dupe: "
1043                                       + OUString::number(nIdx)
1044                                       + "\nFormatElements: "
1045                                       + OUString::number( j )
1046                                       + "("
1047                                       + xSeq[j].formatKey
1048                                       + ") "
1049                                       + aDupes.makeStringAndClear();
1050                         LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg ));
1051                     }
1052                 }
1053             }
1054         }
1055 
1056         MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1057         ImpGenerateFormats( MaxCLOffset, false/*bNoAdditionalFormats*/ );
1058         CLOffset = MaxCLOffset;
1059     }
1060     return CLOffset;
1061 }
1062 
ChangeCL(SvNumFormatType eType,sal_uInt32 & FIndex,LanguageType eLnge)1063 SvNumberFormatTable& SvNumberFormatter::ChangeCL(SvNumFormatType eType,
1064                                                  sal_uInt32& FIndex,
1065                                                  LanguageType eLnge)
1066 {
1067     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1068     ImpGenerateCL(eLnge);
1069     return GetEntryTable(eType, FIndex, ActLnge);
1070 }
1071 
GetEntryTable(SvNumFormatType eType,sal_uInt32 & FIndex,LanguageType eLnge)1072 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
1073                                                     SvNumFormatType eType,
1074                                                     sal_uInt32& FIndex,
1075                                                     LanguageType eLnge)
1076 {
1077     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1078     if ( pFormatTable )
1079     {
1080         pFormatTable->clear();
1081     }
1082     else
1083     {
1084         pFormatTable.reset( new SvNumberFormatTable );
1085     }
1086     ChangeIntl(eLnge);
1087     sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1088 
1089     // Might generate and insert a default format for the given type
1090     // (e.g. currency) => has to be done before collecting formats.
1091     sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
1092 
1093     auto it = aFTable.find( CLOffset);
1094 
1095     if (eType == SvNumFormatType::ALL)
1096     {
1097         while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1098         {   // copy all entries to output table
1099             (*pFormatTable)[ it->first ] = it->second.get();
1100             ++it;
1101         }
1102     }
1103     else
1104     {
1105         while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1106         {   // copy entries of queried type to output table
1107             if ((it->second->GetType()) & eType)
1108                 (*pFormatTable)[ it->first ] = it->second.get();
1109             ++it;
1110         }
1111     }
1112     if ( !pFormatTable->empty() )
1113     {   // select default if queried format doesn't exist or queried type or
1114         // language differ from existing format
1115         SvNumberformat* pEntry = GetFormatEntry(FIndex);
1116         if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
1117         {
1118             FIndex = nDefaultIndex;
1119         }
1120     }
1121     return *pFormatTable;
1122 }
1123 
IsNumberFormat(const OUString & sString,sal_uInt32 & F_Index,double & fOutNumber,SvNumInputOptions eInputOptions)1124 bool SvNumberFormatter::IsNumberFormat(const OUString& sString,
1125                                        sal_uInt32& F_Index,
1126                                        double& fOutNumber,
1127                                        SvNumInputOptions eInputOptions)
1128 {
1129     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1130 
1131     SvNumFormatType FType;
1132     // For the 0 General format directly use the init/system locale and avoid
1133     // all overhead that is associated with a format passed to the scanner.
1134     const SvNumberformat* pFormat = (F_Index == 0 ? nullptr : ImpSubstituteEntry( GetFormatEntry(F_Index)));
1135     if (!pFormat)
1136     {
1137         ChangeIntl(IniLnge);
1138         FType = SvNumFormatType::NUMBER;
1139     }
1140     else
1141     {
1142         FType = pFormat->GetMaskedType();
1143         if (FType == SvNumFormatType::ALL)
1144         {
1145             FType = SvNumFormatType::DEFINED;
1146         }
1147         ChangeIntl(pFormat->GetLanguage());
1148         // Avoid scanner overhead with the General format of any locale.
1149         // These are never substituted above so safe to ignore.
1150         if ((F_Index % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1151         {
1152             assert(FType == SvNumFormatType::NUMBER);
1153             pFormat = nullptr;
1154         }
1155     }
1156 
1157     bool res;
1158     SvNumFormatType RType = FType;
1159     if (RType == SvNumFormatType::TEXT)
1160     {
1161         res = false;        // type text preset => no conversion to number
1162     }
1163     else
1164     {
1165         res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat, eInputOptions);
1166     }
1167     if (res && !IsCompatible(FType, RType))     // non-matching type
1168     {
1169         switch ( RType )
1170         {
1171         case SvNumFormatType::DATE :
1172             // Preserve ISO 8601 input.
1173             if (pStringScanner->CanForceToIso8601( DateOrder::Invalid))
1174             {
1175                 F_Index = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, ActLnge );
1176             }
1177             else
1178             {
1179                 F_Index = GetStandardFormat( RType, ActLnge );
1180             }
1181             break;
1182         case SvNumFormatType::TIME :
1183             if ( pStringScanner->GetDecPos() )
1184             {
1185                 // 100th seconds
1186                 if ( pStringScanner->GetNumericsCount() > 3 || fOutNumber < 0.0 )
1187                 {
1188                     F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
1189                 }
1190                 else
1191                 {
1192                     F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge );
1193                 }
1194             }
1195             else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1196             {
1197                 F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge );
1198             }
1199             else
1200             {
1201                 F_Index = GetStandardFormat( RType, ActLnge );
1202             }
1203             break;
1204         case SvNumFormatType::DATETIME :
1205             // Preserve ISO 8601 input.
1206             if (pStringScanner->HasIso8601Tsep())
1207             {
1208                 F_Index = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS, ActLnge );
1209             }
1210             else if (pStringScanner->CanForceToIso8601( DateOrder::Invalid))
1211             {
1212                 F_Index = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, ActLnge );
1213             }
1214             else
1215             {
1216                 F_Index = GetStandardFormat( RType, ActLnge );
1217             }
1218             break;
1219         default:
1220             F_Index = GetStandardFormat( RType, ActLnge );
1221         }
1222     }
1223     return res;
1224 }
1225 
GetLanguage() const1226 LanguageType SvNumberFormatter::GetLanguage() const
1227 {
1228     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1229     return IniLnge;
1230 }
1231 
1232 // static
IsCompatible(SvNumFormatType eOldType,SvNumFormatType eNewType)1233 bool SvNumberFormatter::IsCompatible(SvNumFormatType eOldType, SvNumFormatType eNewType)
1234 {
1235     if (eOldType == eNewType)
1236     {
1237         return true;
1238     }
1239     else if (eOldType == SvNumFormatType::DEFINED)
1240     {
1241         return true;
1242     }
1243     else
1244     {
1245         switch (eNewType)
1246         {
1247         case SvNumFormatType::NUMBER:
1248             switch (eOldType)
1249             {
1250             case SvNumFormatType::PERCENT:
1251             case SvNumFormatType::CURRENCY:
1252             case SvNumFormatType::SCIENTIFIC:
1253             case SvNumFormatType::FRACTION:
1254             case SvNumFormatType::DEFINED:
1255                 return true;
1256             case SvNumFormatType::LOGICAL:
1257             default:
1258                 return false;
1259             }
1260             break;
1261         case SvNumFormatType::DATE:
1262             switch (eOldType)
1263             {
1264             case SvNumFormatType::DATETIME:
1265                 return true;
1266             default:
1267                 return false;
1268             }
1269             break;
1270         case SvNumFormatType::TIME:
1271             switch (eOldType)
1272             {
1273             case SvNumFormatType::DATETIME:
1274                 return true;
1275             default:
1276                 return false;
1277             }
1278             break;
1279         case SvNumFormatType::DATETIME:
1280             switch (eOldType)
1281             {
1282             case SvNumFormatType::TIME:
1283             case SvNumFormatType::DATE:
1284                 return true;
1285             default:
1286                 return false;
1287             }
1288             break;
1289         case SvNumFormatType::DURATION:
1290             return false;
1291         default:
1292             return false;
1293         }
1294     }
1295 }
1296 
1297 
ImpGetDefaultFormat(SvNumFormatType nType)1298 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( SvNumFormatType nType )
1299 {
1300     sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1301     sal_uInt32 nSearch;
1302     switch( nType )
1303     {
1304     case SvNumFormatType::DATE:
1305         nSearch = CLOffset + ZF_STANDARD_DATE;
1306         break;
1307     case SvNumFormatType::TIME:
1308         nSearch = CLOffset + ZF_STANDARD_TIME;
1309         break;
1310     case SvNumFormatType::DATETIME:
1311         nSearch = CLOffset + ZF_STANDARD_DATETIME;
1312         break;
1313     case SvNumFormatType::DURATION:
1314         nSearch = CLOffset + ZF_STANDARD_DURATION;
1315         break;
1316     case SvNumFormatType::PERCENT:
1317         nSearch = CLOffset + ZF_STANDARD_PERCENT;
1318         break;
1319     case SvNumFormatType::SCIENTIFIC:
1320         nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1321         break;
1322     default:
1323         nSearch = CLOffset + ZF_STANDARD;
1324     }
1325 
1326     DefaultFormatKeysMap::const_iterator it = aDefaultFormatKeys.find( nSearch);
1327     sal_uInt32 nDefaultFormat = (it != aDefaultFormatKeys.end() ?
1328                                  it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
1329     if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1330     {
1331         // look for a defined standard
1332         sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1333         sal_uInt32 nKey(0);
1334         auto it2 = aFTable.find( CLOffset );
1335         while ( it2 != aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey )
1336         {
1337             const SvNumberformat* pEntry = it2->second.get();
1338             if ( pEntry->IsStandard() && (pEntry->GetMaskedType() == nType) )
1339             {
1340                 nDefaultFormat = nKey;
1341                 break;  // while
1342             }
1343             ++it2;
1344         }
1345 
1346         if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1347         {   // none found, use old fixed standards
1348             switch( nType )
1349             {
1350             case SvNumFormatType::DATE:
1351                 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1352                 break;
1353             case SvNumFormatType::TIME:
1354                 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1355                 break;
1356             case SvNumFormatType::DATETIME:
1357                 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1358                 break;
1359             case SvNumFormatType::DURATION:
1360                 nDefaultFormat = CLOffset + ZF_STANDARD_DURATION;
1361                 break;
1362             case SvNumFormatType::PERCENT:
1363                 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1364                 break;
1365             case SvNumFormatType::SCIENTIFIC:
1366                 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1367                 break;
1368             default:
1369                 nDefaultFormat = CLOffset + ZF_STANDARD;
1370             }
1371         }
1372         aDefaultFormatKeys[ nSearch ] = nDefaultFormat;
1373     }
1374     return nDefaultFormat;
1375 }
1376 
1377 
GetStandardFormat(SvNumFormatType eType,LanguageType eLnge)1378 sal_uInt32 SvNumberFormatter::GetStandardFormat( SvNumFormatType eType, LanguageType eLnge )
1379 {
1380     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1381     if (eLnge == LANGUAGE_DONTKNOW)
1382     {
1383         eLnge = IniLnge;
1384     }
1385     sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1386     switch(eType)
1387     {
1388     case SvNumFormatType::CURRENCY:
1389         return ( eLnge == LANGUAGE_SYSTEM ) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1390     case SvNumFormatType::DURATION :
1391         return GetFormatIndex( NF_TIME_HH_MMSS, eLnge);
1392     case SvNumFormatType::DATE:
1393     case SvNumFormatType::TIME:
1394     case SvNumFormatType::DATETIME:
1395     case SvNumFormatType::PERCENT:
1396     case SvNumFormatType::SCIENTIFIC:
1397         return ImpGetDefaultFormat( eType );
1398     case SvNumFormatType::FRACTION:
1399         return CLOffset + ZF_STANDARD_FRACTION;
1400     case SvNumFormatType::LOGICAL:
1401         return CLOffset + ZF_STANDARD_LOGICAL;
1402     case SvNumFormatType::TEXT:
1403         return CLOffset + ZF_STANDARD_TEXT;
1404     case SvNumFormatType::ALL:
1405     case SvNumFormatType::DEFINED:
1406     case SvNumFormatType::NUMBER:
1407     case SvNumFormatType::UNDEFINED:
1408     default:
1409         return CLOffset + ZF_STANDARD;
1410     }
1411 }
1412 
IsSpecialStandardFormat(sal_uInt32 nFIndex,LanguageType eLnge)1413 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1414                                                  LanguageType eLnge )
1415 {
1416     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1417     return
1418         nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1419         nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1420         nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1421         ;
1422 }
1423 
GetStandardFormat(sal_uInt32 nFIndex,SvNumFormatType eType,LanguageType eLnge)1424 sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, SvNumFormatType eType,
1425                                                  LanguageType eLnge )
1426 {
1427     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1428     if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1429         return nFIndex;
1430     else
1431         return GetStandardFormat( eType, eLnge );
1432 }
1433 
GetTimeFormat(double fNumber,LanguageType eLnge,bool bForceDuration)1434 sal_uInt32 SvNumberFormatter::GetTimeFormat( double fNumber, LanguageType eLnge, bool bForceDuration )
1435 {
1436     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1437     bool bSign;
1438     if ( fNumber < 0.0 )
1439     {
1440         bSign = true;
1441         fNumber = -fNumber;
1442     }
1443     else
1444         bSign = false;
1445     double fSeconds = fNumber * 86400;
1446     if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1447     {   // with 100th seconds
1448         if ( bForceDuration || bSign || fSeconds >= 3600 )
1449             return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1450         else
1451             return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1452     }
1453     else
1454     {
1455         if ( bForceDuration || bSign || fNumber >= 1.0 )
1456             return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1457         else
1458             return GetStandardFormat( SvNumFormatType::TIME, eLnge );
1459     }
1460 }
1461 
GetStandardFormat(double fNumber,sal_uInt32 nFIndex,SvNumFormatType eType,LanguageType eLnge)1462 sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1463                                                  SvNumFormatType eType, LanguageType eLnge )
1464 {
1465     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1466     if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1467         return nFIndex;
1468 
1469     switch( eType )
1470     {
1471         case SvNumFormatType::DURATION :
1472             return GetTimeFormat( fNumber, eLnge, true);
1473         case SvNumFormatType::TIME :
1474             return GetTimeFormat( fNumber, eLnge, false);
1475         default:
1476             return GetStandardFormat( eType, eLnge );
1477     }
1478 }
1479 
GuessDateTimeFormat(SvNumFormatType & rType,double fNumber,LanguageType eLnge)1480 sal_uInt32 SvNumberFormatter::GuessDateTimeFormat( SvNumFormatType& rType, double fNumber, LanguageType eLnge )
1481 {
1482     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1483     // Categorize the format according to the implementation of
1484     // SvNumberFormatter::GetEditFormat(), making assumptions about what
1485     // would be time only.
1486     sal_uInt32 nRet;
1487     if (0.0 <= fNumber && fNumber < 1.0)
1488     {
1489         // Clearly a time.
1490         rType = SvNumFormatType::TIME;
1491         nRet = GetTimeFormat( fNumber, eLnge, false);
1492     }
1493     else if (fabs( fNumber) * 24 < 0x7fff)
1494     {
1495         // Assuming duration within 32k hours or 3.7 years.
1496         // This should be SvNumFormatType::DURATION instead, but the outer
1497         // world can't cope with that.
1498         rType = SvNumFormatType::TIME;
1499         nRet = GetTimeFormat( fNumber, eLnge, true);
1500     }
1501     else if (rtl::math::approxFloor( fNumber) != fNumber)
1502     {
1503         // Date+Time.
1504         rType = SvNumFormatType::DATETIME;
1505         nRet = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLnge);
1506     }
1507     else
1508     {
1509         // Date only.
1510         rType = SvNumFormatType::DATE;
1511         nRet = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLnge);
1512     }
1513     return nRet;
1514 }
1515 
GetEditFormat(double fNumber,sal_uInt32 nFIndex,SvNumFormatType eType,LanguageType eLang,SvNumberformat const * pFormat)1516 sal_uInt32 SvNumberFormatter::GetEditFormat( double fNumber, sal_uInt32 nFIndex,
1517                                              SvNumFormatType eType, LanguageType eLang,
1518                                              SvNumberformat const * pFormat )
1519 {
1520     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1521     sal_uInt32 nKey = nFIndex;
1522     switch ( eType )
1523     {
1524     // #61619# always edit using 4-digit year
1525     case SvNumFormatType::DATE :
1526         {
1527             // Preserve ISO 8601 format.
1528             bool bIsoDate =
1529                 nFIndex == GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang) ||
1530                 nFIndex == GetFormatIndex( NF_DATE_DIN_YYMMDD, eLang) ||
1531                 nFIndex == GetFormatIndex( NF_DATE_DIN_MMDD, eLang) ||
1532                 (pFormat && pFormat->IsIso8601( 0 ));
1533             if (rtl::math::approxFloor( fNumber) != fNumber)
1534             {
1535                 // fdo#34977 preserve time when editing even if only date was
1536                 // displayed.
1537                 if (bIsoDate)
1538                     nKey = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, eLang);
1539                 else
1540                     nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1541             }
1542             else
1543             {
1544                 if (bIsoDate)
1545                     nKey = GetFormatIndex( NF_DATE_ISO_YYYYMMDD, eLang);
1546                 else
1547                     nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1548             }
1549         }
1550         break;
1551     case SvNumFormatType::TIME :
1552         if (fNumber < 0.0 || fNumber >= 1.0)
1553         {
1554             /* XXX NOTE: this is a purely arbitrary value within the limits
1555              * of a signed 16-bit. 32k hours are 3.7 years ... or
1556              * 1903-09-26 if date. */
1557             if (fabs( fNumber) * 24 < 0x7fff)
1558                 nKey = GetTimeFormat( fNumber, eLang, true);
1559             // Preserve duration, use [HH]:MM:SS instead of time.
1560             else
1561                 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1562             // Assume that a large value is a datetime with only time
1563             // displayed.
1564         }
1565         else
1566             nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1567         break;
1568     case SvNumFormatType::DURATION :
1569         nKey = GetTimeFormat( fNumber, eLang, true);
1570         break;
1571     case SvNumFormatType::DATETIME :
1572         if (nFIndex == GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS, eLang))
1573             nKey = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS, eLang );
1574         else if (nFIndex == GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, eLang) || (pFormat && pFormat->IsIso8601( 0 )))
1575             nKey = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, eLang );
1576         else
1577             nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1578         break;
1579     case SvNumFormatType::NUMBER:
1580         nKey = GetStandardFormat( eType, eLang );
1581         break;
1582     default:
1583         nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1584     }
1585     return nKey;
1586 }
1587 
GetInputLineString(const double & fOutNumber,sal_uInt32 nFIndex,OUString & sOutString)1588 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1589                                            sal_uInt32 nFIndex,
1590                                            OUString& sOutString)
1591 {
1592     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1593     Color* pColor;
1594     sal_uInt32 nRealKey = nFIndex;
1595     SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ), &nRealKey);
1596     if (!pFormat)
1597     {
1598         pFormat = GetFormatEntry(ZF_STANDARD);
1599     }
1600 
1601     LanguageType eLang = pFormat->GetLanguage();
1602     ChangeIntl( eLang );
1603 
1604     SvNumFormatType eType = pFormat->GetMaskedType();
1605     if (eType == SvNumFormatType::ALL)
1606     {
1607         // Mixed types in subformats, use first.
1608         /* XXX we could choose a subformat according to fOutNumber and
1609          * subformat conditions, but they may exist to suppress 0 or negative
1610          * numbers so wouldn't be a safe bet. */
1611         eType = pFormat->GetNumForInfoScannedType(0);
1612     }
1613 
1614     sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
1615     bool bPrecChanged = false;
1616     if (eType == SvNumFormatType::NUMBER ||
1617         eType == SvNumFormatType::PERCENT ||
1618         eType == SvNumFormatType::CURRENCY ||
1619         eType == SvNumFormatType::SCIENTIFIC ||
1620         eType == SvNumFormatType::FRACTION)
1621     {
1622         if (eType != SvNumFormatType::PERCENT)  // special treatment of % later
1623         {
1624             eType = SvNumFormatType::NUMBER;
1625         }
1626         ChangeStandardPrec(INPUTSTRING_PRECISION);
1627         bPrecChanged = true;
1628     }
1629 
1630     sal_uInt32 nKey = GetEditFormat( fOutNumber, nRealKey, eType, eLang, pFormat);
1631     if ( nKey != nRealKey )
1632     {
1633         pFormat = GetFormatEntry( nKey );
1634     }
1635     if (pFormat)
1636     {
1637         if ( eType == SvNumFormatType::TIME && pFormat->GetFormatPrecision() )
1638         {
1639             ChangeStandardPrec(INPUTSTRING_PRECISION);
1640             bPrecChanged = true;
1641         }
1642         pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1643     }
1644     if (bPrecChanged)
1645     {
1646         ChangeStandardPrec(nOldPrec);
1647     }
1648 }
1649 
GetOutputString(const OUString & sString,sal_uInt32 nFIndex,OUString & sOutString,Color ** ppColor,bool bUseStarFormat)1650 void SvNumberFormatter::GetOutputString(const OUString& sString,
1651                                         sal_uInt32 nFIndex,
1652                                         OUString& sOutString,
1653                                         Color** ppColor,
1654                                         bool bUseStarFormat )
1655 {
1656     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1657     SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1658     // ImpSubstituteEntry() is unnecessary here because so far only numeric
1659     // (time and date) are substituted.
1660     if (!pFormat)
1661     {
1662         pFormat = GetFormatEntry(ZF_STANDARD_TEXT);
1663     }
1664     if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1665     {
1666         *ppColor = nullptr;
1667         sOutString = sString;
1668     }
1669     else
1670     {
1671         ChangeIntl(pFormat->GetLanguage());
1672         if ( bUseStarFormat )
1673         {
1674            pFormat->SetStarFormatSupport( true );
1675         }
1676         pFormat->GetOutputString(sString, sOutString, ppColor);
1677         if ( bUseStarFormat )
1678         {
1679            pFormat->SetStarFormatSupport( false );
1680         }
1681     }
1682 }
1683 
GetOutputString(const double & fOutNumber,sal_uInt32 nFIndex,OUString & sOutString,Color ** ppColor,bool bUseStarFormat)1684 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1685                                         sal_uInt32 nFIndex,
1686                                         OUString& sOutString,
1687                                         Color** ppColor,
1688                                         bool bUseStarFormat )
1689 {
1690     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1691     if (bNoZero && fOutNumber == 0.0)
1692     {
1693         sOutString.clear();
1694         return;
1695     }
1696     SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ));
1697     if (!pFormat)
1698         pFormat = GetFormatEntry(ZF_STANDARD);
1699     ChangeIntl(pFormat->GetLanguage());
1700     if ( bUseStarFormat )
1701         pFormat->SetStarFormatSupport( true );
1702     pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1703     if ( bUseStarFormat )
1704         pFormat->SetStarFormatSupport( false );
1705 }
1706 
GetPreviewString(const OUString & sFormatString,double fPreviewNumber,OUString & sOutString,Color ** ppColor,LanguageType eLnge,bool bUseStarFormat)1707 bool SvNumberFormatter::GetPreviewString(const OUString& sFormatString,
1708                                          double fPreviewNumber,
1709                                          OUString& sOutString,
1710                                          Color** ppColor,
1711                                          LanguageType eLnge,
1712                                          bool bUseStarFormat )
1713 {
1714     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1715     if (sFormatString.isEmpty())                       // no empty string
1716     {
1717         return false;
1718     }
1719     sal_uInt32 nKey;
1720     if (eLnge == LANGUAGE_DONTKNOW)
1721     {
1722         eLnge = IniLnge;
1723     }
1724     ChangeIntl(eLnge);                          // change locale if necessary
1725     eLnge = ActLnge;
1726     sal_Int32 nCheckPos = -1;
1727     OUString sTmpString = sFormatString;
1728     std::unique_ptr<SvNumberformat> p_Entry(new SvNumberformat(sTmpString,
1729                                                  pFormatScanner.get(),
1730                                                  pStringScanner.get(),
1731                                                  nCheckPos,
1732                                                  eLnge));
1733     if (nCheckPos == 0)                                 // String ok
1734     {
1735         sal_uInt32 CLOffset = ImpGenerateCL(eLnge);     // create new standard formats if necessary
1736         nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1737         if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND)       // already present
1738         {
1739             GetOutputString(fPreviewNumber, nKey, sOutString, ppColor, bUseStarFormat);
1740         }
1741         else
1742         {
1743             if ( bUseStarFormat )
1744             {
1745                 p_Entry->SetStarFormatSupport( true );
1746             }
1747             p_Entry->GetOutputString(fPreviewNumber, sOutString, ppColor);
1748             if ( bUseStarFormat )
1749             {
1750                 p_Entry->SetStarFormatSupport( false );
1751             }
1752         }
1753         return true;
1754     }
1755     else
1756     {
1757         return false;
1758     }
1759 }
1760 
GetPreviewStringGuess(const OUString & sFormatString,double fPreviewNumber,OUString & sOutString,Color ** ppColor,LanguageType eLnge)1761 bool SvNumberFormatter::GetPreviewStringGuess( const OUString& sFormatString,
1762                                                double fPreviewNumber,
1763                                                OUString& sOutString,
1764                                                Color** ppColor,
1765                                                LanguageType eLnge )
1766 {
1767     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1768     if (sFormatString.isEmpty())                       // no empty string
1769     {
1770         return false;
1771     }
1772     if (eLnge == LANGUAGE_DONTKNOW)
1773     {
1774         eLnge = IniLnge;
1775     }
1776     ChangeIntl( eLnge );
1777     eLnge = ActLnge;
1778     bool bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1779 
1780     OUString aFormatStringUpper( pCharClass->uppercase( sFormatString ) );
1781     sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1782     sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1783     if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1784     {
1785         // Target format present
1786         GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1787         return true;
1788     }
1789 
1790     std::unique_ptr<SvNumberformat> pEntry;
1791     sal_Int32 nCheckPos = -1;
1792     OUString sTmpString;
1793 
1794     if ( bEnglish )
1795     {
1796         sTmpString = sFormatString;
1797         pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner.get(),
1798                                      pStringScanner.get(), nCheckPos, eLnge ));
1799     }
1800     else
1801     {
1802         nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1803         nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1804         bool bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1805 
1806         // Try English -> other or convert english to other
1807         LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1808         pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge, false, false);
1809         sTmpString = sFormatString;
1810         pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner.get(),
1811                                      pStringScanner.get(), nCheckPos, eFormatLang ));
1812         pFormatScanner->SetConvertMode( false );
1813         ChangeIntl( eLnge );
1814 
1815         if ( !bEnglishFormat )
1816         {
1817             if ( nCheckPos != 0 || xTransliteration->isEqual( sFormatString,
1818                                                               pEntry->GetFormatstring() ) )
1819             {
1820                 // other Format
1821                 // Force locale's keywords.
1822                 pFormatScanner->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy );
1823                 sTmpString = sFormatString;
1824                 pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner.get(),
1825                                              pStringScanner.get(), nCheckPos, eLnge ));
1826             }
1827             else
1828             {
1829                 // verify english
1830                 sal_Int32 nCheckPos2 = -1;
1831                 // try other --> english
1832                 eFormatLang = eLnge;
1833                 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US, false, false);
1834                 sTmpString = sFormatString;
1835                 std::unique_ptr<SvNumberformat> pEntry2(new SvNumberformat( sTmpString, pFormatScanner.get(),
1836                                                               pStringScanner.get(), nCheckPos2, eFormatLang ));
1837                 pFormatScanner->SetConvertMode( false );
1838                 ChangeIntl( eLnge );
1839                 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1840                                                                     pEntry2->GetFormatstring() ) )
1841                 {
1842                     // other Format
1843                     // Force locale's keywords.
1844                     pFormatScanner->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy );
1845                     sTmpString = sFormatString;
1846                     pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner.get(),
1847                                                  pStringScanner.get(), nCheckPos, eLnge ));
1848                 }
1849             }
1850         }
1851     }
1852 
1853     if (nCheckPos == 0)                                 // String ok
1854     {
1855         ImpGenerateCL( eLnge );     // create new standard formats if necessary
1856         pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1857         return true;
1858     }
1859     return false;
1860 }
1861 
GetPreviewString(const OUString & sFormatString,const OUString & sPreviewString,OUString & sOutString,Color ** ppColor,LanguageType eLnge)1862 bool SvNumberFormatter::GetPreviewString( const OUString& sFormatString,
1863                                           const OUString& sPreviewString,
1864                                           OUString& sOutString,
1865                                           Color** ppColor,
1866                                           LanguageType eLnge )
1867 {
1868     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1869     if (sFormatString.isEmpty())               // no empty string
1870     {
1871         return false;
1872     }
1873     sal_uInt32 nKey;
1874     if (eLnge == LANGUAGE_DONTKNOW)
1875     {
1876         eLnge = IniLnge;
1877     }
1878     ChangeIntl(eLnge);                          // switch if needed
1879     eLnge = ActLnge;
1880     sal_Int32 nCheckPos = -1;
1881     OUString sTmpString = sFormatString;
1882     std::unique_ptr<SvNumberformat> p_Entry(new SvNumberformat( sTmpString,
1883                                                   pFormatScanner.get(),
1884                                                   pStringScanner.get(),
1885                                                   nCheckPos,
1886                                                   eLnge));
1887     if (nCheckPos == 0)                          // String ok
1888     {
1889         // May have to create standard formats for this locale.
1890         sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1891         nKey = ImpIsEntry( p_Entry->GetFormatstring(), CLOffset, eLnge);
1892         if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND)       // already present
1893         {
1894             GetOutputString( sPreviewString, nKey, sOutString, ppColor);
1895         }
1896         else
1897         {
1898             // If the format is valid but not a text format and does not
1899             // include a text subformat, an empty string would result. Same as
1900             // in SvNumberFormatter::GetOutputString()
1901             if (p_Entry->IsTextFormat() || p_Entry->HasTextFormat())
1902             {
1903                 p_Entry->GetOutputString( sPreviewString, sOutString, ppColor);
1904             }
1905             else
1906             {
1907                 *ppColor = nullptr;
1908                 sOutString = sPreviewString;
1909             }
1910         }
1911         return true;
1912     }
1913     else
1914     {
1915         return false;
1916     }
1917 }
1918 
TestNewString(const OUString & sFormatString,LanguageType eLnge)1919 sal_uInt32 SvNumberFormatter::TestNewString(const OUString& sFormatString,
1920                                             LanguageType eLnge)
1921 {
1922     ::osl::MutexGuard aGuard( GetInstanceMutex() );
1923     if (sFormatString.isEmpty())                       // no empty string
1924     {
1925         return NUMBERFORMAT_ENTRY_NOT_FOUND;
1926     }
1927     if (eLnge == LANGUAGE_DONTKNOW)
1928     {
1929         eLnge = IniLnge;
1930     }
1931     ChangeIntl(eLnge);                                  // change locale if necessary
1932     eLnge = ActLnge;
1933     sal_uInt32 nRes;
1934     sal_Int32 nCheckPos = -1;
1935     OUString sTmpString = sFormatString;
1936     std::unique_ptr<SvNumberformat> pEntry(new SvNumberformat(sTmpString,
1937                                                 pFormatScanner.get(),
1938                                                 pStringScanner.get(),
1939                                                 nCheckPos,
1940                                                 eLnge));
1941     if (nCheckPos == 0)                                 // String ok
1942     {
1943         sal_uInt32 CLOffset = ImpGenerateCL(eLnge);     // create new standard formats if necessary
1944         nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1945                                                         // already present?
1946     }
1947     else
1948     {
1949         nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1950     }
1951     return nRes;
1952 }
1953 
ImpInsertFormat(const css::i18n::NumberFormatCode & rCode,sal_uInt32 nPos,bool bAfterChangingSystemCL,sal_Int16 nOrgIndex)1954 SvNumberformat* SvNumberFormatter::ImpInsertFormat( const css::i18n::NumberFormatCode& rCode,
1955                                                     sal_uInt32 nPos, bool bAfterChangingSystemCL,
1956                                                     sal_Int16 nOrgIndex )
1957 {
1958     SAL_WARN_IF( NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS <= rCode.Index && rCode.Index < NF_INDEX_TABLE_ENTRIES,
1959             "svl.numbers", "i18npool locale '" << maLanguageTag.getBcp47() <<
1960             "' uses reserved formatIndex value " << rCode.Index << ", next free: " << NF_INDEX_TABLE_ENTRIES <<
1961             "  Please see description in include/svl/zforlist.hxx at end of enum NfIndexTableOffset");
1962     assert( (rCode.Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS || NF_INDEX_TABLE_ENTRIES <= rCode.Index) &&
1963             "reserved formatIndex, see warning above");
1964 
1965     OUString aCodeStr( rCode.Code );
1966     if ( rCode.Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
1967             rCode.Usage == css::i18n::KNumberFormatUsage::CURRENCY &&
1968             rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1969     {   // strip surrounding [$...] on automatic currency
1970         if ( aCodeStr.indexOf( "[$" ) >= 0)
1971             aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr );
1972         else
1973         {
1974             if (LocaleDataWrapper::areChecksEnabled() &&
1975                     rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1976             {
1977                 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
1978                                 OUString::number( rCode.Index) +
1979                                 ":\n" +
1980                                 rCode.Code;
1981                 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1982             }
1983         }
1984     }
1985     sal_Int32 nCheckPos = 0;
1986     std::unique_ptr<SvNumberformat> pFormat(new SvNumberformat(aCodeStr,
1987                                                                pFormatScanner.get(),
1988                                                                pStringScanner.get(),
1989                                                                nCheckPos,
1990                                                                ActLnge));
1991     if (nCheckPos != 0)
1992     {
1993         if (LocaleDataWrapper::areChecksEnabled())
1994         {
1995             OUString aMsg = "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
1996                             OUString::number( rCode.Index ) +
1997                             "\n" +
1998                             rCode.Code;
1999             LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
2000         }
2001         return nullptr;
2002     }
2003     if ( rCode.Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
2004     {
2005         sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
2006         sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
2007         if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
2008         {
2009             // If bAfterChangingSystemCL there will definitely be some dups,
2010             // don't cry then.
2011             if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL)
2012             {
2013                 // Test for duplicate indexes in locale data.
2014                 switch ( nOrgIndex )
2015                 {
2016                 // These may be dups of integer versions for locales where
2017                 // currencies have no decimals like Italian Lira.
2018                 case NF_CURRENCY_1000DEC2 :         // NF_CURRENCY_1000INT
2019                 case NF_CURRENCY_1000DEC2_RED :     // NF_CURRENCY_1000INT_RED
2020                 case NF_CURRENCY_1000DEC2_DASHED :  // NF_CURRENCY_1000INT_RED
2021                     break;
2022                 default:
2023                 {
2024                     OUString aMsg = "SvNumberFormatter::ImpInsertFormat: dup format code, index "
2025                                   + OUString::number( rCode.Index )
2026                                   + "\n"
2027                                   + rCode.Code;
2028                     LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
2029                 }
2030                 }
2031             }
2032             return nullptr;
2033         }
2034         else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2035         {
2036             if (LocaleDataWrapper::areChecksEnabled())
2037             {
2038                 OUString aMsg =  "SvNumberFormatter::ImpInsertFormat: too many format codes, index "
2039                               + OUString::number( rCode.Index )
2040                               + "\n"
2041                               +  rCode.Code;
2042                 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
2043             }
2044             return nullptr;
2045         }
2046     }
2047     auto pFormat2 = pFormat.get();
2048     if ( !aFTable.emplace( nPos, std::move(pFormat) ).second )
2049     {
2050         if (LocaleDataWrapper::areChecksEnabled())
2051         {
2052             OUString aMsg = "ImpInsertFormat: can't insert number format key pos: "
2053                           + OUString::number( nPos )
2054                           + ", code index "
2055                           + OUString::number( rCode.Index )
2056                           + "\n"
2057                           + rCode.Code;
2058             LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
2059         }
2060         else
2061         {
2062             SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
2063         }
2064         return nullptr;
2065     }
2066     if ( rCode.Default )
2067         pFormat2->SetStandard();
2068     if ( !rCode.DefaultName.isEmpty() )
2069         pFormat2->SetComment( rCode.DefaultName );
2070     return pFormat2;
2071 }
2072 
GetFormatSpecialInfo(sal_uInt32 nFormat,bool & bThousand,bool & IsRed,sal_uInt16 & nPrecision,sal_uInt16 & nLeadingCnt)2073 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
2074                                              bool& bThousand,
2075                                              bool& IsRed,
2076                                              sal_uInt16& nPrecision,
2077                                              sal_uInt16& nLeadingCnt)
2078 
2079 {
2080     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2081     SvNumberformat* pFormat = GetFormatEntry( nFormat );
2082     if (pFormat)
2083         pFormat->GetFormatSpecialInfo(bThousand, IsRed,
2084                                       nPrecision, nLeadingCnt);
2085     else
2086     {
2087         bThousand = false;
2088         IsRed = false;
2089         nPrecision = pFormatScanner->GetStandardPrec();
2090         nLeadingCnt = 0;
2091     }
2092 }
2093 
GetFormatPrecision(sal_uInt32 nFormat) const2094 sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
2095 {
2096     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2097     const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2098     if ( pFormat )
2099         return pFormat->GetFormatPrecision();
2100     else
2101         return pFormatScanner->GetStandardPrec();
2102 }
2103 
GetFormatIntegerDigits(sal_uInt32 nFormat) const2104 sal_uInt16 SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat ) const
2105 {
2106     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2107     const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2108     if ( pFormat )
2109         return pFormat->GetFormatIntegerDigits();
2110     else
2111         return 1;
2112 }
2113 
GetFormatDecimalSep(sal_uInt32 nFormat) const2114 OUString SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
2115 {
2116     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2117     const SvNumberformat* pFormat = GetFormatEntry(nFormat);
2118     if (!pFormat)
2119     {
2120         return GetNumDecimalSep();
2121     }
2122     return GetLangDecimalSep( pFormat->GetLanguage());
2123 }
2124 
GetLangDecimalSep(LanguageType nLang) const2125 OUString SvNumberFormatter::GetLangDecimalSep( LanguageType nLang ) const
2126 {
2127     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2128     if (nLang == ActLnge)
2129     {
2130         return GetNumDecimalSep();
2131     }
2132     OUString aRet;
2133     LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
2134     if (nLang == eSaveLang)
2135     {
2136         aRet = xLocaleData->getNumDecimalSep();
2137     }
2138     else
2139     {
2140         LanguageTag aSaveLocale( xLocaleData->getLanguageTag() );
2141         const_cast<SvNumberFormatter*>(this)->xLocaleData.changeLocale( LanguageTag( nLang));
2142         aRet = xLocaleData->getNumDecimalSep();
2143         const_cast<SvNumberFormatter*>(this)->xLocaleData.changeLocale( aSaveLocale );
2144     }
2145     return aRet;
2146 }
2147 
2148 
GetFormatSpecialInfo(const OUString & rFormatString,bool & bThousand,bool & IsRed,sal_uInt16 & nPrecision,sal_uInt16 & nLeadingCnt,LanguageType eLnge)2149 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const OUString& rFormatString,
2150                                                     bool& bThousand, bool& IsRed, sal_uInt16& nPrecision,
2151                                                     sal_uInt16& nLeadingCnt, LanguageType eLnge )
2152 
2153 {
2154     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2155     if (eLnge == LANGUAGE_DONTKNOW)
2156     {
2157         eLnge = IniLnge;
2158     }
2159     ChangeIntl(eLnge);                                  // change locale if necessary
2160     eLnge = ActLnge;
2161     OUString aTmpStr( rFormatString );
2162     sal_Int32 nCheckPos = 0;
2163     std::unique_ptr<SvNumberformat> pFormat(new SvNumberformat( aTmpStr, pFormatScanner.get(),
2164                                                   pStringScanner.get(), nCheckPos, eLnge ));
2165     if ( nCheckPos == 0 )
2166     {
2167         pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nLeadingCnt );
2168     }
2169     else
2170     {
2171         bThousand = false;
2172         IsRed = false;
2173         nPrecision = pFormatScanner->GetStandardPrec();
2174         nLeadingCnt = 0;
2175     }
2176     return nCheckPos;
2177 }
2178 
ImpGetFormatCodeIndex(css::uno::Sequence<css::i18n::NumberFormatCode> & rSeq,const NfIndexTableOffset nTabOff)2179 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
2180             css::uno::Sequence< css::i18n::NumberFormatCode >& rSeq,
2181             const NfIndexTableOffset nTabOff )
2182 {
2183     auto pSeq = std::find_if(rSeq.begin(), rSeq.end(),
2184         [nTabOff](const css::i18n::NumberFormatCode& rCode) { return rCode.Index == nTabOff; });
2185     if (pSeq != rSeq.end())
2186         return static_cast<sal_Int32>(std::distance(rSeq.begin(), pSeq));
2187     if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
2188                 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
2189                 || nTabOff == NF_CURRENCY_1000INT_RED
2190                 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
2191     {   // currency entries with decimals might not exist, e.g. Italian Lira
2192         OUString aMsg = "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "
2193                       + OUString::number( nTabOff );
2194         LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(aMsg));
2195     }
2196     if ( rSeq.hasElements() )
2197     {
2198         // look for a preset default
2199         pSeq = std::find_if(rSeq.begin(), rSeq.end(),
2200             [](const css::i18n::NumberFormatCode& rCode) { return rCode.Default; });
2201         if (pSeq != rSeq.end())
2202             return static_cast<sal_Int32>(std::distance(rSeq.begin(), pSeq));
2203         // currencies are special, not all format codes must exist, but all
2204         // builtin number format key index positions must have a format assigned
2205         if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2206         {
2207             // look for a format with decimals
2208             pSeq = std::find_if(rSeq.begin(), rSeq.end(),
2209                 [](const css::i18n::NumberFormatCode& rCode) { return rCode.Index == NF_CURRENCY_1000DEC2; });
2210             if (pSeq != rSeq.end())
2211                 return static_cast<sal_Int32>(std::distance(rSeq.begin(), pSeq));
2212             // last resort: look for a format without decimals
2213             pSeq = std::find_if(rSeq.begin(), rSeq.end(),
2214                 [](const css::i18n::NumberFormatCode& rCode) { return rCode.Index == NF_CURRENCY_1000INT; });
2215             if (pSeq != rSeq.end())
2216                 return static_cast<sal_Int32>(std::distance(rSeq.begin(), pSeq));
2217         }
2218     }
2219     else
2220     {   // we need at least _some_ format
2221         rSeq.realloc(1);
2222         rSeq[0] = css::i18n::NumberFormatCode();
2223         rSeq[0].Code = "0" + GetNumDecimalSep() + "############";
2224     }
2225     return 0;
2226 }
2227 
2228 
ImpAdjustFormatCodeDefault(css::i18n::NumberFormatCode * pFormatArr,sal_Int32 nCnt)2229 void SvNumberFormatter::ImpAdjustFormatCodeDefault(
2230         css::i18n::NumberFormatCode * pFormatArr,
2231         sal_Int32 nCnt )
2232 {
2233     if ( !nCnt )
2234         return;
2235     if (LocaleDataWrapper::areChecksEnabled())
2236     {
2237         // check the locale data for correctness
2238         OStringBuffer aMsg;
2239         sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2240         nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2241         for ( nElem = 0; nElem < nCnt; nElem++ )
2242         {
2243             switch ( pFormatArr[nElem].Type )
2244             {
2245             case i18n::KNumberFormatType::SHORT :
2246                 nShort = nElem;
2247                 break;
2248             case i18n::KNumberFormatType::MEDIUM :
2249                 nMedium = nElem;
2250                 break;
2251             case i18n::KNumberFormatType::LONG :
2252                 nLong = nElem;
2253                 break;
2254             default:
2255                 aMsg.append("unknown type");
2256             }
2257             if ( pFormatArr[nElem].Default )
2258             {
2259                 switch ( pFormatArr[nElem].Type )
2260                 {
2261                 case i18n::KNumberFormatType::SHORT :
2262                     if ( nShortDef != -1 )
2263                         aMsg.append("dupe short type default");
2264                     nShortDef = nElem;
2265                     break;
2266                 case i18n::KNumberFormatType::MEDIUM :
2267                     if ( nMediumDef != -1 )
2268                         aMsg.append("dupe medium type default");
2269                     nMediumDef = nElem;
2270                     break;
2271                 case i18n::KNumberFormatType::LONG :
2272                     if ( nLongDef != -1 )
2273                         aMsg.append("dupe long type default");
2274                     nLongDef = nElem;
2275                     break;
2276                 }
2277             }
2278             if (!aMsg.isEmpty())
2279             {
2280                 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2281                 aMsg.append("\nXML locale data FormatElement formatindex: ");
2282                 aMsg.append(static_cast<sal_Int32>(pFormatArr[nElem].Index));
2283                 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(),
2284                     RTL_TEXTENCODING_ASCII_US));
2285                 LocaleDataWrapper::outputCheckMessage(xLocaleData->appendLocaleInfo(aUMsg));
2286             }
2287         }
2288         if ( nShort != -1 && nShortDef == -1 )
2289             aMsg.append("no short type default  ");
2290         if ( nMedium != -1 && nMediumDef == -1 )
2291             aMsg.append("no medium type default  ");
2292         if ( nLong != -1 && nLongDef == -1 )
2293             aMsg.append("no long type default  ");
2294         if (!aMsg.isEmpty())
2295         {
2296             aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2297             aMsg.append("\nXML locale data FormatElement group of: ");
2298             OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
2299             LocaleDataWrapper::outputCheckMessage(
2300                 xLocaleData->appendLocaleInfo(aUMsg + pFormatArr[0].NameID));
2301         }
2302     }
2303     // find the default (medium preferred, then long) and reset all other defaults
2304     sal_Int32 nElem, nDef, nMedium;
2305     nDef = nMedium = -1;
2306     for ( nElem = 0; nElem < nCnt; nElem++ )
2307     {
2308         if ( pFormatArr[nElem].Default )
2309         {
2310             switch ( pFormatArr[nElem].Type )
2311             {
2312             case i18n::KNumberFormatType::MEDIUM :
2313                 nDef = nMedium = nElem;
2314                 break;
2315             case i18n::KNumberFormatType::LONG :
2316                 if ( nMedium == -1 )
2317                     nDef = nElem;
2318                 [[fallthrough]];
2319             default:
2320                 if ( nDef == -1 )
2321                     nDef = nElem;
2322                 pFormatArr[nElem].Default = false;
2323             }
2324         }
2325     }
2326     if ( nDef == -1 )
2327         nDef = 0;
2328     pFormatArr[nDef].Default = true;
2329 }
2330 
GetFormatEntry(sal_uInt32 nKey)2331 SvNumberformat* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey )
2332 {
2333     auto it = aFTable.find( nKey);
2334     if (it != aFTable.end())
2335         return it->second.get();
2336     return nullptr;
2337 }
2338 
GetFormatEntry(sal_uInt32 nKey) const2339 const SvNumberformat* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey ) const
2340 {
2341     return GetEntry( nKey);
2342 }
2343 
GetEntry(sal_uInt32 nKey) const2344 const SvNumberformat* SvNumberFormatter::GetEntry( sal_uInt32 nKey ) const
2345 {
2346     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2347     auto it = aFTable.find( nKey);
2348     if (it != aFTable.end())
2349         return it->second.get();
2350     return nullptr;
2351 }
2352 
GetSubstitutedEntry(sal_uInt32 nKey,sal_uInt32 & o_rNewKey) const2353 const SvNumberformat* SvNumberFormatter::GetSubstitutedEntry( sal_uInt32 nKey, sal_uInt32 & o_rNewKey ) const
2354 {
2355     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2356     // A tad ugly, but GetStandardFormat() and GetFormatIndex() in
2357     // ImpSubstituteEntry() may have to add the LANGUAGE_SYSTEM formats if not
2358     // already present (which in practice most times they are).
2359     SvNumberFormatter* pThis = const_cast<SvNumberFormatter*>(this);
2360     return pThis->ImpSubstituteEntry( pThis->GetFormatEntry( nKey), &o_rNewKey);
2361 }
2362 
ImpSubstituteEntry(SvNumberformat * pFormat,sal_uInt32 * o_pRealKey)2363 SvNumberformat* SvNumberFormatter::ImpSubstituteEntry( SvNumberformat* pFormat, sal_uInt32 * o_pRealKey )
2364 {
2365     if (!pFormat || !pFormat->IsSubstituted())
2366         return pFormat;
2367 
2368     // XXX NOTE: substitution can not be done in GetFormatEntry() as otherwise
2369     // to be substituted formats would "vanish", i.e. from the number formatter
2370     // dialog or when exporting to Excel.
2371 
2372     sal_uInt32 nKey;
2373     if (pFormat->IsSystemTimeFormat())
2374         /* TODO: should we have NF_TIME_SYSTEM for consistency? */
2375         nKey = GetStandardFormat( SvNumFormatType::TIME, LANGUAGE_SYSTEM);
2376     else if (pFormat->IsSystemLongDateFormat())
2377         /* TODO: either that above, or have a long option for GetStandardFormat() */
2378         nKey = GetFormatIndex( NF_DATE_SYSTEM_LONG, LANGUAGE_SYSTEM);
2379     else
2380         return pFormat;
2381 
2382     if (o_pRealKey)
2383         *o_pRealKey = nKey;
2384     auto it = aFTable.find( nKey);
2385     return it == aFTable.end() ? nullptr : it->second.get();
2386 }
2387 
ImpGenerateFormats(sal_uInt32 CLOffset,bool bNoAdditionalFormats)2388 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditionalFormats )
2389 {
2390     bool bOldConvertMode = pFormatScanner->GetConvertMode();
2391     if (bOldConvertMode)
2392     {
2393         pFormatScanner->SetConvertMode(false);      // switch off for this function
2394     }
2395 
2396     css::lang::Locale aLocale = GetLanguageTag().getLocale();
2397     css::uno::Reference< css::i18n::XNumberFormatCode > xNFC = i18n::NumberFormatMapper::create( m_xContext );
2398     sal_Int32 nIdx;
2399     bool bDefault;
2400 
2401     // Number
2402     uno::Sequence< i18n::NumberFormatCode > aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER, aLocale );
2403     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2404 
2405     // General
2406     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2407     SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2408             CLOffset + ZF_STANDARD /* NF_NUMBER_STANDARD */ );
2409     if (pStdFormat)
2410     {
2411         // This is _the_ standard format.
2412         if (LocaleDataWrapper::areChecksEnabled() && pStdFormat->GetType() != SvNumFormatType::NUMBER)
2413         {
2414             LocaleDataWrapper::outputCheckMessage( xLocaleData->
2415                                                    appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2416         }
2417         pStdFormat->SetType( SvNumFormatType::NUMBER );
2418         pStdFormat->SetStandard();
2419         pStdFormat->SetLastInsertKey( SV_MAX_COUNT_STANDARD_FORMATS, SvNumberformat::FormatterPrivateAccess() );
2420     }
2421     else
2422     {
2423         if (LocaleDataWrapper::areChecksEnabled())
2424         {
2425             LocaleDataWrapper::outputCheckMessage( xLocaleData->
2426                                                    appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2427         }
2428     }
2429 
2430     {
2431         // Boolean
2432         OUString aFormatCode = pFormatScanner->GetBooleanString();
2433         sal_Int32 nCheckPos = 0;
2434 
2435         std::unique_ptr<SvNumberformat> pNewFormat(new SvNumberformat( aFormatCode, pFormatScanner.get(),
2436                                                                        pStringScanner.get(), nCheckPos, ActLnge ));
2437         pNewFormat->SetType(SvNumFormatType::LOGICAL);
2438         pNewFormat->SetStandard();
2439         if ( !aFTable.emplace(CLOffset + ZF_STANDARD_LOGICAL /* NF_BOOLEAN */,
2440                             std::move(pNewFormat)).second )
2441         {
2442             SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2443         }
2444 
2445         // Text
2446         aFormatCode = "@";
2447         pNewFormat.reset(new SvNumberformat( aFormatCode, pFormatScanner.get(),
2448                                              pStringScanner.get(), nCheckPos, ActLnge ));
2449         pNewFormat->SetType(SvNumFormatType::TEXT);
2450         pNewFormat->SetStandard();
2451         if ( !aFTable.emplace( CLOffset + ZF_STANDARD_TEXT /* NF_TEXT */,
2452                                std::move(pNewFormat)).second )
2453         {
2454             SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2455         }
2456     }
2457 
2458     // 0
2459     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2460     ImpInsertFormat( aFormatSeq[nIdx],
2461                      CLOffset + ZF_STANDARD+1 /* NF_NUMBER_INT */ );
2462 
2463     // 0.00
2464     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2465     ImpInsertFormat( aFormatSeq[nIdx],
2466                      CLOffset + ZF_STANDARD+2 /* NF_NUMBER_DEC2 */ );
2467 
2468     // #,##0
2469     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2470     ImpInsertFormat( aFormatSeq[nIdx],
2471                      CLOffset + ZF_STANDARD+3 /* NF_NUMBER_1000INT */ );
2472 
2473     // #,##0.00
2474     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2475     ImpInsertFormat( aFormatSeq[nIdx],
2476                      CLOffset + ZF_STANDARD+4 /* NF_NUMBER_1000DEC2 */ );
2477 
2478     // #.##0,00 System country/language dependent
2479     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2480     ImpInsertFormat( aFormatSeq[nIdx],
2481                      CLOffset + ZF_STANDARD+5 /* NF_NUMBER_SYSTEM */ );
2482 
2483 
2484     // Percent number
2485     aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER, aLocale );
2486     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2487 
2488     // 0%
2489     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2490     ImpInsertFormat( aFormatSeq[nIdx],
2491                      CLOffset + ZF_STANDARD_PERCENT /* NF_PERCENT_INT */ );
2492 
2493     // 0.00%
2494     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2495     ImpInsertFormat( aFormatSeq[nIdx],
2496                      CLOffset + ZF_STANDARD_PERCENT+1 /* NF_PERCENT_DEC2 */ );
2497 
2498 
2499     // Currency. NO default standard option! Default is determined of locale
2500     // data default currency and format is generated if needed.
2501     aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY, aLocale );
2502     if (LocaleDataWrapper::areChecksEnabled())
2503     {
2504         // though no default desired here, test for correctness of locale data
2505         ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2506     }
2507 
2508     // #,##0
2509     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2510     bDefault = aFormatSeq[nIdx].Default;
2511     aFormatSeq[nIdx].Default = false;
2512     ImpInsertFormat( aFormatSeq[nIdx],
2513                      CLOffset + ZF_STANDARD_CURRENCY /* NF_CURRENCY_1000INT */ );
2514     aFormatSeq[nIdx].Default = bDefault;
2515 
2516     // #,##0.00
2517     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2518     bDefault = aFormatSeq[nIdx].Default;
2519     aFormatSeq[nIdx].Default = false;
2520     ImpInsertFormat( aFormatSeq[nIdx],
2521                      CLOffset + ZF_STANDARD_CURRENCY+1 /* NF_CURRENCY_1000DEC2 */ );
2522     aFormatSeq[nIdx].Default = bDefault;
2523 
2524     // #,##0 negative red
2525     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2526     bDefault = aFormatSeq[nIdx].Default;
2527     aFormatSeq[nIdx].Default = false;
2528     ImpInsertFormat( aFormatSeq[nIdx],
2529                      CLOffset + ZF_STANDARD_CURRENCY+2 /* NF_CURRENCY_1000INT_RED */ );
2530     aFormatSeq[nIdx].Default = bDefault;
2531 
2532     // #,##0.00 negative red
2533     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2534     bDefault = aFormatSeq[nIdx].Default;
2535     aFormatSeq[nIdx].Default = false;
2536     ImpInsertFormat( aFormatSeq[nIdx],
2537                      CLOffset + ZF_STANDARD_CURRENCY+3 /* NF_CURRENCY_1000DEC2_RED */ );
2538     aFormatSeq[nIdx].Default = bDefault;
2539 
2540     // #,##0.00 USD
2541     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2542     bDefault = aFormatSeq[nIdx].Default;
2543     aFormatSeq[nIdx].Default = false;
2544     ImpInsertFormat( aFormatSeq[nIdx],
2545                      CLOffset + ZF_STANDARD_CURRENCY+4 /* NF_CURRENCY_1000DEC2_CCC */ );
2546     aFormatSeq[nIdx].Default = bDefault;
2547 
2548     // #.##0,--
2549     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2550     bDefault = aFormatSeq[nIdx].Default;
2551     aFormatSeq[nIdx].Default = false;
2552     ImpInsertFormat( aFormatSeq[nIdx],
2553                      CLOffset + ZF_STANDARD_CURRENCY+5 /* NF_CURRENCY_1000DEC2_DASHED */ );
2554     aFormatSeq[nIdx].Default = bDefault;
2555 
2556 
2557     // Date
2558     aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::DATE, aLocale );
2559     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2560 
2561     // DD.MM.YY   System
2562     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2563     ImpInsertFormat( aFormatSeq[nIdx],
2564                      CLOffset + ZF_STANDARD_DATE /* NF_DATE_SYSTEM_SHORT */ );
2565 
2566     // NN DD.MMM YY
2567     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2568     ImpInsertFormat( aFormatSeq[nIdx],
2569                      CLOffset + ZF_STANDARD_DATE+1 /* NF_DATE_DEF_NNDDMMMYY */ );
2570 
2571     // DD.MM.YY   def/System
2572     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2573     ImpInsertFormat( aFormatSeq[nIdx],
2574                      CLOffset + ZF_STANDARD_DATE+2 /* NF_DATE_SYS_MMYY */ );
2575 
2576     // DD MMM
2577     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2578     ImpInsertFormat( aFormatSeq[nIdx],
2579                      CLOffset + ZF_STANDARD_DATE+3 /* NF_DATE_SYS_DDMMM */ );
2580 
2581     // MMMM
2582     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2583     ImpInsertFormat( aFormatSeq[nIdx],
2584                      CLOffset + ZF_STANDARD_DATE+4 /* NF_DATE_MMMM */ );
2585 
2586     // QQ YY
2587     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2588     ImpInsertFormat( aFormatSeq[nIdx],
2589                      CLOffset + ZF_STANDARD_DATE+5 /* NF_DATE_QQJJ */ );
2590 
2591     // DD.MM.YYYY   was DD.MM.[YY]YY
2592     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2593     ImpInsertFormat( aFormatSeq[nIdx],
2594                      CLOffset + ZF_STANDARD_DATE+6 /* NF_DATE_SYS_DDMMYYYY */ );
2595 
2596     // DD.MM.YY   def/System
2597     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2598     ImpInsertFormat( aFormatSeq[nIdx],
2599                      CLOffset + ZF_STANDARD_DATE+7 /* NF_DATE_SYS_DDMMYY */ );
2600 
2601     // NNN, D. MMMM YYYY   System
2602     // Long day of week: "NNNN" instead of "NNN," because of compatibility
2603     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2604     ImpInsertFormat( aFormatSeq[nIdx],
2605                      CLOffset + ZF_STANDARD_DATE+8 /* NF_DATE_SYSTEM_LONG */ );
2606 
2607     // Hard coded but system (regional settings) delimiters dependent long date formats
2608 
2609     // D. MMM YY   def/System
2610     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2611     ImpInsertFormat( aFormatSeq[nIdx],
2612                      CLOffset + ZF_STANDARD_DATE+9 /* NF_DATE_SYS_DMMMYY */ );
2613 
2614     // D. MMM YYYY   def/System
2615     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2616     ImpInsertFormat( aFormatSeq[nIdx],
2617                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY /* NF_DATE_SYS_DMMMYYYY */ );
2618 
2619     // D. MMMM YYYY   def/System
2620     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2621     ImpInsertFormat( aFormatSeq[nIdx],
2622                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY /* NF_DATE_SYS_DMMMMYYYY */ );
2623 
2624     // NN, D. MMM YY   def/System
2625     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2626     ImpInsertFormat( aFormatSeq[nIdx],
2627                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY /* NF_DATE_SYS_NNDMMMYY */ );
2628 
2629     // NN, D. MMMM YYYY   def/System
2630     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2631     ImpInsertFormat( aFormatSeq[nIdx],
2632                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY /*  NF_DATE_SYS_NNDMMMMYYYY */ );
2633 
2634     // NNN, D. MMMM YYYY   def/System
2635     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2636     ImpInsertFormat( aFormatSeq[nIdx],
2637                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY /* NF_DATE_SYS_NNNNDMMMMYYYY */ );
2638 
2639     // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2640 
2641     // D. MMM. YYYY   DIN/EN
2642     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2643     ImpInsertFormat( aFormatSeq[nIdx],
2644                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY /* NF_DATE_DIN_DMMMYYYY */ );
2645 
2646     // D. MMMM YYYY   DIN/EN
2647     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2648     ImpInsertFormat( aFormatSeq[nIdx],
2649                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY /* NF_DATE_DIN_DMMMMYYYY */ );
2650 
2651     // MM-DD   DIN/EN
2652     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2653     ImpInsertFormat( aFormatSeq[nIdx],
2654                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD /* NF_DATE_DIN_MMDD */ );
2655 
2656     // YY-MM-DD   DIN/EN
2657     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2658     ImpInsertFormat( aFormatSeq[nIdx],
2659                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD /* NF_DATE_DIN_YYMMDD */ );
2660 
2661     // YYYY-MM-DD   DIN/EN/ISO
2662     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2663     ImpInsertFormat( aFormatSeq[nIdx],
2664                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD /* NF_DATE_DIN_YYYYMMDD */ );
2665 
2666 
2667     // Time
2668     aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::TIME, aLocale );
2669     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2670 
2671     // HH:MM
2672     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2673     ImpInsertFormat( aFormatSeq[nIdx],
2674                      CLOffset + ZF_STANDARD_TIME /* NF_TIME_HHMM */ );
2675 
2676     // HH:MM:SS
2677     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2678     ImpInsertFormat( aFormatSeq[nIdx],
2679                      CLOffset + ZF_STANDARD_TIME+1 /* NF_TIME_HHMMSS */ );
2680 
2681     // HH:MM AM/PM
2682     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2683     ImpInsertFormat( aFormatSeq[nIdx],
2684                      CLOffset + ZF_STANDARD_TIME+2 /* NF_TIME_HHMMAMPM */ );
2685 
2686     // HH:MM:SS AM/PM
2687     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2688     ImpInsertFormat( aFormatSeq[nIdx],
2689                      CLOffset + ZF_STANDARD_TIME+3 /* NF_TIME_HHMMSSAMPM */ );
2690 
2691     // [HH]:MM:SS
2692     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2693     ImpInsertFormat( aFormatSeq[nIdx],
2694                      CLOffset + ZF_STANDARD_TIME+4 /* NF_TIME_HH_MMSS */ );
2695 
2696     // MM:SS,00
2697     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2698     ImpInsertFormat( aFormatSeq[nIdx],
2699                      CLOffset + ZF_STANDARD_TIME+5 /* NF_TIME_MMSS00 */ );
2700 
2701     // [HH]:MM:SS,00
2702     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2703     ImpInsertFormat( aFormatSeq[nIdx],
2704                      CLOffset + ZF_STANDARD_TIME+6 /* NF_TIME_HH_MMSS00 */ );
2705 
2706 
2707     // DateTime
2708     aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME, aLocale );
2709     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2710 
2711     // DD.MM.YY HH:MM   System
2712     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2713     ImpInsertFormat( aFormatSeq[nIdx],
2714                      CLOffset + ZF_STANDARD_DATETIME /* NF_DATETIME_SYSTEM_SHORT_HHMM */ );
2715 
2716     // DD.MM.YYYY HH:MM:SS   System
2717     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2718     ImpInsertFormat( aFormatSeq[nIdx],
2719                      CLOffset + ZF_STANDARD_DATETIME+1 /* NF_DATETIME_SYS_DDMMYYYY_HHMMSS */ );
2720 
2721     const NfKeywordTable & rKeyword = pFormatScanner->GetKeywords();
2722     i18n::NumberFormatCode aSingleFormatCode;
2723     aSingleFormatCode.Usage = i18n::KNumberFormatUsage::DATE_TIME;
2724 
2725     // YYYY-MM-DD HH:MM:SS   ISO (with blank instead of 'T')
2726     aSingleFormatCode.Code =
2727         rKeyword[NF_KEY_YYYY] + "-" +
2728         rKeyword[NF_KEY_MM] + "-" +
2729         rKeyword[NF_KEY_DD] + " " +
2730         rKeyword[NF_KEY_HH] + ":" +
2731         rKeyword[NF_KEY_MMI] + ":" +
2732         rKeyword[NF_KEY_SS];
2733     ImpInsertFormat( aSingleFormatCode,
2734                      CLOffset + ZF_STANDARD_DATETIME+2 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS */ );
2735 
2736     // YYYY-MM-DD"T"HH:MM:SS   ISO
2737     aSingleFormatCode.Code =
2738         rKeyword[NF_KEY_YYYY] + "-" +
2739         rKeyword[NF_KEY_MM] + "-" +
2740         rKeyword[NF_KEY_DD] + "\"T\"" +
2741         rKeyword[NF_KEY_HH] + ":" +
2742         rKeyword[NF_KEY_MMI] + ":" +
2743         rKeyword[NF_KEY_SS];
2744     SvNumberformat* pFormat = ImpInsertFormat( aSingleFormatCode,
2745                      CLOffset + ZF_STANDARD_DATETIME+3 /* NF_DATETIME_ISO_YYYYMMDDTHHMMSS */ );
2746     assert(pFormat);
2747     pFormat->SetComment("ISO 8601");    // not to be localized
2748 
2749 
2750     // Scientific number
2751     aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER, aLocale );
2752     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2753 
2754     // 0.00E+000
2755     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2756     ImpInsertFormat( aFormatSeq[nIdx],
2757                      CLOffset + ZF_STANDARD_SCIENTIFIC /* NF_SCIENTIFIC_000E000 */ );
2758 
2759     // 0.00E+00
2760     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2761     ImpInsertFormat( aFormatSeq[nIdx],
2762                      CLOffset + ZF_STANDARD_SCIENTIFIC+1 /* NF_SCIENTIFIC_000E00 */ );
2763 
2764 
2765     // Fraction number (no default option)
2766     aSingleFormatCode.Usage = i18n::KNumberFormatUsage::FRACTION_NUMBER;
2767 
2768      // # ?/?
2769     aSingleFormatCode.Code = "# ?/?";
2770     ImpInsertFormat( aSingleFormatCode,
2771                      CLOffset + ZF_STANDARD_FRACTION /* NF_FRACTION_1D */ );
2772 
2773     // # ??/??
2774     //! "??/" would be interpreted by the compiler as a trigraph for '\'
2775     aSingleFormatCode.Code = "# ?\?/?\?";
2776     ImpInsertFormat( aSingleFormatCode,
2777                      CLOffset + ZF_STANDARD_FRACTION+1 /* NF_FRACTION_2D */ );
2778 
2779     // # ???/???
2780     //! "??/" would be interpreted by the compiler as a trigraph for '\'
2781     aSingleFormatCode.Code = "# ?\?\?/?\?\?";
2782     ImpInsertFormat( aSingleFormatCode,
2783                      CLOffset + ZF_STANDARD_FRACTION+2 /* NF_FRACTION_3D */ );
2784 
2785     // # ?/2
2786     aSingleFormatCode.Code = "# ?/2";
2787     ImpInsertFormat( aSingleFormatCode,
2788                      CLOffset + ZF_STANDARD_FRACTION+3 /* NF_FRACTION_2 */ );
2789 
2790     // # ?/4
2791     aSingleFormatCode.Code = "# ?/4";
2792     ImpInsertFormat( aSingleFormatCode,
2793                      CLOffset + ZF_STANDARD_FRACTION+4 /* NF_FRACTION_4 */ );
2794 
2795     // # ?/8
2796     aSingleFormatCode.Code = "# ?/8";
2797     ImpInsertFormat( aSingleFormatCode,
2798                      CLOffset + ZF_STANDARD_FRACTION+5 /* NF_FRACTION_8 */ );
2799 
2800     // # ??/16
2801     aSingleFormatCode.Code = "# ?\?/16";
2802     ImpInsertFormat( aSingleFormatCode,
2803                      CLOffset + ZF_STANDARD_FRACTION+6 /* NF_FRACTION_16 */ );
2804 
2805     // # ??/10
2806     aSingleFormatCode.Code = "# ?\?/10";
2807     ImpInsertFormat( aSingleFormatCode,
2808                      CLOffset + ZF_STANDARD_FRACTION+7 /* NF_FRACTION_10 */ );
2809 
2810     // # ??/100
2811     aSingleFormatCode.Code = "# ?\?/100";
2812     ImpInsertFormat( aSingleFormatCode,
2813                      CLOffset + ZF_STANDARD_FRACTION+8 /* NF_FRACTION_100 */ );
2814 
2815 
2816     // Week of year
2817     aSingleFormatCode.Code = rKeyword[NF_KEY_WW];
2818     ImpInsertFormat( aSingleFormatCode,
2819                      CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_WW /* NF_DATE_WW */ );
2820 
2821     // Now all additional format codes provided by I18N, but only if not
2822     // changing SystemCL, then they are appended last after user defined.
2823     if ( !bNoAdditionalFormats )
2824     {
2825         ImpGenerateAdditionalFormats( CLOffset, xNFC, false );
2826     }
2827     if (bOldConvertMode)
2828     {
2829         pFormatScanner->SetConvertMode(true);
2830     }
2831 }
2832 
2833 
ImpGenerateAdditionalFormats(sal_uInt32 CLOffset,css::uno::Reference<css::i18n::XNumberFormatCode> const & rNumberFormatCode,bool bAfterChangingSystemCL)2834 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2835             css::uno::Reference< css::i18n::XNumberFormatCode > const & rNumberFormatCode,
2836             bool bAfterChangingSystemCL )
2837 {
2838     SvNumberformat* pStdFormat = GetFormatEntry( CLOffset + ZF_STANDARD );
2839     if ( !pStdFormat )
2840     {
2841         SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2842         return ;
2843     }
2844     sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
2845     css::lang::Locale aLocale = GetLanguageTag().getLocale();
2846 
2847     // All currencies, this time with [$...] which was stripped in
2848     // ImpGenerateFormats for old "automatic" currency formats.
2849     uno::Sequence< i18n::NumberFormatCode > aFormatSeq = rNumberFormatCode->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY, aLocale );
2850     sal_Int32 nCodes = aFormatSeq.getLength();
2851     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2852     for ( i18n::NumberFormatCode& rFormat : aFormatSeq )
2853     {
2854         if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2855         {
2856             SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2857             break;  // for
2858         }
2859         if ( rFormat.Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
2860                 rFormat.Index != NF_CURRENCY_1000DEC2_CCC )
2861         {   // Insert only if not already inserted, but internal index must be
2862             // above so ImpInsertFormat can distinguish it.
2863             sal_Int16 nOrgIndex = rFormat.Index;
2864             rFormat.Index = sal::static_int_cast< sal_Int16 >(
2865                 rFormat.Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2866             //! no default on currency
2867             bool bDefault = rFormat.Default;
2868             rFormat.Default = false;
2869             if ( SvNumberformat* pNewFormat = ImpInsertFormat( rFormat, nPos+1,
2870                         bAfterChangingSystemCL, nOrgIndex ) )
2871             {
2872                 pNewFormat->SetAdditionalBuiltin();
2873                 nPos++;
2874             }
2875             rFormat.Index = nOrgIndex;
2876             rFormat.Default = bDefault;
2877         }
2878     }
2879 
2880     // All additional format codes provided by I18N that are not old standard
2881     // index. Additional formats may define defaults, currently there is no
2882     // check if more than one default of a usage/type combination is provided,
2883     // like it is done for usage groups with ImpAdjustFormatCodeDefault().
2884     // There is no harm though, on first invocation ImpGetDefaultFormat() will
2885     // use the first default encountered.
2886     aFormatSeq = rNumberFormatCode->getAllFormatCodes( aLocale );
2887     for ( const auto& rFormat : std::as_const(aFormatSeq) )
2888     {
2889         if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2890         {
2891             SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2892             break;  // for
2893         }
2894         if ( rFormat.Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
2895         {
2896             if ( SvNumberformat* pNewFormat = ImpInsertFormat( rFormat, nPos+1,
2897                         bAfterChangingSystemCL ) )
2898             {
2899                 pNewFormat->SetAdditionalBuiltin();
2900                 nPos++;
2901             }
2902         }
2903     }
2904 
2905     pStdFormat->SetLastInsertKey( static_cast<sal_uInt16>(nPos - CLOffset), SvNumberformat::FormatterPrivateAccess() );
2906 }
2907 
2908 
ImpPosToken(const OUStringBuffer & sFormat,sal_Unicode token,sal_Int32 nStartPos) const2909 sal_Int32 SvNumberFormatter::ImpPosToken ( const OUStringBuffer & sFormat, sal_Unicode token, sal_Int32 nStartPos /* = 0*/ ) const
2910 {
2911     sal_Int32 nLength = sFormat.getLength();
2912     for ( sal_Int32 i=nStartPos; i<nLength && i>=0 ; i++ )
2913     {
2914         switch(sFormat[i])
2915         {
2916             case '\"' : // skip text
2917                 i = sFormat.indexOf('\"',i+1);
2918                 break;
2919             case '['  : // skip condition
2920                 i = sFormat.indexOf(']',i+1);
2921                 break;
2922             case '\\' : // skip escaped character
2923                 i++;
2924                 break;
2925             case ';'  :
2926                 if (token == ';')
2927                     return i;
2928                 break;
2929             case 'e'  :
2930             case 'E'  :
2931                 if (token == 'E')
2932                    return i; // if 'E' is outside "" and [] it must be the 'E' exponent
2933                 break;
2934             default : break;
2935         }
2936         if ( i<0 )
2937             i--;
2938     }
2939     return -2;
2940 }
2941 
GenerateFormat(sal_uInt32 nIndex,LanguageType eLnge,bool bThousand,bool IsRed,sal_uInt16 nPrecision,sal_uInt16 nLeadingZeros)2942 OUString SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex,
2943                                            LanguageType eLnge,
2944                                            bool bThousand,
2945                                            bool IsRed,
2946                                            sal_uInt16 nPrecision,
2947                                            sal_uInt16 nLeadingZeros)
2948 {
2949     ::osl::MutexGuard aGuard( GetInstanceMutex() );
2950     if (eLnge == LANGUAGE_DONTKNOW)
2951     {
2952         eLnge = IniLnge;
2953     }
2954 
2955     const SvNumberformat* pFormat = GetFormatEntry( nIndex );
2956     const SvNumFormatType eType = (pFormat ? pFormat->GetMaskedType() : SvNumFormatType::UNDEFINED);
2957 
2958     ImpGenerateCL(eLnge);           // create new standard formats if necessary
2959 
2960     utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2961     // always group of 3 for Engineering notation
2962     const sal_Int32 nDigitsInFirstGroup = ( bThousand && (eType == SvNumFormatType::SCIENTIFIC) ) ? 3 : aGrouping.get();
2963     const OUString& rThSep = GetNumThousandSep();
2964 
2965     OUStringBuffer sString;
2966     using comphelper::string::padToLength;
2967 
2968     if (nLeadingZeros == 0)
2969     {
2970         if (!bThousand)
2971             sString.append('#');
2972         else
2973         {
2974             if (eType == SvNumFormatType::SCIENTIFIC)
2975             {  // for scientific, bThousand is used for Engineering notation
2976                 sString.append("###");
2977             }
2978             else
2979             {
2980                 sString.append('#');
2981                 sString.append(rThSep);
2982                 padToLength(sString, sString.getLength() + nDigitsInFirstGroup, '#');
2983             }
2984         }
2985     }
2986     else
2987     {
2988         for (sal_uInt16 i = 0; i < nLeadingZeros; i++)
2989         {
2990             if (bThousand && i > 0 && i == aGrouping.getPos())
2991             {
2992                 sString.insert(0, rThSep);
2993                 aGrouping.advance();
2994             }
2995             sString.insert(0, '0');
2996         }
2997         if ( bThousand )
2998         {
2999             sal_Int32 nDigits = (eType == SvNumFormatType::SCIENTIFIC) ?  3*((nLeadingZeros-1)/3 + 1) : nDigitsInFirstGroup + 1;
3000             for (sal_Int32 i = nLeadingZeros; i < nDigits; i++)
3001             {
3002                 if ( i % nDigitsInFirstGroup == 0 )
3003                     sString.insert(0, rThSep);
3004                 sString.insert(0, '#');
3005             }
3006         }
3007     }
3008     if (nPrecision > 0 && eType != SvNumFormatType::FRACTION )
3009     {
3010         sString.append(GetNumDecimalSep());
3011         padToLength(sString, sString.getLength() + nPrecision, '0');
3012     }
3013     if (eType == SvNumFormatType::PERCENT)
3014     {
3015         sString.append('%');
3016     }
3017     else if (eType == SvNumFormatType::SCIENTIFIC)
3018     {
3019       OUStringBuffer sOldFormatString = pFormat->GetFormatstring();
3020       sal_Int32 nIndexE = ImpPosToken( sOldFormatString, 'E' );
3021       if (nIndexE > -1)
3022       {
3023         sal_Int32 nIndexSep = ImpPosToken( sOldFormatString, ';', nIndexE );
3024         if (nIndexSep > nIndexE)
3025             sString.append( sOldFormatString.copy(nIndexE, nIndexSep - nIndexE) );
3026         else
3027             sString.append( sOldFormatString.copy(nIndexE) );
3028       }
3029     }
3030     else if (eType == SvNumFormatType::CURRENCY)
3031     {
3032         OUStringBuffer sNegStr(sString);
3033         OUString aCurr;
3034         const NfCurrencyEntry* pEntry;
3035         bool bBank;
3036         if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
3037         {
3038             if ( pEntry )
3039             {
3040                 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3041                     xLocaleData->getCurrPositiveFormat(),
3042                     pEntry->GetPositiveFormat(), bBank );
3043                 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3044                     xLocaleData->getCurrNegativeFormat(),
3045                     pEntry->GetNegativeFormat(), bBank );
3046                 pEntry->CompletePositiveFormatString( sString, bBank, nPosiForm );
3047                 pEntry->CompleteNegativeFormatString( sNegStr, bBank, nNegaForm );
3048             }
3049             else
3050             {   // assume currency abbreviation (AKA banking symbol), not symbol
3051                 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3052                     xLocaleData->getCurrPositiveFormat(),
3053                     xLocaleData->getCurrPositiveFormat(), true );
3054                 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3055                     xLocaleData->getCurrNegativeFormat(),
3056                     xLocaleData->getCurrNegativeFormat(), true );
3057                 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr, nPosiForm );
3058                 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr, nNegaForm );
3059             }
3060         }
3061         else
3062         {   // "automatic" old style
3063             OUString aSymbol, aAbbrev;
3064             GetCompatibilityCurrency( aSymbol, aAbbrev );
3065             NfCurrencyEntry::CompletePositiveFormatString( sString,
3066                                 aSymbol, xLocaleData->getCurrPositiveFormat() );
3067             NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
3068                                 aSymbol, xLocaleData->getCurrNegativeFormat() );
3069         }
3070         if (IsRed)
3071         {
3072             sString.append(';');
3073             sString.append('[');
3074             sString.append(pFormatScanner->GetRedString());
3075             sString.append(']');
3076         }
3077         else
3078         {
3079             sString.append(';');
3080         }
3081         sString.append(sNegStr.makeStringAndClear());
3082     }
3083     else if (eType == SvNumFormatType::FRACTION)
3084     {
3085         OUString aIntegerFractionDelimiterString = pFormat->GetIntegerFractionDelimiterString( 0 );
3086         if ( aIntegerFractionDelimiterString == " " )
3087             sString.append( aIntegerFractionDelimiterString );
3088         else
3089         {
3090             sString.append( '"' );
3091             sString.append( aIntegerFractionDelimiterString );
3092             sString.append( '"' );
3093         }
3094         sString.append( pFormat->GetNumeratorString( 0 ) );
3095         sString.append( '/' );
3096         if ( nPrecision > 0 )
3097             padToLength(sString, sString.getLength() + nPrecision, '?');
3098         else
3099             sString.append( '#' );
3100     }
3101     if (eType != SvNumFormatType::CURRENCY)
3102     {
3103         bool insertBrackets = false;
3104         if ( eType != SvNumFormatType::UNDEFINED)
3105         {
3106             insertBrackets = pFormat->IsNegativeInBracket();
3107         }
3108         if (IsRed || insertBrackets)
3109         {
3110             OUStringBuffer sTmpStr(sString);
3111 
3112             if (pFormat && pFormat->HasPositiveBracketPlaceholder())
3113             {
3114                  sTmpStr.append('_');
3115                  sTmpStr.append(')');
3116             }
3117             sTmpStr.append(';');
3118 
3119             if (IsRed)
3120             {
3121                 sTmpStr.append('[');
3122                 sTmpStr.append(pFormatScanner->GetRedString());
3123                 sTmpStr.append(']');
3124             }
3125 
3126             if (insertBrackets)
3127             {
3128                 sTmpStr.append('(');
3129                 sTmpStr.append(sString.toString());
3130                 sTmpStr.append(')');
3131             }
3132             else
3133             {
3134                 sTmpStr.append('-');
3135                 sTmpStr.append(sString.toString());
3136             }
3137             sString = sTmpStr;
3138         }
3139     }
3140     return sString.makeStringAndClear();
3141 }
3142 
IsUserDefined(const OUString & sStr,LanguageType eLnge)3143 bool SvNumberFormatter::IsUserDefined(const OUString& sStr,
3144                                       LanguageType eLnge)
3145 {
3146     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3147     if (eLnge == LANGUAGE_DONTKNOW)
3148     {
3149         eLnge = IniLnge;
3150     }
3151     sal_uInt32 CLOffset = ImpGenerateCL(eLnge);     // create new standard formats if necessary
3152     eLnge = ActLnge;
3153 
3154     sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
3155     if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
3156     {
3157         return true;
3158     }
3159     SvNumberformat* pEntry = GetFormatEntry( nKey );
3160     return pEntry && (pEntry->GetType() & SvNumFormatType::DEFINED);
3161 }
3162 
GetEntryKey(const OUString & sStr,LanguageType eLnge)3163 sal_uInt32 SvNumberFormatter::GetEntryKey(const OUString& sStr,
3164                                           LanguageType eLnge)
3165 {
3166     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3167     if (eLnge == LANGUAGE_DONTKNOW)
3168     {
3169         eLnge = IniLnge;
3170     }
3171     sal_uInt32 CLOffset = ImpGenerateCL(eLnge);     // create new standard formats if necessary
3172     return ImpIsEntry(sStr, CLOffset, eLnge);
3173 }
3174 
GetStandardIndex(LanguageType eLnge)3175 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
3176 {
3177     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3178     if (eLnge == LANGUAGE_DONTKNOW)
3179     {
3180         eLnge = IniLnge;
3181     }
3182     return GetStandardFormat(SvNumFormatType::NUMBER, eLnge);
3183 }
3184 
GetType(sal_uInt32 nFIndex) const3185 SvNumFormatType SvNumberFormatter::GetType(sal_uInt32 nFIndex) const
3186 {
3187     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3188     SvNumFormatType eType;
3189     const SvNumberformat* pFormat = GetFormatEntry( nFIndex );
3190     if (!pFormat)
3191     {
3192         eType = SvNumFormatType::UNDEFINED;
3193     }
3194     else
3195     {
3196         eType = pFormat->GetMaskedType();
3197         if (eType == SvNumFormatType::ALL)
3198         {
3199             eType = SvNumFormatType::DEFINED;
3200         }
3201     }
3202     return eType;
3203 }
3204 
ClearMergeTable()3205 void SvNumberFormatter::ClearMergeTable()
3206 {
3207     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3208     if ( pMergeTable )
3209     {
3210         pMergeTable->clear();
3211     }
3212 }
3213 
MergeFormatter(SvNumberFormatter & rTable)3214 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
3215 {
3216     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3217     if ( pMergeTable )
3218     {
3219         ClearMergeTable();
3220     }
3221     else
3222     {
3223         pMergeTable.reset( new SvNumberFormatterIndexTable );
3224     }
3225 
3226     sal_uInt32 nCLOffset = 0;
3227     sal_uInt32 nOldKey, nOffset, nNewKey;
3228 
3229     for (const auto& rEntry : rTable.aFTable)
3230     {
3231         SvNumberformat* pFormat = rEntry.second.get();
3232         nOldKey = rEntry.first;
3233         nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET;     // relative index
3234         if (nOffset == 0)                                   // 1st format of CL
3235         {
3236             nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
3237         }
3238         if (nOffset <= SV_MAX_COUNT_STANDARD_FORMATS)     // Std.form.
3239         {
3240             nNewKey = nCLOffset + nOffset;
3241             if (aFTable.find( nNewKey) == aFTable.end())    // not already present
3242             {
3243                 std::unique_ptr<SvNumberformat> pNewEntry(new SvNumberformat( *pFormat, *pFormatScanner ));
3244                 if (!aFTable.emplace( nNewKey, std::move(pNewEntry)).second)
3245                 {
3246                     SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3247                 }
3248             }
3249             if (nNewKey != nOldKey)                     // new index
3250             {
3251                 (*pMergeTable)[nOldKey] = nNewKey;
3252             }
3253         }
3254         else                                            // user defined
3255         {
3256             std::unique_ptr<SvNumberformat> pNewEntry(new SvNumberformat( *pFormat, *pFormatScanner ));
3257             nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
3258                                  nCLOffset,
3259                                  pFormat->GetLanguage());
3260             if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND) // only if not present yet
3261             {
3262                 SvNumberformat* pStdFormat = GetFormatEntry(nCLOffset + ZF_STANDARD);
3263                 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3264                 nNewKey = nPos+1;
3265                 if (nNewKey - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
3266                 {
3267                     SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3268                 }
3269                 else if (!aFTable.emplace( nNewKey, std::move(pNewEntry)).second)
3270                 {
3271                     SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3272                 }
3273                 else
3274                 {
3275                     pStdFormat->SetLastInsertKey(static_cast<sal_uInt16>(nNewKey - nCLOffset),
3276                             SvNumberformat::FormatterPrivateAccess());
3277                 }
3278             }
3279             if (nNewKey != nOldKey)                     // new index
3280             {
3281                 (*pMergeTable)[nOldKey] = nNewKey;
3282             }
3283         }
3284     }
3285     return pMergeTable.get();
3286 }
3287 
3288 
ConvertMergeTableToMap()3289 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
3290 {
3291     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3292     if (!HasMergeFormatTable())
3293     {
3294         return SvNumberFormatterMergeMap();
3295     }
3296     SvNumberFormatterMergeMap aMap;
3297     for (const auto& rEntry : *pMergeTable)
3298     {
3299         sal_uInt32 nOldKey = rEntry.first;
3300         aMap[ nOldKey ] = rEntry.second;
3301     }
3302     ClearMergeTable();
3303     return aMap;
3304 }
3305 
3306 
GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat,LanguageType eLnge)3307 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
3308                                                              LanguageType eLnge )
3309 {
3310     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3311     if ( eLnge == LANGUAGE_DONTKNOW )
3312     {
3313         eLnge = IniLnge;
3314     }
3315     if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
3316     {
3317         return nFormat;     // it stays as it is
3318     }
3319     sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET;  // relative index
3320     if ( nOffset > SV_MAX_COUNT_STANDARD_FORMATS )
3321     {
3322         return nFormat;    // not a built-in format
3323     }
3324     sal_uInt32 nCLOffset = ImpGenerateCL(eLnge);    // create new standard formats if necessary
3325     return nCLOffset + nOffset;
3326 }
3327 
3328 
GetFormatIndex(NfIndexTableOffset nTabOff,LanguageType eLnge)3329 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
3330                                               LanguageType eLnge )
3331 {
3332     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3333     if (nTabOff >= NF_INDEX_TABLE_ENTRIES)
3334         return NUMBERFORMAT_ENTRY_NOT_FOUND;
3335 
3336     if (eLnge == LANGUAGE_DONTKNOW)
3337         eLnge = IniLnge;
3338 
3339     if (indexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND)
3340         return NUMBERFORMAT_ENTRY_NOT_FOUND;
3341 
3342     sal_uInt32 nCLOffset = ImpGenerateCL(eLnge);    // create new standard formats if necessary
3343 
3344     return nCLOffset + indexTable[nTabOff];
3345 }
3346 
3347 
GetIndexTableOffset(sal_uInt32 nFormat) const3348 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
3349 {
3350     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3351     sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET;      // relative index
3352     if ( nOffset > SV_MAX_COUNT_STANDARD_FORMATS )
3353     {
3354         return NF_INDEX_TABLE_ENTRIES;      // not a built-in format
3355     }
3356 
3357     for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3358     {
3359         if (indexTable[j] == nOffset)
3360             return static_cast<NfIndexTableOffset>(j);
3361     }
3362     return NF_INDEX_TABLE_ENTRIES;      // bad luck
3363 }
3364 
SetEvalDateFormat(NfEvalDateFormat eEDF)3365 void SvNumberFormatter::SetEvalDateFormat( NfEvalDateFormat eEDF )
3366 {
3367     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3368     eEvalDateFormat = eEDF;
3369 }
3370 
GetEvalDateFormat() const3371 NfEvalDateFormat SvNumberFormatter::GetEvalDateFormat() const
3372 {
3373     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3374     return eEvalDateFormat;
3375 }
3376 
SetYear2000(sal_uInt16 nVal)3377 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal )
3378 {
3379     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3380     pStringScanner->SetYear2000( nVal );
3381 }
3382 
3383 
GetYear2000() const3384 sal_uInt16 SvNumberFormatter::GetYear2000() const
3385 {
3386     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3387     return pStringScanner->GetYear2000();
3388 }
3389 
3390 
ExpandTwoDigitYear(sal_uInt16 nYear) const3391 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear ) const
3392 {
3393     if ( nYear < 100 )
3394         return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3395             pStringScanner->GetYear2000() );
3396     return nYear;
3397 }
3398 
3399 
3400 // static
GetYear2000Default()3401 sal_uInt16 SvNumberFormatter::GetYear2000Default()
3402 {
3403     if (!utl::ConfigManager::IsFuzzing())
3404         return static_cast<sal_uInt16>(::utl::MiscCfg().GetYear2000());
3405     return 1930;
3406 }
3407 
3408 
3409 // static
GetTheCurrencyTable()3410 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3411 {
3412     while ( !bCurrencyTableInitialized )
3413         ImpInitCurrencyTable();
3414     return theCurrencyTable::get();
3415 }
3416 
3417 
3418 // static
MatchSystemCurrency()3419 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3420 {
3421     // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3422     const NfCurrencyTable& rTable = GetTheCurrencyTable();
3423     return nSystemCurrencyPosition ? &rTable[nSystemCurrencyPosition] : nullptr;
3424 }
3425 
3426 
3427 // static
GetCurrencyEntry(LanguageType eLang)3428 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3429 {
3430     if ( eLang == LANGUAGE_SYSTEM )
3431     {
3432         const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3433         return pCurr ? *pCurr : GetTheCurrencyTable()[0];
3434     }
3435     else
3436     {
3437         eLang = MsLangId::getRealLanguage( eLang );
3438         const NfCurrencyTable& rTable = GetTheCurrencyTable();
3439         sal_uInt16 nCount = rTable.size();
3440         for ( sal_uInt16 j = 0; j < nCount; j++ )
3441         {
3442             if ( rTable[j].GetLanguage() == eLang )
3443                 return rTable[j];
3444         }
3445         return rTable[0];
3446     }
3447 }
3448 
3449 
3450 // static
GetCurrencyEntry(const OUString & rAbbrev,LanguageType eLang)3451 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(const OUString& rAbbrev, LanguageType eLang )
3452 {
3453     eLang = MsLangId::getRealLanguage( eLang );
3454     const NfCurrencyTable& rTable = GetTheCurrencyTable();
3455     sal_uInt16 nCount = rTable.size();
3456     for ( sal_uInt16 j = 0; j < nCount; j++ )
3457     {
3458         if ( rTable[j].GetLanguage() == eLang &&
3459              rTable[j].GetBankSymbol() == rAbbrev )
3460         {
3461             return &rTable[j];
3462         }
3463     }
3464     return nullptr;
3465 }
3466 
3467 
3468 // static
GetLegacyOnlyCurrencyEntry(const OUString & rSymbol,const OUString & rAbbrev)3469 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString& rSymbol,
3470                                                                       const OUString& rAbbrev )
3471 {
3472     GetTheCurrencyTable();      // just for initialization
3473     const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3474     sal_uInt16 nCount = rTable.size();
3475     for ( sal_uInt16 j = 0; j < nCount; j++ )
3476     {
3477         if ( rTable[j].GetSymbol() == rSymbol &&
3478              rTable[j].GetBankSymbol() == rAbbrev )
3479         {
3480             return &rTable[j];
3481         }
3482     }
3483     return nullptr;
3484 }
3485 
3486 
3487 // static
IMPL_STATIC_LINK_NOARG(SvNumberFormatter,CurrencyChangeLink,LinkParamNone *,void)3488 IMPL_STATIC_LINK_NOARG( SvNumberFormatter, CurrencyChangeLink, LinkParamNone*, void )
3489 {
3490     OUString aAbbrev;
3491     LanguageType eLang = LANGUAGE_SYSTEM;
3492     SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3493     SetDefaultSystemCurrency( aAbbrev, eLang );
3494 }
3495 
3496 
3497 // static
SetDefaultSystemCurrency(const OUString & rAbbrev,LanguageType eLang)3498 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString& rAbbrev, LanguageType eLang )
3499 {
3500     ::osl::MutexGuard aGuard( GetGlobalMutex() );
3501     if ( eLang == LANGUAGE_SYSTEM )
3502     {
3503         eLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3504     }
3505     const NfCurrencyTable& rTable = GetTheCurrencyTable();
3506     sal_uInt16 nCount = rTable.size();
3507     if ( !rAbbrev.isEmpty() )
3508     {
3509         for ( sal_uInt16 j = 0; j < nCount; j++ )
3510         {
3511             if ( rTable[j].GetLanguage() == eLang && rTable[j].GetBankSymbol() == rAbbrev )
3512             {
3513                 nSystemCurrencyPosition = j;
3514                 return ;
3515             }
3516         }
3517     }
3518     else
3519     {
3520         for ( sal_uInt16 j = 0; j < nCount; j++ )
3521         {
3522             if ( rTable[j].GetLanguage() == eLang )
3523             {
3524                 nSystemCurrencyPosition = j;
3525                 return ;
3526             }
3527         }
3528     }
3529     nSystemCurrencyPosition = 0;    // not found => simple SYSTEM
3530 }
3531 
3532 
ResetDefaultSystemCurrency()3533 void SvNumberFormatter::ResetDefaultSystemCurrency()
3534 {
3535     nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3536 }
3537 
3538 
InvalidateDateAcceptancePatterns()3539 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3540 {
3541     pStringScanner->InvalidateDateAcceptancePatterns();
3542 }
3543 
3544 
ImpGetDefaultSystemCurrencyFormat()3545 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3546 {
3547     if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3548     {
3549         sal_Int32 nCheck;
3550         SvNumFormatType nType;
3551         NfWSStringsDtor aCurrList;
3552         sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3553             GetCurrencyEntry( LANGUAGE_SYSTEM ), false );
3554         DBG_ASSERT( aCurrList.size(), "where is the NewCurrency System standard format?!?" );
3555         // if already loaded or user defined nDefaultSystemCurrencyFormat
3556         // will be set to the right value
3557         PutEntry( aCurrList[ nDefault ], nCheck, nType,
3558             nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3559         DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3560         DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3561             "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3562     }
3563     return nDefaultSystemCurrencyFormat;
3564 }
3565 
3566 
ImpGetDefaultCurrencyFormat()3567 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3568 {
3569     sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3570     DefaultFormatKeysMap::const_iterator it = aDefaultFormatKeys.find( CLOffset + ZF_STANDARD_CURRENCY );
3571     sal_uInt32 nDefaultCurrencyFormat = (it != aDefaultFormatKeys.end() ?
3572             it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
3573     if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3574     {
3575         // look for a defined standard
3576         sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3577         sal_uInt32 nKey(0);
3578         auto it2 = aFTable.lower_bound( CLOffset );
3579         while ( it2 != aFTable.end() && (nKey = it2->first) >= CLOffset && nKey < nStopKey )
3580         {
3581             const SvNumberformat* pEntry = it2->second.get();
3582             if ( pEntry->IsStandard() && (pEntry->GetType() & SvNumFormatType::CURRENCY) )
3583             {
3584                 nDefaultCurrencyFormat = nKey;
3585                 break;  // while
3586             }
3587             ++it2;
3588         }
3589 
3590         if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3591         {   // none found, create one
3592             sal_Int32 nCheck;
3593             NfWSStringsDtor aCurrList;
3594             sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3595                 GetCurrencyEntry( ActLnge ), false );
3596             DBG_ASSERT( aCurrList.size(), "where is the NewCurrency standard format?" );
3597             if ( !aCurrList.empty() )
3598             {
3599                 // if already loaded or user defined nDefaultSystemCurrencyFormat
3600                 // will be set to the right value
3601                 SvNumFormatType nType;
3602                 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3603                     nDefaultCurrencyFormat, ActLnge );
3604                 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3605                 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3606                     "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3607             }
3608             // old automatic currency format as a last resort
3609             if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3610                 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3611             else
3612             {   // mark as standard so that it is found next time
3613                 SvNumberformat* pEntry = GetFormatEntry( nDefaultCurrencyFormat );
3614                 if ( pEntry )
3615                     pEntry->SetStandard();
3616             }
3617         }
3618         aDefaultFormatKeys[ CLOffset + ZF_STANDARD_CURRENCY ] = nDefaultCurrencyFormat;
3619     }
3620     return nDefaultCurrencyFormat;
3621 }
3622 
3623 
3624 // static
3625 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
ImpLookupCurrencyEntryLoopBody(const NfCurrencyEntry * & pFoundEntry,bool & bFoundBank,const NfCurrencyEntry * pData,sal_uInt16 nPos,const OUString & rSymbol)3626 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3627     const NfCurrencyEntry*& pFoundEntry, bool& bFoundBank, const NfCurrencyEntry* pData,
3628     sal_uInt16 nPos, const OUString& rSymbol )
3629 {
3630     bool bFound;
3631     if ( pData->GetSymbol() == rSymbol )
3632     {
3633         bFound = true;
3634         bFoundBank = false;
3635     }
3636     else if ( pData->GetBankSymbol() == rSymbol )
3637     {
3638         bFound = true;
3639         bFoundBank = true;
3640     }
3641     else
3642         bFound = false;
3643     if ( bFound )
3644     {
3645         if ( pFoundEntry && pFoundEntry != pData )
3646         {
3647             pFoundEntry = nullptr;
3648             return false;   // break loop, not unique
3649         }
3650         if ( nPos == 0 )
3651         {   // first entry is SYSTEM
3652             pFoundEntry = MatchSystemCurrency();
3653             if ( pFoundEntry )
3654             {
3655                 return false;   // break loop
3656                 // even if there are more matching entries
3657                 // this one is probably the one we are looking for
3658             }
3659             else
3660             {
3661                 pFoundEntry = pData;
3662             }
3663         }
3664         else
3665         {
3666             pFoundEntry = pData;
3667         }
3668     }
3669     return true;
3670 }
3671 
3672 
GetNewCurrencySymbolString(sal_uInt32 nFormat,OUString & rStr,const NfCurrencyEntry ** ppEntry,bool * pBank) const3673 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, OUString& rStr,
3674                                                     const NfCurrencyEntry** ppEntry /* = NULL */,
3675                                                     bool* pBank /* = NULL */ ) const
3676 {
3677     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3678     if ( ppEntry )
3679         *ppEntry = nullptr;
3680     if ( pBank )
3681         *pBank = false;
3682 
3683     const SvNumberformat* pFormat = GetFormatEntry(nFormat);
3684     if ( pFormat )
3685     {
3686         OUStringBuffer sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
3687         OUString aSymbol, aExtension;
3688         if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3689         {
3690             if ( ppEntry )
3691             {
3692                 bool bFoundBank = false;
3693                 // we definitely need an entry matching the format code string
3694                 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3695                     bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3696                     true );
3697                 if ( pFoundEntry )
3698                 {
3699                     *ppEntry = pFoundEntry;
3700                     if ( pBank )
3701                         *pBank = bFoundBank;
3702                     rStr = pFoundEntry->BuildSymbolString(bFoundBank);
3703                 }
3704             }
3705             if ( rStr.isEmpty() )
3706             {   // analog to BuildSymbolString
3707                 sBuff.append("[$");
3708                 if ( aSymbol.indexOf( '-' ) != -1 ||
3709                         aSymbol.indexOf( ']' ) != -1 )
3710                 {
3711                     sBuff.append('"');
3712                     sBuff.append( aSymbol);
3713                     sBuff.append('"');
3714                 }
3715                 else
3716                 {
3717                     sBuff.append(aSymbol);
3718                 }
3719                 if ( !aExtension.isEmpty() )
3720                 {
3721                     sBuff.append(aExtension);
3722                 }
3723                 sBuff.append(']');
3724             }
3725             rStr = sBuff.toString();
3726             return true;
3727         }
3728     }
3729     rStr.clear();
3730     return false;
3731 }
3732 
3733 
3734 // static
GetCurrencyEntry(bool & bFoundBank,const OUString & rSymbol,const OUString & rExtension,LanguageType eFormatLanguage,bool bOnlyStringLanguage)3735 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank,
3736                                                             const OUString& rSymbol,
3737                                                             const OUString& rExtension,
3738                                                             LanguageType eFormatLanguage,
3739                                                             bool bOnlyStringLanguage )
3740 {
3741     sal_Int32 nExtLen = rExtension.getLength();
3742     LanguageType eExtLang;
3743     if ( nExtLen )
3744     {
3745         // rExtension should be a 16-bit hex value max FFFF which may contain a
3746         // leading "-" separator (that is not a minus sign, but toInt32 can be
3747         // used to parse it, with post-processing as necessary):
3748         sal_Int32 nExtLang = rExtension.toInt32( 16 );
3749         if ( !nExtLang )
3750         {
3751             eExtLang = LANGUAGE_DONTKNOW;
3752         }
3753         else
3754         {
3755             eExtLang = LanguageType((nExtLang < 0) ? -nExtLang : nExtLang);
3756         }
3757     }
3758     else
3759     {
3760         eExtLang = LANGUAGE_DONTKNOW;
3761     }
3762     const NfCurrencyEntry* pFoundEntry = nullptr;
3763     const NfCurrencyTable& rTable = GetTheCurrencyTable();
3764     sal_uInt16 nCount = rTable.size();
3765     bool bCont = true;
3766 
3767     // first try with given extension language/country
3768     if ( nExtLen )
3769     {
3770         for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3771         {
3772             LanguageType eLang = rTable[j].GetLanguage();
3773             if ( eLang == eExtLang ||
3774                  ((eExtLang == LANGUAGE_DONTKNOW) &&
3775                   (eLang == LANGUAGE_SYSTEM)))
3776             {
3777                 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3778                                                         &rTable[j], j, rSymbol );
3779             }
3780         }
3781     }
3782 
3783     // ok?
3784     if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3785     {
3786         return pFoundEntry;
3787     }
3788     if ( !bOnlyStringLanguage )
3789     {
3790         // now try the language/country of the number format
3791         for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3792         {
3793             LanguageType eLang = rTable[j].GetLanguage();
3794             if ( eLang == eFormatLanguage ||
3795                  ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3796                   (eLang == LANGUAGE_SYSTEM)))
3797             {
3798                 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3799                                                         &rTable[j], j, rSymbol );
3800             }
3801         }
3802 
3803         // ok?
3804         if ( pFoundEntry || !bCont )
3805         {
3806             return pFoundEntry;
3807         }
3808     }
3809 
3810     // then try without language/country if no extension specified
3811     if ( !nExtLen )
3812     {
3813         for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3814         {
3815             bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3816                                                     &rTable[j], j, rSymbol );
3817         }
3818     }
3819 
3820     return pFoundEntry;
3821 }
3822 
3823 
GetCompatibilityCurrency(OUString & rSymbol,OUString & rAbbrev) const3824 void SvNumberFormatter::GetCompatibilityCurrency( OUString& rSymbol, OUString& rAbbrev ) const
3825 {
3826     ::osl::MutexGuard aGuard( GetInstanceMutex() );
3827     css::uno::Sequence< css::i18n::Currency2 >
3828         xCurrencies( xLocaleData->getAllCurrencies() );
3829 
3830     auto pCurrency = std::find_if(xCurrencies.begin(), xCurrencies.end(),
3831         [](const css::i18n::Currency2& rCurrency) { return rCurrency.UsedInCompatibleFormatCodes; });
3832     if (pCurrency != xCurrencies.end())
3833     {
3834         rSymbol = pCurrency->Symbol;
3835         rAbbrev = pCurrency->BankSymbol;
3836     }
3837     else
3838     {
3839         if (LocaleDataWrapper::areChecksEnabled())
3840         {
3841             LocaleDataWrapper::outputCheckMessage( xLocaleData->
3842                                                    appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3843         }
3844         rSymbol = xLocaleData->getCurrSymbol();
3845         rAbbrev = xLocaleData->getCurrBankSymbol();
3846     }
3847 }
3848 
3849 
lcl_CheckCurrencySymbolPosition(const NfCurrencyEntry & rCurr)3850 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3851 {
3852     switch ( rCurr.GetPositiveFormat() )
3853     {
3854     case 0:                                         // $1
3855     case 1:                                         // 1$
3856     case 2:                                         // $ 1
3857     case 3:                                         // 1 $
3858         break;
3859     default:
3860         LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3861         break;
3862     }
3863     switch ( rCurr.GetNegativeFormat() )
3864     {
3865     case 0:                                         // ($1)
3866     case 1:                                         // -$1
3867     case 2:                                         // $-1
3868     case 3:                                         // $1-
3869     case 4:                                         // (1$)
3870     case 5:                                         // -1$
3871     case 6:                                         // 1-$
3872     case 7:                                         // 1$-
3873     case 8:                                         // -1 $
3874     case 9:                                         // -$ 1
3875     case 10:                                        // 1 $-
3876     case 11:                                        // $ -1
3877     case 12 :                                       // $ 1-
3878     case 13 :                                       // 1- $
3879     case 14 :                                       // ($ 1)
3880     case 15 :                                       // (1 $)
3881         break;
3882     default:
3883         LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3884         break;
3885     }
3886 }
3887 
3888 // static
IsLocaleInstalled(LanguageType eLang)3889 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang )
3890 {
3891     // The set is initialized as a side effect of the currency table
3892     // created, make sure that exists, which usually is the case unless a
3893     // SvNumberFormatter was never instantiated.
3894     GetTheCurrencyTable();
3895     const NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3896     return rInstalledLocales.find( eLang) != rInstalledLocales.end();
3897 }
3898 
3899 // static
ImpInitCurrencyTable()3900 void SvNumberFormatter::ImpInitCurrencyTable()
3901 {
3902     // Race condition possible:
3903     // ::osl::MutexGuard aGuard( GetMutex() );
3904     // while ( !bCurrencyTableInitialized )
3905     //      ImpInitCurrencyTable();
3906     static bool bInitializing = false;
3907     if ( bCurrencyTableInitialized || bInitializing )
3908     {
3909         return ;
3910     }
3911     bInitializing = true;
3912 
3913     LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3914     std::unique_ptr<LocaleDataWrapper> pLocaleData(new LocaleDataWrapper(
3915         ::comphelper::getProcessComponentContext(),
3916         SvtSysLocale().GetLanguageTag() ));
3917     // get user configured currency
3918     OUString aConfiguredCurrencyAbbrev;
3919     LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3920     SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3921         aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3922     sal_uInt16 nSecondarySystemCurrencyPosition = 0;
3923     sal_uInt16 nMatchingSystemCurrencyPosition = 0;
3924 
3925     // First entry is SYSTEM:
3926     theCurrencyTable::get().insert(
3927         theCurrencyTable::get().begin(),
3928         std::make_unique<NfCurrencyEntry>(*pLocaleData, LANGUAGE_SYSTEM));
3929     sal_uInt16 nCurrencyPos = 1;
3930 
3931     const css::uno::Sequence< css::lang::Locale > xLoc = LocaleDataWrapper::getInstalledLocaleNames();
3932     sal_Int32 nLocaleCount = xLoc.getLength();
3933     SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount << "\"" );
3934     NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3935     NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3936     NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3937     sal_uInt16 nLegacyOnlyCurrencyPos = 0;
3938     for ( css::lang::Locale const & rLocale : xLoc )
3939     {
3940         LanguageType eLang = LanguageTag::convertToLanguageType( rLocale, false);
3941         rInstalledLocales.insert( eLang);
3942         pLocaleData->setLanguageTag( LanguageTag( rLocale) );
3943         Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3944         sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3945         Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3946 
3947         // one default currency for each locale, insert first so it is found first
3948         sal_Int32 nDefault;
3949         for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3950         {
3951             if ( pCurrencies[nDefault].Default )
3952                 break;
3953         }
3954         std::unique_ptr<NfCurrencyEntry> pEntry;
3955         if ( nDefault < nCurrencyCount )
3956         {
3957             pEntry.reset(new NfCurrencyEntry(pCurrencies[nDefault], *pLocaleData, eLang));
3958         }
3959         else
3960         {   // first or ShellsAndPebbles
3961             pEntry.reset(new NfCurrencyEntry(*pLocaleData, eLang));
3962         }
3963         if (LocaleDataWrapper::areChecksEnabled())
3964         {
3965             lcl_CheckCurrencySymbolPosition( *pEntry );
3966         }
3967         if ( !nSystemCurrencyPosition && !aConfiguredCurrencyAbbrev.isEmpty() &&
3968              pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
3969              pEntry->GetLanguage() == eConfiguredCurrencyLanguage )
3970         {
3971             nSystemCurrencyPosition = nCurrencyPos;
3972         }
3973         if ( !nMatchingSystemCurrencyPosition &&
3974              pEntry->GetLanguage() == eSysLang )
3975         {
3976             nMatchingSystemCurrencyPosition = nCurrencyPos;
3977         }
3978         rCurrencyTable.insert(
3979                 rCurrencyTable.begin() + nCurrencyPos++, std::move(pEntry));
3980         // all remaining currencies for each locale
3981         if ( nCurrencyCount > 1 )
3982         {
3983             sal_Int32 nCurrency;
3984             for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3985             {
3986                 if (pCurrencies[nCurrency].LegacyOnly)
3987                 {
3988                     rLegacyOnlyCurrencyTable.insert(
3989                         rLegacyOnlyCurrencyTable.begin() + nLegacyOnlyCurrencyPos++,
3990                         std::make_unique<NfCurrencyEntry>(
3991                             pCurrencies[nCurrency], *pLocaleData, eLang));
3992                 }
3993                 else if ( nCurrency != nDefault )
3994                 {
3995                     pEntry.reset(new NfCurrencyEntry(pCurrencies[nCurrency], *pLocaleData, eLang));
3996                     // no dupes
3997                     bool bInsert = true;
3998                     sal_uInt16 n = rCurrencyTable.size();
3999                     sal_uInt16 aCurrencyIndex = 1; // skip first SYSTEM entry
4000                     for ( sal_uInt16 j=1; j<n; j++ )
4001                     {
4002                         if ( rCurrencyTable[aCurrencyIndex++] == *pEntry )
4003                         {
4004                             bInsert = false;
4005                             break;  // for
4006                         }
4007                     }
4008                     if ( !bInsert )
4009                     {
4010                         pEntry.reset();
4011                     }
4012                     else
4013                     {
4014                         if ( !nSecondarySystemCurrencyPosition &&
4015                              (!aConfiguredCurrencyAbbrev.isEmpty() ?
4016                               pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
4017                               pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
4018                         {
4019                             nSecondarySystemCurrencyPosition = nCurrencyPos;
4020                         }
4021                         if ( !nMatchingSystemCurrencyPosition &&
4022                              pEntry->GetLanguage() ==  eSysLang )
4023                         {
4024                             nMatchingSystemCurrencyPosition = nCurrencyPos;
4025                         }
4026                         rCurrencyTable.insert(
4027                             rCurrencyTable.begin() + nCurrencyPos++, std::move(pEntry));
4028                     }
4029                 }
4030             }
4031         }
4032     }
4033     if ( !nSystemCurrencyPosition )
4034     {
4035         nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
4036     }
4037     if ((!aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
4038         LocaleDataWrapper::areChecksEnabled())
4039     {
4040         LocaleDataWrapper::outputCheckMessage(
4041                 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
4042     }
4043     // match SYSTEM if no configured currency found
4044     if ( !nSystemCurrencyPosition )
4045     {
4046         nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
4047     }
4048     if ((aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
4049         LocaleDataWrapper::areChecksEnabled())
4050     {
4051         LocaleDataWrapper::outputCheckMessage(
4052                 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
4053     }
4054     pLocaleData.reset();
4055     SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( nullptr, SvNumberFormatter, CurrencyChangeLink ) );
4056     bInitializing = false;
4057     bCurrencyTableInitialized = true;
4058 }
4059 
4060 
addToCurrencyFormatsList(NfWSStringsDtor & rStrArr,const OUString & rFormat)4061 static void addToCurrencyFormatsList( NfWSStringsDtor& rStrArr, const OUString& rFormat )
4062 {
4063     // Prevent duplicates even over subsequent calls of
4064     // GetCurrencyFormatStrings() with the same vector.
4065     if (std::find( rStrArr.begin(), rStrArr.end(), rFormat) == rStrArr.end())
4066         rStrArr.push_back( rFormat);
4067 }
4068 
4069 
GetCurrencyFormatStrings(NfWSStringsDtor & rStrArr,const NfCurrencyEntry & rCurr,bool bBank) const4070 sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
4071                                                         const NfCurrencyEntry& rCurr,
4072                                                         bool bBank ) const
4073 {
4074     ::osl::MutexGuard aGuard( GetInstanceMutex() );
4075     OUString aRed = "["
4076                   + pFormatScanner->GetRedString()
4077                   + "]";
4078 
4079     sal_uInt16 nDefault = 0;
4080     if ( bBank )
4081     {
4082         // Only bank symbols.
4083         OUString aPositiveBank = rCurr.BuildPositiveFormatString(true, *xLocaleData);
4084         OUString aNegativeBank = rCurr.BuildNegativeFormatString(true, *xLocaleData );
4085 
4086         OUString format1 = aPositiveBank
4087                          + ";"
4088                          + aNegativeBank;
4089         addToCurrencyFormatsList( rStrArr, format1);
4090 
4091         OUString format2 = aPositiveBank
4092                          + ";"
4093                          + aRed
4094                          + aNegativeBank;
4095         addToCurrencyFormatsList( rStrArr, format2);
4096 
4097         nDefault = rStrArr.size() - 1;
4098     }
4099     else
4100     {
4101         // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
4102         // duplicates if no decimals in currency.
4103         OUString aPositive = rCurr.BuildPositiveFormatString(false, *xLocaleData );
4104         OUString aNegative = rCurr.BuildNegativeFormatString(false, *xLocaleData );
4105         OUString format1;
4106         OUString format2;
4107         OUString format3;
4108         OUString format4;
4109         OUString format5;
4110         if (rCurr.GetDigits())
4111         {
4112             OUString aPositiveNoDec = rCurr.BuildPositiveFormatString(false, *xLocaleData, 0);
4113             OUString aNegativeNoDec = rCurr.BuildNegativeFormatString(false, *xLocaleData, 0 );
4114             OUString aPositiveDashed = rCurr.BuildPositiveFormatString(false, *xLocaleData, 2);
4115             OUString aNegativeDashed = rCurr.BuildNegativeFormatString(false, *xLocaleData, 2);
4116 
4117             format1 = aPositiveNoDec
4118                     + ";"
4119                     + aNegativeNoDec;
4120 
4121             format3 = aPositiveNoDec
4122                     + ";"
4123                     + aRed
4124                     + aNegativeNoDec;
4125 
4126             format5 = aPositiveDashed
4127                     + ";"
4128                     + aRed
4129                     + aNegativeDashed;
4130         }
4131 
4132         format2 = aPositive
4133                 + ";"
4134                 + aNegative;
4135 
4136         format4 = aPositive
4137                 + ";"
4138                 + aRed
4139                 + aNegative;
4140 
4141         if (rCurr.GetDigits())
4142         {
4143             addToCurrencyFormatsList( rStrArr, format1);
4144         }
4145         addToCurrencyFormatsList( rStrArr, format2);
4146         if (rCurr.GetDigits())
4147         {
4148             addToCurrencyFormatsList( rStrArr, format3);
4149         }
4150         addToCurrencyFormatsList( rStrArr, format4);
4151         nDefault = rStrArr.size() - 1;
4152         if (rCurr.GetDigits())
4153         {
4154             addToCurrencyFormatsList( rStrArr, format5);
4155         }
4156     }
4157     return nDefault;
4158 }
4159 
GetMergeFormatIndex(sal_uInt32 nOldFmt) const4160 sal_uInt32 SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt ) const
4161 {
4162     ::osl::MutexGuard aGuard( GetInstanceMutex() );
4163     if (pMergeTable)
4164     {
4165         SvNumberFormatterIndexTable::const_iterator it = pMergeTable->find(nOldFmt);
4166         if (it != pMergeTable->end())
4167         {
4168             return it->second;
4169         }
4170     }
4171     return nOldFmt;
4172 }
4173 
HasMergeFormatTable() const4174 bool SvNumberFormatter::HasMergeFormatTable() const
4175 {
4176     ::osl::MutexGuard aGuard( GetInstanceMutex() );
4177     return pMergeTable && !pMergeTable->empty();
4178 }
4179 
4180 // static
ExpandTwoDigitYear(sal_uInt16 nYear,sal_uInt16 nTwoDigitYearStart)4181 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear, sal_uInt16 nTwoDigitYearStart )
4182 {
4183     if ( nYear < 100 )
4184     {
4185         if ( nYear < (nTwoDigitYearStart % 100) )
4186         {
4187             return nYear + (((nTwoDigitYearStart / 100) + 1) * 100);
4188         }
4189         else
4190         {
4191             return nYear + ((nTwoDigitYearStart / 100) * 100);
4192         }
4193     }
4194     return nYear;
4195 }
4196 
NfCurrencyEntry(const LocaleDataWrapper & rLocaleData,LanguageType eLang)4197 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
4198 {
4199     aSymbol         = rLocaleData.getCurrSymbol();
4200     aBankSymbol     = rLocaleData.getCurrBankSymbol();
4201     eLanguage       = eLang;
4202     nPositiveFormat = rLocaleData.getCurrPositiveFormat();
4203     nNegativeFormat = rLocaleData.getCurrNegativeFormat();
4204     nDigits         = rLocaleData.getCurrDigits();
4205     cZeroChar       = rLocaleData.getCurrZeroChar();
4206 }
4207 
4208 
NfCurrencyEntry(const css::i18n::Currency & rCurr,const LocaleDataWrapper & rLocaleData,LanguageType eLang)4209 NfCurrencyEntry::NfCurrencyEntry( const css::i18n::Currency & rCurr,
4210                                   const LocaleDataWrapper& rLocaleData, LanguageType eLang )
4211 {
4212     aSymbol         = rCurr.Symbol;
4213     aBankSymbol     = rCurr.BankSymbol;
4214     eLanguage       = eLang;
4215     nPositiveFormat = rLocaleData.getCurrPositiveFormat();
4216     nNegativeFormat = rLocaleData.getCurrNegativeFormat();
4217     nDigits         = rCurr.DecimalPlaces;
4218     cZeroChar       = rLocaleData.getCurrZeroChar();
4219 }
4220 
operator ==(const NfCurrencyEntry & r) const4221 bool NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
4222 {
4223     return aSymbol      == r.aSymbol
4224         && aBankSymbol  == r.aBankSymbol
4225         && eLanguage    == r.eLanguage
4226         ;
4227 }
4228 
BuildSymbolString(bool bBank,bool bWithoutExtension) const4229 OUString NfCurrencyEntry::BuildSymbolString(bool bBank,
4230                                             bool bWithoutExtension) const
4231 {
4232     OUStringBuffer aBuf("[$");
4233     if (bBank)
4234     {
4235         aBuf.append(aBankSymbol);
4236     }
4237     else
4238     {
4239         if ( aSymbol.indexOf( '-' ) >= 0 ||
4240              aSymbol.indexOf( ']' ) >= 0)
4241         {
4242             aBuf.append('"').append(aSymbol).append('"');
4243         }
4244         else
4245         {
4246             aBuf.append(aSymbol);
4247         }
4248         if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
4249         {
4250             sal_Int32 nLang = static_cast<sal_uInt16>(eLanguage);
4251             aBuf.append('-').append(OUString::number(nLang, 16).toAsciiUpperCase());
4252         }
4253     }
4254     aBuf.append(']');
4255     return aBuf.makeStringAndClear();
4256 }
4257 
Impl_BuildFormatStringNumChars(const LocaleDataWrapper & rLoc,sal_uInt16 nDecimalFormat) const4258 OUString NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper& rLoc,
4259                                                           sal_uInt16 nDecimalFormat) const
4260 {
4261     OUStringBuffer aBuf;
4262     aBuf.append('#').append(rLoc.getNumThousandSep()).append("##0");
4263     if (nDecimalFormat && nDigits)
4264     {
4265         aBuf.append(rLoc.getNumDecimalSep());
4266         sal_Unicode cDecimalChar = nDecimalFormat == 2 ? '-' : cZeroChar;
4267         for (sal_uInt16 i = 0; i < nDigits; ++i)
4268         {
4269             aBuf.append(cDecimalChar);
4270         }
4271     }
4272     return aBuf.makeStringAndClear();
4273 }
4274 
4275 
BuildPositiveFormatString(bool bBank,const LocaleDataWrapper & rLoc,sal_uInt16 nDecimalFormat) const4276 OUString NfCurrencyEntry::BuildPositiveFormatString(bool bBank, const LocaleDataWrapper& rLoc,
4277                                                     sal_uInt16 nDecimalFormat) const
4278 {
4279     OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4280     sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( rLoc.getCurrPositiveFormat(),
4281                                                                         nPositiveFormat, bBank );
4282     CompletePositiveFormatString(sBuf, bBank, nPosiForm);
4283     return sBuf.makeStringAndClear();
4284 }
4285 
4286 
BuildNegativeFormatString(bool bBank,const LocaleDataWrapper & rLoc,sal_uInt16 nDecimalFormat) const4287 OUString NfCurrencyEntry::BuildNegativeFormatString(bool bBank,
4288             const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
4289 {
4290     OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4291     sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc.getCurrNegativeFormat(),
4292                                                                         nNegativeFormat, bBank );
4293     CompleteNegativeFormatString(sBuf, bBank, nNegaForm);
4294     return sBuf.makeStringAndClear();
4295 }
4296 
4297 
CompletePositiveFormatString(OUStringBuffer & rStr,bool bBank,sal_uInt16 nPosiForm) const4298 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, bool bBank,
4299                                                    sal_uInt16 nPosiForm) const
4300 {
4301     OUString aSymStr = BuildSymbolString(bBank);
4302     NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
4303 }
4304 
4305 
CompleteNegativeFormatString(OUStringBuffer & rStr,bool bBank,sal_uInt16 nNegaForm) const4306 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr, bool bBank,
4307                                                    sal_uInt16 nNegaForm) const
4308 {
4309     OUString aSymStr = BuildSymbolString(bBank);
4310     NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
4311 }
4312 
4313 
4314 // static
CompletePositiveFormatString(OUStringBuffer & rStr,const OUString & rSymStr,sal_uInt16 nPositiveFormat)4315 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, const OUString& rSymStr,
4316                                                    sal_uInt16 nPositiveFormat)
4317 {
4318     switch( nPositiveFormat )
4319     {
4320         case 0:                                         // $1
4321             rStr.insert(0, rSymStr);
4322         break;
4323         case 1:                                         // 1$
4324             rStr.append(rSymStr);
4325         break;
4326         case 2:                                         // $ 1
4327         {
4328             rStr.insert(0, ' ');
4329             rStr.insert(0, rSymStr);
4330         }
4331         break;
4332         case 3:                                         // 1 $
4333         {
4334             rStr.append(' ');
4335             rStr.append(rSymStr);
4336         }
4337         break;
4338         default:
4339             SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4340         break;
4341     }
4342 }
4343 
4344 
4345 // static
CompleteNegativeFormatString(OUStringBuffer & rStr,const OUString & rSymStr,sal_uInt16 nNegativeFormat)4346 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr,
4347                                                    const OUString& rSymStr,
4348                                                    sal_uInt16 nNegativeFormat)
4349 {
4350     switch( nNegativeFormat )
4351     {
4352         case 0:                                         // ($1)
4353         {
4354             rStr.insert(0, rSymStr);
4355             rStr.insert(0, '(');
4356             rStr.append(')');
4357         }
4358         break;
4359         case 1:                                         // -$1
4360         {
4361             rStr.insert(0, rSymStr);
4362             rStr.insert(0, '-');
4363         }
4364         break;
4365         case 2:                                         // $-1
4366         {
4367             rStr.insert(0, '-');
4368             rStr.insert(0, rSymStr);
4369         }
4370         break;
4371         case 3:                                         // $1-
4372         {
4373             rStr.insert(0, rSymStr);
4374             rStr.append('-');
4375         }
4376         break;
4377         case 4:                                         // (1$)
4378         {
4379             rStr.insert(0, '(');
4380             rStr.append(rSymStr);
4381             rStr.append(')');
4382         }
4383         break;
4384         case 5:                                         // -1$
4385         {
4386             rStr.append(rSymStr);
4387             rStr.insert(0, '-');
4388         }
4389         break;
4390         case 6:                                         // 1-$
4391         {
4392             rStr.append('-');
4393             rStr.append(rSymStr);
4394         }
4395         break;
4396         case 7:                                         // 1$-
4397         {
4398             rStr.append(rSymStr);
4399             rStr.append('-');
4400         }
4401         break;
4402         case 8:                                         // -1 $
4403         {
4404             rStr.append(' ');
4405             rStr.append(rSymStr);
4406             rStr.insert(0, '-');
4407         }
4408         break;
4409         case 9:                                         // -$ 1
4410         {
4411             rStr.insert(0, ' ');
4412             rStr.insert(0, rSymStr);
4413             rStr.insert(0, '-');
4414         }
4415         break;
4416         case 10:                                        // 1 $-
4417         {
4418             rStr.append(' ');
4419             rStr.append(rSymStr);
4420             rStr.append('-');
4421         }
4422         break;
4423         case 11:                                        // $ -1
4424         {
4425             rStr.insert(0, " -");
4426             rStr.insert(0, rSymStr);
4427         }
4428         break;
4429         case 12 :                                       // $ 1-
4430         {
4431             rStr.insert(0, ' ');
4432             rStr.insert(0, rSymStr);
4433             rStr.append('-');
4434         }
4435         break;
4436         case 13 :                                       // 1- $
4437         {
4438             rStr.append('-');
4439             rStr.append(' ');
4440             rStr.append(rSymStr);
4441         }
4442         break;
4443         case 14 :                                       // ($ 1)
4444         {
4445             rStr.insert(0, ' ');
4446             rStr.insert(0, rSymStr);
4447             rStr.insert(0, '(');
4448             rStr.append(')');
4449         }
4450         break;
4451         case 15 :                                       // (1 $)
4452         {
4453             rStr.insert(0, '(');
4454             rStr.append(' ');
4455             rStr.append(rSymStr);
4456             rStr.append(')');
4457         }
4458         break;
4459         default:
4460             SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4461         break;
4462     }
4463 }
4464 
4465 
4466 // static
GetEffectivePositiveFormat(sal_uInt16 nIntlFormat,sal_uInt16 nCurrFormat,bool bBank)4467 sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat,
4468                                                         sal_uInt16 nCurrFormat, bool bBank )
4469 {
4470     if ( bBank )
4471     {
4472 #if NF_BANKSYMBOL_FIX_POSITION
4473         (void) nIntlFormat; // avoid warnings
4474         return 3;
4475 #else
4476         switch ( nIntlFormat )
4477         {
4478         case 0:                                         // $1
4479             nIntlFormat = 2;                            // $ 1
4480             break;
4481         case 1:                                         // 1$
4482             nIntlFormat = 3;                            // 1 $
4483             break;
4484         case 2:                                         // $ 1
4485             break;
4486         case 3:                                         // 1 $
4487             break;
4488         default:
4489             SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4490             break;
4491         }
4492         return nIntlFormat;
4493 #endif
4494     }
4495     else
4496         return nCurrFormat;
4497 }
4498 
4499 
4500 //! Call this only if nCurrFormat is really with parentheses!
lcl_MergeNegativeParenthesisFormat(sal_uInt16 nIntlFormat,sal_uInt16 nCurrFormat)4501 static sal_uInt16 lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat )
4502 {
4503     short nSign = 0;        // -1:=bracket 0:=left, 1:=middle, 2:=right
4504     switch ( nIntlFormat )
4505     {
4506     case 0:                                         // ($1)
4507     case 4:                                         // (1$)
4508     case 14 :                                       // ($ 1)
4509     case 15 :                                       // (1 $)
4510         return nCurrFormat;
4511     case 1:                                         // -$1
4512     case 5:                                         // -1$
4513     case 8:                                         // -1 $
4514     case 9:                                         // -$ 1
4515         nSign = 0;
4516         break;
4517     case 2:                                         // $-1
4518     case 6:                                         // 1-$
4519     case 11 :                                       // $ -1
4520     case 13 :                                       // 1- $
4521         nSign = 1;
4522         break;
4523     case 3:                                         // $1-
4524     case 7:                                         // 1$-
4525     case 10:                                        // 1 $-
4526     case 12 :                                       // $ 1-
4527         nSign = 2;
4528         break;
4529     default:
4530         SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4531         break;
4532     }
4533 
4534     switch ( nCurrFormat )
4535     {
4536     case 0:                                         // ($1)
4537         switch ( nSign )
4538         {
4539         case 0:
4540             return 1;                           // -$1
4541         case 1:
4542             return 2;                           // $-1
4543         case 2:
4544             return 3;                           // $1-
4545         }
4546         break;
4547     case 4:                                         // (1$)
4548         switch ( nSign )
4549         {
4550         case 0:
4551             return 5;                           // -1$
4552         case 1:
4553             return 6;                           // 1-$
4554         case 2:
4555             return 7;                           // 1$-
4556         }
4557         break;
4558     case 14 :                                       // ($ 1)
4559         switch ( nSign )
4560         {
4561         case 0:
4562             return 9;                           // -$ 1
4563         case 1:
4564             return 11;                          // $ -1
4565         case 2:
4566             return 12;                          // $ 1-
4567         }
4568         break;
4569     case 15 :                                       // (1 $)
4570         switch ( nSign )
4571         {
4572         case 0:
4573             return 8;                           // -1 $
4574         case 1:
4575             return 13;                          // 1- $
4576         case 2:
4577             return 10;                          // 1 $-
4578         }
4579         break;
4580     }
4581     return nCurrFormat;
4582 }
4583 
4584 
4585 // static
GetEffectiveNegativeFormat(sal_uInt16 nIntlFormat,sal_uInt16 nCurrFormat,bool bBank)4586 sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4587             sal_uInt16 nCurrFormat, bool bBank )
4588 {
4589     if ( bBank )
4590     {
4591 #if NF_BANKSYMBOL_FIX_POSITION
4592         return 8;
4593 #else
4594         switch ( nIntlFormat )
4595         {
4596         case 0:                                         // ($1)
4597 //          nIntlFormat = 14;                           // ($ 1)
4598             nIntlFormat = 9;                            // -$ 1
4599             break;
4600         case 1:                                         // -$1
4601             nIntlFormat = 9;                            // -$ 1
4602             break;
4603         case 2:                                         // $-1
4604             nIntlFormat = 11;                           // $ -1
4605             break;
4606         case 3:                                         // $1-
4607             nIntlFormat = 12;                           // $ 1-
4608             break;
4609         case 4:                                         // (1$)
4610 //          nIntlFormat = 15;                           // (1 $)
4611             nIntlFormat = 8;                            // -1 $
4612             break;
4613         case 5:                                         // -1$
4614             nIntlFormat = 8;                            // -1 $
4615             break;
4616         case 6:                                         // 1-$
4617             nIntlFormat = 13;                           // 1- $
4618             break;
4619         case 7:                                         // 1$-
4620             nIntlFormat = 10;                           // 1 $-
4621             break;
4622         case 8:                                         // -1 $
4623             break;
4624         case 9:                                         // -$ 1
4625             break;
4626         case 10:                                        // 1 $-
4627             break;
4628         case 11:                                        // $ -1
4629             break;
4630         case 12 :                                       // $ 1-
4631             break;
4632         case 13 :                                       // 1- $
4633             break;
4634         case 14 :                                       // ($ 1)
4635 //          nIntlFormat = 14;                           // ($ 1)
4636             nIntlFormat = 9;                            // -$ 1
4637             break;
4638         case 15 :                                       // (1 $)
4639 //          nIntlFormat = 15;                           // (1 $)
4640             nIntlFormat = 8;                            // -1 $
4641             break;
4642         default:
4643             SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4644             break;
4645         }
4646 #endif
4647     }
4648     else if ( nIntlFormat != nCurrFormat )
4649     {
4650         switch ( nCurrFormat )
4651         {
4652         case 0:                                         // ($1)
4653             nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4654                 nIntlFormat, nCurrFormat );
4655             break;
4656         case 1:                                         // -$1
4657             nIntlFormat = nCurrFormat;
4658             break;
4659         case 2:                                         // $-1
4660             nIntlFormat = nCurrFormat;
4661             break;
4662         case 3:                                         // $1-
4663             nIntlFormat = nCurrFormat;
4664             break;
4665         case 4:                                         // (1$)
4666             nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4667                 nIntlFormat, nCurrFormat );
4668             break;
4669         case 5:                                         // -1$
4670             nIntlFormat = nCurrFormat;
4671             break;
4672         case 6:                                         // 1-$
4673             nIntlFormat = nCurrFormat;
4674             break;
4675         case 7:                                         // 1$-
4676             nIntlFormat = nCurrFormat;
4677             break;
4678         case 8:                                         // -1 $
4679             nIntlFormat = nCurrFormat;
4680             break;
4681         case 9:                                         // -$ 1
4682             nIntlFormat = nCurrFormat;
4683             break;
4684         case 10:                                        // 1 $-
4685             nIntlFormat = nCurrFormat;
4686             break;
4687         case 11:                                        // $ -1
4688             nIntlFormat = nCurrFormat;
4689             break;
4690         case 12 :                                       // $ 1-
4691             nIntlFormat = nCurrFormat;
4692             break;
4693         case 13 :                                       // 1- $
4694             nIntlFormat = nCurrFormat;
4695             break;
4696         case 14 :                                       // ($ 1)
4697             nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4698                 nIntlFormat, nCurrFormat );
4699             break;
4700         case 15 :                                       // (1 $)
4701             nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4702                 nIntlFormat, nCurrFormat );
4703             break;
4704         default:
4705             SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4706             break;
4707         }
4708     }
4709     return nIntlFormat;
4710 }
4711 
GetKeywords(sal_uInt32 nKey)4712 const NfKeywordTable & SvNumberFormatter::GetKeywords( sal_uInt32 nKey )
4713 {
4714     osl::MutexGuard aGuard( GetInstanceMutex() );
4715     const SvNumberformat* pFormat = GetFormatEntry( nKey);
4716     if (pFormat)
4717         ChangeIntl( pFormat->GetLanguage());
4718     else
4719         ChangeIntl( IniLnge);
4720     return pFormatScanner->GetKeywords();
4721 }
4722 
GetEnglishKeywords() const4723 const NfKeywordTable & SvNumberFormatter::GetEnglishKeywords() const
4724 {
4725     return ImpSvNumberformatScan::GetEnglishKeywords();
4726 }
4727 
GetStandardColors() const4728 const std::vector<Color> & SvNumberFormatter::GetStandardColors() const
4729 {
4730     return ImpSvNumberformatScan::GetStandardColors();
4731 }
4732 
GetMaxDefaultColors() const4733 size_t SvNumberFormatter::GetMaxDefaultColors() const
4734 {
4735     return ImpSvNumberformatScan::GetMaxDefaultColors();
4736 }
4737 
4738 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4739