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