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