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