Line data Source code
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 <string.h>
21 : #include <stdio.h>
22 : #include <string>
23 :
24 : #include <unotools/localedatawrapper.hxx>
25 : #include <unotools/numberformatcodewrapper.hxx>
26 : #include <unotools/calendarwrapper.hxx>
27 : #include <unotools/digitgroupingiterator.hxx>
28 : #include <tools/debug.hxx>
29 : #include <i18nlangtag/languagetag.hxx>
30 :
31 : #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
32 : #include <com/sun/star/i18n/KNumberFormatType.hpp>
33 : #include <com/sun/star/i18n/LocaleData.hpp>
34 : #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
35 : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
36 : #include <com/sun/star/i18n/NumberFormatIndex.hpp>
37 :
38 : #include <comphelper/processfactory.hxx>
39 : #include <rtl/instance.hxx>
40 : #include <rtl/ustrbuf.hxx>
41 : #include <sal/macros.h>
42 :
43 : static const int nDateFormatInvalid = -1;
44 : static const sal_uInt16 nCurrFormatInvalid = 0xffff;
45 : static const sal_uInt16 nCurrFormatDefault = 0;
46 :
47 : using namespace ::com::sun::star;
48 : using namespace ::com::sun::star::i18n;
49 : using namespace ::com::sun::star::uno;
50 :
51 : namespace
52 : {
53 : struct InstalledLocales
54 : : public rtl::Static<
55 : uno::Sequence< lang::Locale >, InstalledLocales >
56 : {};
57 :
58 : struct InstalledLanguageTypes
59 : : public rtl::Static<
60 : uno::Sequence< sal_uInt16 >, InstalledLanguageTypes >
61 : {};
62 : }
63 :
64 : sal_uInt8 LocaleDataWrapper::nLocaleDataChecking = 0;
65 :
66 16762 : LocaleDataWrapper::LocaleDataWrapper(
67 : const Reference< uno::XComponentContext > & rxContext,
68 : const LanguageTag& rLanguageTag
69 : )
70 : :
71 : m_xContext( rxContext ),
72 : xLD( LocaleData::create(rxContext) ),
73 : maLanguageTag( rLanguageTag ),
74 : bLocaleDataItemValid( false ),
75 16762 : bReservedWordValid( false )
76 : {
77 16762 : invalidateData();
78 16762 : }
79 :
80 7148 : LocaleDataWrapper::LocaleDataWrapper(
81 : const LanguageTag& rLanguageTag
82 : )
83 : :
84 : m_xContext( comphelper::getProcessComponentContext() ),
85 : xLD( LocaleData::create(m_xContext) ),
86 : maLanguageTag( rLanguageTag ),
87 : bLocaleDataItemValid( false ),
88 7148 : bReservedWordValid( false )
89 : {
90 7148 : invalidateData();
91 7148 : }
92 :
93 23720 : LocaleDataWrapper::~LocaleDataWrapper()
94 : {
95 23720 : }
96 :
97 16742 : void LocaleDataWrapper::setLanguageTag( const LanguageTag& rLanguageTag )
98 : {
99 16742 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nCriticalChange );
100 16742 : maLanguageTag = rLanguageTag;
101 16742 : invalidateData();
102 16742 : }
103 :
104 1372 : const LanguageTag& LocaleDataWrapper::getLanguageTag() const
105 : {
106 1372 : ::utl::ReadWriteGuard aGuard( aMutex );
107 1372 : return maLanguageTag;
108 : }
109 :
110 173470 : const ::com::sun::star::lang::Locale& LocaleDataWrapper::getMyLocale() const
111 : {
112 173470 : ::utl::ReadWriteGuard aGuard( aMutex );
113 173470 : return maLanguageTag.getLocale();
114 : }
115 :
116 40652 : void LocaleDataWrapper::invalidateData()
117 : {
118 40652 : aCurrSymbol = "";
119 40652 : aCurrBankSymbol = "";
120 40652 : nDateFormat = nLongDateFormat = nDateFormatInvalid;
121 40652 : nCurrPositiveFormat = nCurrNegativeFormat = nCurrDigits = nCurrFormatInvalid;
122 40652 : if ( bLocaleDataItemValid )
123 : {
124 32364 : for (sal_Int32 j=0; j<LocaleItem::COUNT; ++j)
125 30566 : aLocaleItem[j] = "";
126 1798 : bLocaleDataItemValid = false;
127 : }
128 40652 : if ( bReservedWordValid )
129 : {
130 1066 : for ( sal_Int16 j=0; j<reservedWords::COUNT; ++j )
131 984 : aReservedWord[j] = "";
132 82 : bReservedWordValid = false;
133 : }
134 40652 : xDefaultCalendar.reset();
135 40652 : if (aGrouping.getLength())
136 82 : aGrouping[0] = 0;
137 40652 : if (aDateAcceptancePatterns.getLength())
138 20 : aDateAcceptancePatterns = Sequence<OUString>();
139 : // dummies
140 40652 : cCurrZeroChar = '0';
141 40652 : }
142 :
143 : /* FIXME-BCP47: locale data should provide a language tag instead that could be
144 : * passed on. */
145 70816 : ::com::sun::star::i18n::LanguageCountryInfo LocaleDataWrapper::getLanguageCountryInfo() const
146 : {
147 : try
148 : {
149 70816 : return xLD->getLanguageCountryInfo( getMyLocale() );
150 : }
151 0 : catch (const Exception& e)
152 : {
153 : SAL_WARN( "unotools.i18n", "getLanguageCountryInfo: Exception caught " << e.Message );
154 : }
155 0 : return ::com::sun::star::i18n::LanguageCountryInfo();
156 : }
157 :
158 11865 : ::com::sun::star::i18n::LocaleDataItem LocaleDataWrapper::getLocaleItem() const
159 : {
160 : try
161 : {
162 11865 : return xLD->getLocaleItem( getMyLocale() );
163 : }
164 0 : catch (const Exception& e)
165 : {
166 : SAL_WARN( "unotools.i18n", "getLocaleItem: Exception caught " << e.Message );
167 : }
168 0 : return ::com::sun::star::i18n::LocaleDataItem();
169 : }
170 :
171 61126 : ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 > LocaleDataWrapper::getAllCurrencies() const
172 : {
173 : try
174 : {
175 61126 : return xLD->getAllCurrencies2( getMyLocale() );
176 : }
177 0 : catch (const Exception& e)
178 : {
179 : SAL_WARN( "unotools.i18n", "getAllCurrencies: Exception caught " << e.Message );
180 : }
181 0 : return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >(0);
182 : }
183 :
184 0 : ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::FormatElement > LocaleDataWrapper::getAllFormats() const
185 : {
186 : try
187 : {
188 0 : return xLD->getAllFormats( getMyLocale() );
189 : }
190 0 : catch (const Exception& e)
191 : {
192 : SAL_WARN( "unotools.i18n", "getAllFormats: Exception caught " << e.Message );
193 : }
194 0 : return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::FormatElement >(0);
195 : }
196 :
197 12341 : ::com::sun::star::i18n::ForbiddenCharacters LocaleDataWrapper::getForbiddenCharacters() const
198 : {
199 : try
200 : {
201 12341 : return xLD->getForbiddenCharacters( getMyLocale() );
202 : }
203 0 : catch (const Exception& e)
204 : {
205 : SAL_WARN( "unotools.i18n", "getForbiddenCharacters: Exception caught " << e.Message );
206 : }
207 0 : return ::com::sun::star::i18n::ForbiddenCharacters();
208 : }
209 :
210 1623 : ::com::sun::star::uno::Sequence< OUString > LocaleDataWrapper::getReservedWord() const
211 : {
212 : try
213 : {
214 1623 : return xLD->getReservedWord( getMyLocale() );
215 : }
216 0 : catch ( const Exception& e )
217 : {
218 : SAL_WARN( "unotools.i18n", "getReservedWord: Exception caught " << e.Message );
219 : }
220 0 : return ::com::sun::star::uno::Sequence< OUString >(0);
221 : }
222 :
223 62 : ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > LocaleDataWrapper::getAllInstalledLocaleNames() const
224 : {
225 62 : uno::Sequence< lang::Locale > &rInstalledLocales = InstalledLocales::get();
226 :
227 62 : if ( rInstalledLocales.getLength() )
228 0 : return rInstalledLocales;
229 :
230 : try
231 : {
232 62 : rInstalledLocales = xLD->getAllInstalledLocaleNames();
233 : }
234 0 : catch ( const Exception& e )
235 : {
236 : SAL_WARN( "unotools.i18n", "getAllInstalledLocaleNames: Exception caught " << e.Message );
237 : }
238 62 : return rInstalledLocales;
239 : }
240 :
241 : // --- Impl and helpers ----------------------------------------------------
242 :
243 : // static
244 62 : ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > LocaleDataWrapper::getInstalledLocaleNames()
245 : {
246 : const uno::Sequence< lang::Locale > &rInstalledLocales =
247 62 : InstalledLocales::get();
248 :
249 62 : if ( !rInstalledLocales.getLength() )
250 : {
251 62 : LocaleDataWrapper aLDW( ::comphelper::getProcessComponentContext(), LanguageTag( LANGUAGE_SYSTEM) );
252 62 : aLDW.getAllInstalledLocaleNames();
253 : }
254 62 : return rInstalledLocales;
255 : }
256 :
257 : // static
258 0 : ::com::sun::star::uno::Sequence< sal_uInt16 > LocaleDataWrapper::getInstalledLanguageTypes()
259 : {
260 : uno::Sequence< sal_uInt16 > &rInstalledLanguageTypes =
261 0 : InstalledLanguageTypes::get();
262 :
263 0 : if ( rInstalledLanguageTypes.getLength() )
264 0 : return rInstalledLanguageTypes;
265 :
266 : ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
267 0 : getInstalledLocaleNames();
268 0 : sal_Int32 nCount = xLoc.getLength();
269 0 : ::com::sun::star::uno::Sequence< sal_uInt16 > xLang( nCount );
270 0 : sal_Int32 nLanguages = 0;
271 0 : for ( sal_Int32 i=0; i<nCount; i++ )
272 : {
273 0 : LanguageTag aLanguageTag( xLoc[i] );
274 0 : OUString aDebugLocale;
275 0 : if (areChecksEnabled())
276 : {
277 0 : aDebugLocale = aLanguageTag.getBcp47( false);
278 : }
279 :
280 0 : LanguageType eLang = aLanguageTag.getLanguageType( false);
281 0 : if (areChecksEnabled() && eLang == LANGUAGE_DONTKNOW)
282 : {
283 0 : OUStringBuffer aMsg("ConvertIsoNamesToLanguage: unknown MS-LCID for locale\n");
284 0 : aMsg.append(aDebugLocale);
285 0 : outputCheckMessage(aMsg.makeStringAndClear());
286 : }
287 :
288 0 : switch ( eLang )
289 : {
290 : case LANGUAGE_NORWEGIAN : // no_NO, not Bokmal (nb_NO), not Nynorsk (nn_NO)
291 0 : eLang = LANGUAGE_DONTKNOW; // don't offer "Unknown" language
292 0 : break;
293 : }
294 0 : if ( eLang != LANGUAGE_DONTKNOW )
295 : {
296 0 : LanguageTag aBackLanguageTag( eLang);
297 0 : if ( aLanguageTag != aBackLanguageTag )
298 : {
299 : // In checks, exclude known problems because no MS-LCID defined
300 : // and default for Language found.
301 0 : if ( areChecksEnabled()
302 0 : && aDebugLocale != "ar-SD" // Sudan/ar
303 0 : && aDebugLocale != "en-CB" // Caribbean is not a country
304 : // && aDebugLocale != "en-BG" // ?!? Bulgaria/en
305 : // && aDebugLocale != "es-BR" // ?!? Brazil/es
306 : )
307 : {
308 0 : OUStringBuffer aMsg("ConvertIsoNamesToLanguage/ConvertLanguageToIsoNames: ambiguous locale (MS-LCID?)\n");
309 0 : aMsg.append(aDebugLocale);
310 0 : aMsg.appendAscii(" -> 0x");
311 0 : aMsg.append(static_cast<sal_Int32>(eLang), 16);
312 0 : aMsg.appendAscii(" -> ");
313 0 : aMsg.append(aBackLanguageTag.getBcp47());
314 0 : outputCheckMessage( aMsg.makeStringAndClear() );
315 : }
316 0 : eLang = LANGUAGE_DONTKNOW;
317 0 : }
318 : }
319 0 : if ( eLang != LANGUAGE_DONTKNOW )
320 0 : xLang[ nLanguages++ ] = eLang;
321 0 : }
322 0 : if ( nLanguages < nCount )
323 0 : xLang.realloc( nLanguages );
324 0 : rInstalledLanguageTypes = xLang;
325 :
326 0 : return rInstalledLanguageTypes;
327 : }
328 :
329 6895334 : const OUString& LocaleDataWrapper::getOneLocaleItem( sal_Int16 nItem ) const
330 : {
331 6895334 : ::utl::ReadWriteGuard aGuard( aMutex );
332 6895334 : if ( nItem >= LocaleItem::COUNT )
333 : {
334 : SAL_WARN( "unotools.i18n", "getOneLocaleItem: bounds" );
335 0 : return aLocaleItem[0];
336 : }
337 6895334 : if (aLocaleItem[nItem].isEmpty())
338 : { // no cached content
339 23752 : aGuard.changeReadToWrite();
340 23752 : ((LocaleDataWrapper*)this)->getOneLocaleItemImpl( nItem );
341 : }
342 6895334 : return aLocaleItem[nItem];
343 : }
344 :
345 23752 : void LocaleDataWrapper::getOneLocaleItemImpl( sal_Int16 nItem )
346 : {
347 23752 : if ( !bLocaleDataItemValid )
348 : {
349 10512 : aLocaleDataItem = getLocaleItem();
350 10512 : bLocaleDataItemValid = true;
351 : }
352 23752 : switch ( nItem )
353 : {
354 : case LocaleItem::DATE_SEPARATOR :
355 1685 : aLocaleItem[nItem] = aLocaleDataItem.dateSeparator;
356 1685 : break;
357 : case LocaleItem::THOUSAND_SEPARATOR :
358 10117 : aLocaleItem[nItem] = aLocaleDataItem.thousandSeparator;
359 10117 : break;
360 : case LocaleItem::DECIMAL_SEPARATOR :
361 8276 : aLocaleItem[nItem] = aLocaleDataItem.decimalSeparator;
362 8276 : break;
363 : case LocaleItem::TIME_SEPARATOR :
364 1675 : aLocaleItem[nItem] = aLocaleDataItem.timeSeparator;
365 1675 : break;
366 : case LocaleItem::TIME_100SEC_SEPARATOR :
367 1589 : aLocaleItem[nItem] = aLocaleDataItem.time100SecSeparator;
368 1589 : break;
369 : case LocaleItem::LIST_SEPARATOR :
370 70 : aLocaleItem[nItem] = aLocaleDataItem.listSeparator;
371 70 : break;
372 : case LocaleItem::SINGLE_QUOTATION_START :
373 0 : aLocaleItem[nItem] = aLocaleDataItem.quotationStart;
374 0 : break;
375 : case LocaleItem::SINGLE_QUOTATION_END :
376 34 : aLocaleItem[nItem] = aLocaleDataItem.quotationEnd;
377 34 : break;
378 : case LocaleItem::DOUBLE_QUOTATION_START :
379 0 : aLocaleItem[nItem] = aLocaleDataItem.doubleQuotationStart;
380 0 : break;
381 : case LocaleItem::DOUBLE_QUOTATION_END :
382 0 : aLocaleItem[nItem] = aLocaleDataItem.doubleQuotationEnd;
383 0 : break;
384 : case LocaleItem::MEASUREMENT_SYSTEM :
385 170 : aLocaleItem[nItem] = aLocaleDataItem.measurementSystem;
386 170 : break;
387 : case LocaleItem::TIME_AM :
388 42 : aLocaleItem[nItem] = aLocaleDataItem.timeAM;
389 42 : break;
390 : case LocaleItem::TIME_PM :
391 42 : aLocaleItem[nItem] = aLocaleDataItem.timePM;
392 42 : break;
393 : case LocaleItem::LONG_DATE_DAY_OF_WEEK_SEPARATOR :
394 24 : aLocaleItem[nItem] = aLocaleDataItem.LongDateDayOfWeekSeparator;
395 24 : break;
396 : case LocaleItem::LONG_DATE_DAY_SEPARATOR :
397 14 : aLocaleItem[nItem] = aLocaleDataItem.LongDateDaySeparator;
398 14 : break;
399 : case LocaleItem::LONG_DATE_MONTH_SEPARATOR :
400 14 : aLocaleItem[nItem] = aLocaleDataItem.LongDateMonthSeparator;
401 14 : break;
402 : case LocaleItem::LONG_DATE_YEAR_SEPARATOR :
403 0 : aLocaleItem[nItem] = aLocaleDataItem.LongDateYearSeparator;
404 0 : break;
405 : default:
406 : SAL_WARN( "unotools.i18n", "getOneLocaleItemImpl: which one?" );
407 : }
408 23752 : }
409 :
410 3252 : void LocaleDataWrapper::getOneReservedWordImpl( sal_Int16 nWord )
411 : {
412 3252 : if ( !bReservedWordValid )
413 : {
414 1623 : aReservedWordSeq = getReservedWord();
415 1623 : bReservedWordValid = true;
416 : }
417 : DBG_ASSERT( nWord < aReservedWordSeq.getLength(), "getOneReservedWordImpl: which one?" );
418 3252 : if ( nWord < aReservedWordSeq.getLength() )
419 3252 : aReservedWord[nWord] = aReservedWordSeq[nWord];
420 3252 : }
421 :
422 68674 : const OUString& LocaleDataWrapper::getOneReservedWord( sal_Int16 nWord ) const
423 : {
424 68674 : ::utl::ReadWriteGuard aGuard( aMutex );
425 68674 : if ( nWord < 0 || nWord >= reservedWords::COUNT )
426 : {
427 : SAL_WARN( "unotools.i18n", "getOneReservedWord: bounds" );
428 0 : nWord = reservedWords::FALSE_WORD;
429 : }
430 68674 : if (aReservedWord[nWord].isEmpty())
431 : { // no cached content
432 3252 : aGuard.changeReadToWrite();
433 3252 : ((LocaleDataWrapper*)this)->getOneReservedWordImpl( nWord );
434 : }
435 68674 : return aReservedWord[nWord];
436 : }
437 :
438 23962 : MeasurementSystem LocaleDataWrapper::mapMeasurementStringToEnum( const OUString& rMS ) const
439 : {
440 : //! TODO: could be cached too
441 23962 : if ( rMS.equalsIgnoreAsciiCase( "metric" ) )
442 0 : return MEASURE_METRIC;
443 : //! TODO: other measurement systems? => extend enum MeasurementSystem
444 23962 : return MEASURE_US;
445 : }
446 :
447 0 : void LocaleDataWrapper::getDefaultCalendarImpl()
448 : {
449 0 : if (!xDefaultCalendar)
450 : {
451 0 : Sequence< Calendar2 > xCals = getAllCalendars();
452 0 : sal_Int32 nCount = xCals.getLength();
453 0 : sal_Int32 nDef = 0;
454 0 : if (nCount > 1)
455 : {
456 0 : const Calendar2* pArr = xCals.getArray();
457 0 : for (sal_Int32 i=0; i<nCount; ++i)
458 : {
459 0 : if (pArr[i].Default)
460 : {
461 0 : nDef = i;
462 0 : break;
463 : }
464 : }
465 : }
466 0 : xDefaultCalendar.reset( new Calendar2( xCals[nDef]));
467 : }
468 0 : }
469 :
470 0 : const ::boost::shared_ptr< ::com::sun::star::i18n::Calendar2 > LocaleDataWrapper::getDefaultCalendar() const
471 : {
472 0 : ::utl::ReadWriteGuard aGuard( aMutex );
473 0 : if (!xDefaultCalendar)
474 : { // no cached content
475 0 : aGuard.changeReadToWrite();
476 0 : ((LocaleDataWrapper*)this)->getDefaultCalendarImpl();
477 : }
478 0 : return xDefaultCalendar;
479 : }
480 :
481 0 : const ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem2 > LocaleDataWrapper::getDefaultCalendarDays() const
482 : {
483 0 : return getDefaultCalendar()->Days;
484 : }
485 :
486 0 : const ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem2 > LocaleDataWrapper::getDefaultCalendarMonths() const
487 : {
488 0 : return getDefaultCalendar()->Months;
489 : }
490 :
491 : // --- currencies -----------------------------------------------------
492 :
493 15280 : const OUString& LocaleDataWrapper::getCurrSymbol() const
494 : {
495 15280 : ::utl::ReadWriteGuard aGuard( aMutex );
496 15280 : if (aCurrSymbol.isEmpty())
497 : {
498 15112 : aGuard.changeReadToWrite();
499 15112 : ((LocaleDataWrapper*)this)->getCurrSymbolsImpl();
500 : }
501 15280 : return aCurrSymbol;
502 : }
503 :
504 92 : const OUString& LocaleDataWrapper::getCurrBankSymbol() const
505 : {
506 92 : ::utl::ReadWriteGuard aGuard( aMutex );
507 92 : if (aCurrBankSymbol.isEmpty())
508 : {
509 30 : aGuard.changeReadToWrite();
510 30 : ((LocaleDataWrapper*)this)->getCurrSymbolsImpl();
511 : }
512 92 : return aCurrBankSymbol;
513 : }
514 :
515 22276 : sal_uInt16 LocaleDataWrapper::getCurrPositiveFormat() const
516 : {
517 22276 : ::utl::ReadWriteGuard aGuard( aMutex );
518 22276 : if ( nCurrPositiveFormat == nCurrFormatInvalid )
519 : {
520 15090 : aGuard.changeReadToWrite();
521 15090 : ((LocaleDataWrapper*)this)->getCurrFormatsImpl();
522 : }
523 22276 : return nCurrPositiveFormat;
524 : }
525 :
526 22256 : sal_uInt16 LocaleDataWrapper::getCurrNegativeFormat() const
527 : {
528 22256 : ::utl::ReadWriteGuard aGuard( aMutex );
529 22256 : if ( nCurrNegativeFormat == nCurrFormatInvalid )
530 : {
531 0 : aGuard.changeReadToWrite();
532 0 : ((LocaleDataWrapper*)this)->getCurrFormatsImpl();
533 : }
534 22256 : return nCurrNegativeFormat;
535 : }
536 :
537 62 : sal_uInt16 LocaleDataWrapper::getCurrDigits() const
538 : {
539 62 : ::utl::ReadWriteGuard aGuard( aMutex );
540 62 : if ( nCurrDigits == nCurrFormatInvalid )
541 : {
542 0 : aGuard.changeReadToWrite();
543 0 : ((LocaleDataWrapper*)this)->getCurrSymbolsImpl();
544 : }
545 62 : return nCurrDigits;
546 : }
547 :
548 15142 : void LocaleDataWrapper::getCurrSymbolsImpl()
549 : {
550 15142 : Sequence< Currency2 > aCurrSeq = getAllCurrencies();
551 15142 : sal_Int32 nCnt = aCurrSeq.getLength();
552 15142 : Currency2 const * const pCurrArr = aCurrSeq.getArray();
553 : sal_Int32 nElem;
554 15824 : for ( nElem = 0; nElem < nCnt; nElem++ )
555 : {
556 15824 : if ( pCurrArr[nElem].Default )
557 15142 : break;
558 : }
559 15142 : if ( nElem >= nCnt )
560 : {
561 0 : if (areChecksEnabled())
562 : {
563 0 : OUString aMsg( "LocaleDataWrapper::getCurrSymbolsImpl: no default currency" );
564 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
565 : }
566 0 : nElem = 0;
567 0 : if ( nElem >= nCnt )
568 : {
569 0 : if (areChecksEnabled())
570 0 : outputCheckMessage(OUString("LocaleDataWrapper::getCurrSymbolsImpl: no currency at all, using ShellsAndPebbles"));
571 0 : aCurrSymbol = "ShellsAndPebbles";
572 0 : aCurrBankSymbol = aCurrSymbol;
573 0 : nCurrPositiveFormat = nCurrNegativeFormat = nCurrFormatDefault;
574 0 : nCurrDigits = 2;
575 15142 : return;
576 : }
577 : }
578 15142 : aCurrSymbol = pCurrArr[nElem].Symbol;
579 15142 : aCurrBankSymbol = pCurrArr[nElem].BankSymbol;
580 15142 : nCurrDigits = pCurrArr[nElem].DecimalPlaces;
581 : }
582 :
583 30180 : void LocaleDataWrapper::scanCurrFormatImpl( const OUString& rCode,
584 : sal_Int32 nStart, sal_Int32& nSign, sal_Int32& nPar,
585 : sal_Int32& nNum, sal_Int32& nBlank, sal_Int32& nSym )
586 : {
587 30180 : nSign = nPar = nNum = nBlank = nSym = -1;
588 30180 : const sal_Unicode* const pStr = rCode.getStr();
589 30180 : const sal_Unicode* const pStop = pStr + rCode.getLength();
590 30180 : const sal_Unicode* p = pStr + nStart;
591 30180 : int nInSection = 0;
592 30180 : bool bQuote = false;
593 694316 : while ( p < pStop )
594 : {
595 633956 : if ( bQuote )
596 : {
597 0 : if ( *p == '"' && *(p-1) != '\\' )
598 0 : bQuote = false;
599 : }
600 : else
601 : {
602 633956 : switch ( *p )
603 : {
604 : case '"' :
605 0 : if ( pStr == p || *(p-1) != '\\' )
606 0 : bQuote = true;
607 0 : break;
608 : case '-' :
609 44340 : if (!nInSection && nSign == -1)
610 14160 : nSign = p - pStr;
611 44340 : break;
612 : case '(' :
613 930 : if (!nInSection && nPar == -1)
614 930 : nPar = p - pStr;
615 930 : break;
616 : case '0' :
617 : case '#' :
618 189436 : if (!nInSection && nNum == -1)
619 30180 : nNum = p - pStr;
620 189436 : break;
621 : case '[' :
622 45270 : nInSection++;
623 45270 : break;
624 : case ']' :
625 45270 : if ( nInSection )
626 : {
627 45270 : nInSection--;
628 45270 : if (!nInSection && nBlank == -1
629 38078 : && nSym != -1 && p < pStop-1 && *(p+1) == ' ' )
630 7068 : nBlank = p - pStr + 1;
631 : }
632 45270 : break;
633 : case '$' :
634 34568 : if (nSym == -1 && nInSection && *(p-1) == '[')
635 : {
636 30180 : nSym = p - pStr + 1;
637 30180 : if (nNum != -1 && *(p-2) == ' ')
638 7192 : nBlank = p - pStr - 2;
639 : }
640 34568 : break;
641 : case ';' :
642 15090 : if ( !nInSection )
643 15090 : p = pStop;
644 15090 : break;
645 : default:
646 259052 : if (!nInSection && nSym == -1 && rCode.match(aCurrSymbol, (sal_Int32)(p - pStr)))
647 : { // currency symbol not surrounded by [$...]
648 0 : nSym = p - pStr;
649 0 : if (nBlank == -1 && pStr < p && *(p-1) == ' ')
650 0 : nBlank = p - pStr - 1;
651 0 : p += aCurrSymbol.getLength() - 1;
652 0 : if (nBlank == -1 && p < pStop-2 && *(p+2) == ' ')
653 0 : nBlank = p - pStr + 2;
654 : }
655 : }
656 : }
657 633956 : p++;
658 : }
659 30180 : }
660 :
661 15090 : void LocaleDataWrapper::getCurrFormatsImpl()
662 : {
663 15090 : NumberFormatCodeWrapper aNumberFormatCode( m_xContext, getMyLocale() );
664 : uno::Sequence< NumberFormatCode > aFormatSeq
665 30180 : = aNumberFormatCode.getAllFormatCode( KNumberFormatUsage::CURRENCY );
666 15090 : sal_Int32 nCnt = aFormatSeq.getLength();
667 15090 : if ( !nCnt )
668 : { // bad luck
669 0 : if (areChecksEnabled())
670 : {
671 0 : OUString aMsg( "LocaleDataWrapper::getCurrFormatsImpl: no currency formats" );
672 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
673 : }
674 0 : nCurrPositiveFormat = nCurrNegativeFormat = nCurrFormatDefault;
675 15090 : return;
676 : }
677 : // find a negative code (medium preferred) and a default (medium preferred) (not necessarily the same)
678 15090 : NumberFormatCode const * const pFormatArr = aFormatSeq.getArray();
679 : sal_Int32 nElem, nDef, nNeg, nMedium;
680 15090 : nDef = nNeg = nMedium = -1;
681 108902 : for ( nElem = 0; nElem < nCnt; nElem++ )
682 : {
683 93812 : if ( pFormatArr[nElem].Type == KNumberFormatType::MEDIUM )
684 : {
685 77458 : if ( pFormatArr[nElem].Default )
686 : {
687 15090 : nDef = nElem;
688 15090 : nMedium = nElem;
689 15090 : if ( pFormatArr[nElem].Code.indexOf( ';' ) >= 0 )
690 15090 : nNeg = nElem;
691 : }
692 : else
693 : {
694 62368 : if ( (nNeg == -1 || nMedium == -1) && pFormatArr[nElem].Code.indexOf( ';' ) >= 0 )
695 14718 : nNeg = nElem;
696 62368 : if ( nMedium == -1 )
697 14718 : nMedium = nElem;
698 : }
699 : }
700 : else
701 : {
702 16354 : if ( nDef == -1 && pFormatArr[nElem].Default )
703 14594 : nDef = nElem;
704 16354 : if ( nNeg == -1 && pFormatArr[nElem].Code.indexOf( ';' ) >= 0 )
705 14594 : nNeg = nElem;
706 : }
707 : }
708 :
709 : // make sure it's loaded
710 15090 : getCurrSymbol();
711 :
712 : sal_Int32 nSign, nPar, nNum, nBlank, nSym;
713 :
714 : // positive format
715 15090 : nElem = (nDef >= 0 ? nDef : (nNeg >= 0 ? nNeg : 0));
716 15090 : scanCurrFormatImpl( pFormatArr[nElem].Code, 0, nSign, nPar, nNum, nBlank, nSym );
717 15090 : if (areChecksEnabled() && (nNum == -1 || nSym == -1))
718 : {
719 0 : OUString aMsg( "LocaleDataWrapper::getCurrFormatsImpl: CurrPositiveFormat?" );
720 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
721 : }
722 15090 : if (nBlank == -1)
723 : {
724 6844 : if ( nSym < nNum )
725 5418 : nCurrPositiveFormat = 0; // $1
726 : else
727 1426 : nCurrPositiveFormat = 1; // 1$
728 : }
729 : else
730 : {
731 8246 : if ( nSym < nNum )
732 4650 : nCurrPositiveFormat = 2; // $ 1
733 : else
734 3596 : nCurrPositiveFormat = 3; // 1 $
735 : }
736 :
737 : // negative format
738 15090 : if ( nNeg < 0 )
739 0 : nCurrNegativeFormat = nCurrFormatDefault;
740 : else
741 : {
742 15090 : const OUString& rCode = pFormatArr[nNeg].Code;
743 15090 : sal_Int32 nDelim = rCode.indexOf(';');
744 15090 : scanCurrFormatImpl( rCode, nDelim+1, nSign, nPar, nNum, nBlank, nSym );
745 15090 : if (areChecksEnabled() && (nNum == -1 || nSym == -1 || (nPar == -1 && nSign == -1)))
746 : {
747 0 : OUString aMsg( "LocaleDataWrapper::getCurrFormatsImpl: CurrNegativeFormat?" );
748 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
749 : }
750 : // NOTE: one of nPar or nSign are allowed to be -1
751 15090 : if (nBlank == -1)
752 : {
753 9076 : if ( nSym < nNum )
754 : {
755 7650 : if ( -1 < nPar && nPar < nSym )
756 806 : nCurrNegativeFormat = 0; // ($1)
757 6844 : else if ( -1 < nSign && nSign < nSym )
758 4240 : nCurrNegativeFormat = 1; // -$1
759 2604 : else if ( nNum < nSign )
760 0 : nCurrNegativeFormat = 3; // $1-
761 : else
762 2604 : nCurrNegativeFormat = 2; // $-1
763 : }
764 : else
765 : {
766 1426 : if ( -1 < nPar && nPar < nNum )
767 0 : nCurrNegativeFormat = 4; // (1$)
768 1426 : else if ( -1 < nSign && nSign < nNum )
769 1426 : nCurrNegativeFormat = 5; // -1$
770 0 : else if ( nSym < nSign )
771 0 : nCurrNegativeFormat = 7; // 1$-
772 : else
773 0 : nCurrNegativeFormat = 6; // 1-$
774 : }
775 : }
776 : else
777 : {
778 6014 : if ( nSym < nNum )
779 : {
780 2418 : if ( -1 < nPar && nPar < nSym )
781 124 : nCurrNegativeFormat = 14; // ($ 1)
782 2294 : else if ( -1 < nSign && nSign < nSym )
783 1116 : nCurrNegativeFormat = 9; // -$ 1
784 1178 : else if ( nNum < nSign )
785 558 : nCurrNegativeFormat = 12; // $ 1-
786 : else
787 620 : nCurrNegativeFormat = 11; // $ -1
788 : }
789 : else
790 : {
791 3596 : if ( -1 < nPar && nPar < nNum )
792 0 : nCurrNegativeFormat = 15; // (1 $)
793 3596 : else if ( -1 < nSign && nSign < nNum )
794 3596 : nCurrNegativeFormat = 8; // -1 $
795 0 : else if ( nSym < nSign )
796 0 : nCurrNegativeFormat = 10; // 1 $-
797 : else
798 0 : nCurrNegativeFormat = 13; // 1- $
799 : }
800 : }
801 15090 : }
802 : }
803 :
804 : // --- date -----------------------------------------------------------
805 :
806 1842 : DateFormat LocaleDataWrapper::getDateFormat() const
807 : {
808 1842 : ::utl::ReadWriteGuard aGuard( aMutex );
809 1842 : if ( nDateFormat == nDateFormatInvalid )
810 : {
811 106 : aGuard.changeReadToWrite();
812 106 : ((LocaleDataWrapper*)this)->getDateFormatsImpl();
813 : }
814 1842 : return (DateFormat) nDateFormat;
815 : }
816 :
817 238 : DateFormat LocaleDataWrapper::getLongDateFormat() const
818 : {
819 238 : ::utl::ReadWriteGuard aGuard( aMutex );
820 238 : if ( nLongDateFormat == nDateFormatInvalid )
821 : {
822 4 : aGuard.changeReadToWrite();
823 4 : ((LocaleDataWrapper*)this)->getDateFormatsImpl();
824 : }
825 238 : return (DateFormat) nLongDateFormat;
826 : }
827 :
828 220 : DateFormat LocaleDataWrapper::scanDateFormatImpl( const OUString& rCode )
829 : {
830 : // Only some european versions were translated, the ones with different
831 : // keyword combinations are:
832 : // English DMY, German TMJ, Spanish DMA, French JMA, Italian GMA,
833 : // Dutch DMJ, Finnish PKV
834 :
835 : // default is English keywords for every other language
836 220 : sal_Int32 nDay = rCode.indexOf('D');
837 220 : sal_Int32 nMonth = rCode.indexOf('M');
838 220 : sal_Int32 nYear = rCode.indexOf('Y');
839 220 : if (nDay == -1 || nMonth == -1 || nYear == -1)
840 : { // This algorithm assumes that all three parts (DMY) are present
841 0 : if (nMonth == -1)
842 : { // only Finnish has something else than 'M' for month
843 0 : nMonth = rCode.indexOf('K');
844 0 : if (nMonth != -1)
845 : {
846 0 : nDay = rCode.indexOf('P');
847 0 : nYear = rCode.indexOf('V');
848 : }
849 : }
850 0 : else if (nDay == -1)
851 : { // We have a month 'M' if we reach this branch.
852 : // Possible languages containing 'M' but no 'D':
853 : // German, French, Italian
854 0 : nDay = rCode.indexOf('T'); // German
855 0 : if (nDay != -1)
856 0 : nYear = rCode.indexOf('J');
857 : else
858 : {
859 0 : nYear = rCode.indexOf('A'); // French, Italian
860 0 : if (nYear != -1)
861 : {
862 0 : nDay = rCode.indexOf('J'); // French
863 0 : if (nDay == -1)
864 0 : nDay = rCode.indexOf('G'); // Italian
865 : }
866 : }
867 : }
868 : else
869 : { // We have a month 'M' and a day 'D'.
870 : // Possible languages containing 'D' and 'M' but not 'Y':
871 : // Spanish, Dutch
872 0 : nYear = rCode.indexOf('A'); // Spanish
873 0 : if (nYear == -1)
874 0 : nYear = rCode.indexOf('J'); // Dutch
875 : }
876 0 : if (nDay == -1 || nMonth == -1 || nYear == -1)
877 : {
878 0 : if (areChecksEnabled())
879 : {
880 0 : OUString aMsg( "LocaleDataWrapper::scanDateFormat: not all DMY present" );
881 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
882 : }
883 0 : if (nDay == -1)
884 0 : nDay = rCode.getLength();
885 0 : if (nMonth == -1)
886 0 : nMonth = rCode.getLength();
887 0 : if (nYear == -1)
888 0 : nYear = rCode.getLength();
889 : }
890 : }
891 : // compare with <= because each position may equal rCode.getLength()
892 220 : if ( nDay <= nMonth && nMonth <= nYear )
893 4 : return DMY; // also if every position equals rCode.getLength()
894 216 : else if ( nMonth <= nDay && nDay <= nYear )
895 216 : return MDY;
896 0 : else if ( nYear <= nMonth && nMonth <= nDay )
897 0 : return YMD;
898 : else
899 : {
900 0 : if (areChecksEnabled())
901 : {
902 0 : OUString aMsg( "LocaleDataWrapper::scanDateFormat: no magic applyable" );
903 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
904 : }
905 0 : return DMY;
906 : }
907 : }
908 :
909 110 : void LocaleDataWrapper::getDateFormatsImpl()
910 : {
911 110 : NumberFormatCodeWrapper aNumberFormatCode( m_xContext, getMyLocale() );
912 : uno::Sequence< NumberFormatCode > aFormatSeq
913 220 : = aNumberFormatCode.getAllFormatCode( KNumberFormatUsage::DATE );
914 110 : sal_Int32 nCnt = aFormatSeq.getLength();
915 110 : if ( !nCnt )
916 : { // bad luck
917 0 : if (areChecksEnabled())
918 : {
919 0 : OUString aMsg( "LocaleDataWrapper::getDateFormatsImpl: no date formats" );
920 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
921 : }
922 0 : nDateFormat = nLongDateFormat = DMY;
923 110 : return;
924 : }
925 : // find the edit (21), a default (medium preferred),
926 : // a medium (default preferred), and a long (default preferred)
927 110 : NumberFormatCode const * const pFormatArr = aFormatSeq.getArray();
928 : sal_Int32 nElem, nEdit, nDef, nMedium, nLong;
929 110 : nEdit = nDef = nMedium = nLong = -1;
930 3500 : for ( nElem = 0; nElem < nCnt; nElem++ )
931 : {
932 3390 : if ( nEdit == -1 && pFormatArr[nElem].Index == NumberFormatIndex::DATE_SYS_DDMMYYYY )
933 110 : nEdit = nElem;
934 3390 : if ( nDef == -1 && pFormatArr[nElem].Default )
935 110 : nDef = nElem;
936 3390 : switch ( pFormatArr[nElem].Type )
937 : {
938 : case KNumberFormatType::MEDIUM :
939 : {
940 1640 : if ( pFormatArr[nElem].Default )
941 : {
942 110 : nDef = nElem;
943 110 : nMedium = nElem;
944 : }
945 1530 : else if ( nMedium == -1 )
946 2 : nMedium = nElem;
947 : }
948 1640 : break;
949 : case KNumberFormatType::LONG :
950 : {
951 1530 : if ( pFormatArr[nElem].Default )
952 110 : nLong = nElem;
953 1420 : else if ( nLong == -1 )
954 0 : nLong = nElem;
955 : }
956 1530 : break;
957 : }
958 : }
959 110 : if ( nEdit == -1 )
960 : {
961 0 : if (areChecksEnabled())
962 : {
963 0 : OUString aMsg( "LocaleDataWrapper::getDateFormatsImpl: no edit" );
964 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
965 : }
966 0 : if ( nDef == -1 )
967 : {
968 0 : if (areChecksEnabled())
969 : {
970 0 : OUString aMsg( "LocaleDataWrapper::getDateFormatsImpl: no default" );
971 0 : outputCheckMessage( appendLocaleInfo( aMsg ) );
972 : }
973 0 : if ( nMedium != -1 )
974 0 : nDef = nMedium;
975 0 : else if ( nLong != -1 )
976 0 : nDef = nLong;
977 : else
978 0 : nDef = 0;
979 : }
980 0 : nEdit = nDef;
981 : }
982 110 : DateFormat nDF = scanDateFormatImpl( pFormatArr[nEdit].Code );
983 110 : if ( pFormatArr[nEdit].Type == KNumberFormatType::LONG )
984 : { // normally this is not the case
985 0 : nLongDateFormat = nDateFormat = nDF;
986 : }
987 : else
988 : {
989 110 : nDateFormat = nDF;
990 110 : if ( nLong == -1 )
991 0 : nLongDateFormat = nDF;
992 : else
993 110 : nLongDateFormat = scanDateFormatImpl( pFormatArr[nLong].Code );
994 110 : }
995 : }
996 :
997 : // --- digit grouping -------------------------------------------------
998 :
999 7452 : void LocaleDataWrapper::getDigitGroupingImpl()
1000 : {
1001 : /* TODO: This is a very simplified grouping setup that only serves its
1002 : * current purpose for Indian locales. A free-form flexible one would
1003 : * obtain grouping from locale data where it could be specified using, for
1004 : * example, codes like #,### and #,##,### that would generate the integer
1005 : * sequence. Needed additional API and a locale data element.
1006 : */
1007 :
1008 7452 : if (!aGrouping.getLength())
1009 : {
1010 7420 : aGrouping.realloc(3); // room for {3,2,0}
1011 7420 : aGrouping[0] = 0; // invalidate
1012 : }
1013 7452 : if (!aGrouping[0])
1014 : {
1015 7452 : i18n::LanguageCountryInfo aLCInfo( getLanguageCountryInfo());
1016 14896 : if (aLCInfo.Country.equalsIgnoreAsciiCase("IN") || // India
1017 7444 : aLCInfo.Country.equalsIgnoreAsciiCase("BT") ) // Bhutan
1018 : {
1019 8 : aGrouping[0] = 3;
1020 8 : aGrouping[1] = 2;
1021 8 : aGrouping[2] = 0;
1022 : }
1023 : else
1024 : {
1025 7444 : aGrouping[0] = 3;
1026 7444 : aGrouping[1] = 0;
1027 7452 : }
1028 : }
1029 7452 : }
1030 :
1031 370284 : const ::com::sun::star::uno::Sequence< sal_Int32 > LocaleDataWrapper::getDigitGrouping() const
1032 : {
1033 370284 : ::utl::ReadWriteGuard aGuard( aMutex );
1034 370284 : if (!aGrouping.getLength() || aGrouping[0] == 0)
1035 : { // no cached content
1036 7452 : aGuard.changeReadToWrite();
1037 7452 : ((LocaleDataWrapper*)this)->getDigitGroupingImpl();
1038 : }
1039 370284 : return aGrouping;
1040 : }
1041 :
1042 : // --- simple number formatting helpers -------------------------------
1043 :
1044 : // The ImplAdd... methods are taken from class International and modified to
1045 : // suit the needs.
1046 :
1047 134680 : static sal_Unicode* ImplAddUNum( sal_Unicode* pBuf, sal_uInt64 nNumber )
1048 : {
1049 : // fill temp buffer with digits
1050 : sal_Unicode aTempBuf[64];
1051 134680 : sal_Unicode* pTempBuf = aTempBuf;
1052 289826 : do
1053 : {
1054 289826 : *pTempBuf = (sal_Unicode)(nNumber % 10) + '0';
1055 289826 : pTempBuf++;
1056 289826 : nNumber /= 10;
1057 : }
1058 : while ( nNumber );
1059 :
1060 : // copy temp buffer to buffer passed
1061 289826 : do
1062 : {
1063 289826 : pTempBuf--;
1064 289826 : *pBuf = *pTempBuf;
1065 289826 : pBuf++;
1066 : }
1067 : while ( pTempBuf != aTempBuf );
1068 :
1069 134680 : return pBuf;
1070 : }
1071 :
1072 544 : static sal_Unicode* ImplAddUNum( sal_Unicode* pBuf, sal_uInt64 nNumber, int nMinLen )
1073 : {
1074 : // fill temp buffer with digits
1075 : sal_Unicode aTempBuf[64];
1076 544 : sal_Unicode* pTempBuf = aTempBuf;
1077 1234 : do
1078 : {
1079 1234 : *pTempBuf = (sal_Unicode)(nNumber % 10) + '0';
1080 1234 : pTempBuf++;
1081 1234 : nNumber /= 10;
1082 1234 : nMinLen--;
1083 : }
1084 : while ( nNumber );
1085 :
1086 : // fill with zeros up to the minimal length
1087 2006 : while ( nMinLen > 0 )
1088 : {
1089 918 : *pBuf = '0';
1090 918 : pBuf++;
1091 918 : nMinLen--;
1092 : }
1093 :
1094 : // copy temp buffer to real buffer
1095 1234 : do
1096 : {
1097 1234 : pTempBuf--;
1098 1234 : *pBuf = *pTempBuf;
1099 1234 : pBuf++;
1100 : }
1101 : while ( pTempBuf != aTempBuf );
1102 :
1103 544 : return pBuf;
1104 : }
1105 :
1106 3210 : static sal_Unicode* ImplAdd2UNum( sal_Unicode* pBuf, sal_uInt16 nNumber, bool bLeading )
1107 : {
1108 : DBG_ASSERT( nNumber < 100, "ImplAdd2UNum() - Number >= 100" );
1109 :
1110 3210 : if ( nNumber < 10 )
1111 : {
1112 2669 : if ( bLeading )
1113 : {
1114 2615 : *pBuf = '0';
1115 2615 : pBuf++;
1116 : }
1117 2669 : *pBuf = nNumber + '0';
1118 : }
1119 : else
1120 : {
1121 541 : sal_uInt16 nTemp = nNumber % 10;
1122 541 : nNumber /= 10;
1123 541 : *pBuf = nNumber + '0';
1124 541 : pBuf++;
1125 541 : *pBuf = nTemp + '0';
1126 : }
1127 :
1128 3210 : pBuf++;
1129 3210 : return pBuf;
1130 : }
1131 :
1132 0 : static sal_Unicode* ImplAdd9UNum( sal_Unicode* pBuf, sal_uInt32 nNumber, bool bLeading )
1133 : {
1134 : DBG_ASSERT( nNumber < 1000000000, "ImplAdd9UNum() - Number >= 1000000000" );
1135 :
1136 0 : std::ostringstream ostr;
1137 0 : if (bLeading)
1138 : {
1139 0 : ostr.fill('0');
1140 0 : ostr.width(9);
1141 : }
1142 0 : ostr << nNumber;
1143 0 : std::string aStr = ostr.str();
1144 0 : for(const char *pAB= aStr.c_str(); *pAB != '\0'; ++pAB, ++pBuf)
1145 : {
1146 0 : *pBuf = *pAB;
1147 : }
1148 :
1149 0 : return pBuf;
1150 : }
1151 :
1152 110672 : inline sal_Unicode* ImplAddString( sal_Unicode* pBuf, const OUString& rStr )
1153 : {
1154 110672 : if ( rStr.getLength() == 1 )
1155 110672 : *pBuf++ = rStr[0];
1156 0 : else if (rStr.isEmpty())
1157 : ;
1158 : else
1159 : {
1160 0 : memcpy( pBuf, rStr.getStr(), rStr.getLength() * sizeof(sal_Unicode) );
1161 0 : pBuf += rStr.getLength();
1162 : }
1163 110672 : return pBuf;
1164 : }
1165 :
1166 0 : inline sal_Unicode* ImplAddString( sal_Unicode* pBuf, sal_Unicode c )
1167 : {
1168 0 : *pBuf = c;
1169 0 : pBuf++;
1170 0 : return pBuf;
1171 : }
1172 :
1173 0 : inline sal_Unicode* ImplAddString( sal_Unicode* pBuf, const sal_Unicode* pCopyBuf, sal_Int32 nLen )
1174 : {
1175 0 : memcpy( pBuf, pCopyBuf, nLen * sizeof(sal_Unicode) );
1176 0 : return pBuf + nLen;
1177 : }
1178 :
1179 134610 : sal_Unicode* LocaleDataWrapper::ImplAddFormatNum( sal_Unicode* pBuf,
1180 : sal_Int64 nNumber, sal_uInt16 nDecimals, bool bUseThousandSep,
1181 : bool bTrailingZeros ) const
1182 : {
1183 : sal_Unicode aNumBuf[64];
1184 : sal_Unicode* pNumBuf;
1185 : sal_uInt16 nNumLen;
1186 134610 : sal_uInt16 i = 0;
1187 :
1188 : // negative number
1189 134610 : if ( nNumber < 0 )
1190 : {
1191 0 : nNumber *= -1;
1192 0 : *pBuf = '-';
1193 0 : pBuf++;
1194 : }
1195 :
1196 : // convert number
1197 134610 : pNumBuf = ImplAddUNum( aNumBuf, (sal_uInt64)nNumber );
1198 134610 : nNumLen = (sal_uInt16)(sal_uLong)(pNumBuf-aNumBuf);
1199 134610 : pNumBuf = aNumBuf;
1200 :
1201 134610 : if ( nNumLen <= nDecimals )
1202 : {
1203 : // strip .0 in decimals?
1204 28820 : if ( !nNumber && !bTrailingZeros )
1205 : {
1206 1948 : *pBuf = '0';
1207 1948 : pBuf++;
1208 : }
1209 : else
1210 : {
1211 : // LeadingZero, insert 0
1212 26872 : if ( isNumLeadingZero() )
1213 : {
1214 26872 : *pBuf = '0';
1215 26872 : pBuf++;
1216 : }
1217 :
1218 : // append decimal separator
1219 26872 : pBuf = ImplAddString( pBuf, getNumDecimalSep() );
1220 :
1221 : // fill with zeros
1222 80616 : while ( i < (nDecimals-nNumLen) )
1223 : {
1224 26872 : *pBuf = '0';
1225 26872 : pBuf++;
1226 26872 : i++;
1227 : }
1228 :
1229 : // append decimals
1230 80616 : while ( nNumLen )
1231 : {
1232 26872 : *pBuf = *pNumBuf;
1233 26872 : pBuf++;
1234 26872 : pNumBuf++;
1235 26872 : nNumLen--;
1236 : }
1237 : }
1238 : }
1239 : else
1240 : {
1241 105790 : const OUString& rThoSep = getNumThousandSep();
1242 :
1243 : // copy number to buffer (excluding decimals)
1244 105790 : sal_uInt16 nNumLen2 = nNumLen-nDecimals;
1245 105790 : uno::Sequence< sal_Bool > aGroupPos;
1246 105790 : if (bUseThousandSep)
1247 202168 : aGroupPos = utl::DigitGroupingIterator::createForwardSequence(
1248 101084 : nNumLen2, getDigitGrouping());
1249 277966 : for (; i < nNumLen2; ++i )
1250 : {
1251 172176 : *pBuf = *pNumBuf;
1252 172176 : pBuf++;
1253 172176 : pNumBuf++;
1254 :
1255 : // add thousand separator?
1256 172176 : if ( bUseThousandSep && aGroupPos[i] )
1257 240 : pBuf = ImplAddString( pBuf, rThoSep );
1258 : }
1259 :
1260 : // append decimals
1261 105790 : if ( nDecimals )
1262 : {
1263 81248 : pBuf = ImplAddString( pBuf, getNumDecimalSep() );
1264 :
1265 81248 : bool bNullEnd = true;
1266 251124 : while ( i < nNumLen )
1267 : {
1268 88628 : if ( *pNumBuf != '0' )
1269 20604 : bNullEnd = false;
1270 :
1271 88628 : *pBuf = *pNumBuf;
1272 88628 : pBuf++;
1273 88628 : pNumBuf++;
1274 88628 : i++;
1275 : }
1276 :
1277 : // strip .0 in decimals?
1278 81248 : if ( bNullEnd && !bTrailingZeros )
1279 68024 : pBuf -= nDecimals+1;
1280 105790 : }
1281 : }
1282 :
1283 134610 : return pBuf;
1284 : }
1285 :
1286 : // --- simple date and time formatting --------------------------------
1287 :
1288 532 : OUString LocaleDataWrapper::getDate( const Date& rDate ) const
1289 : {
1290 532 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1291 : //!TODO: leading zeros et al
1292 : sal_Unicode aBuf[128];
1293 532 : sal_Unicode* pBuf = aBuf;
1294 532 : sal_uInt16 nDay = rDate.GetDay();
1295 532 : sal_uInt16 nMonth = rDate.GetMonth();
1296 532 : sal_uInt16 nYear = rDate.GetYear();
1297 : sal_uInt16 nYearLen;
1298 :
1299 : if ( true /* IsDateCentury() */ )
1300 532 : nYearLen = 4;
1301 : else
1302 : {
1303 : nYearLen = 2;
1304 : nYear %= 100;
1305 : }
1306 :
1307 532 : switch ( getDateFormat() )
1308 : {
1309 : case DMY :
1310 0 : pBuf = ImplAdd2UNum( pBuf, nDay, true /* IsDateDayLeadingZero() */ );
1311 0 : pBuf = ImplAddString( pBuf, getDateSep() );
1312 0 : pBuf = ImplAdd2UNum( pBuf, nMonth, true /* IsDateMonthLeadingZero() */ );
1313 0 : pBuf = ImplAddString( pBuf, getDateSep() );
1314 0 : pBuf = ImplAddUNum( pBuf, nYear, nYearLen );
1315 0 : break;
1316 : case MDY :
1317 532 : pBuf = ImplAdd2UNum( pBuf, nMonth, true /* IsDateMonthLeadingZero() */ );
1318 532 : pBuf = ImplAddString( pBuf, getDateSep() );
1319 532 : pBuf = ImplAdd2UNum( pBuf, nDay, true /* IsDateDayLeadingZero() */ );
1320 532 : pBuf = ImplAddString( pBuf, getDateSep() );
1321 532 : pBuf = ImplAddUNum( pBuf, nYear, nYearLen );
1322 532 : break;
1323 : default:
1324 0 : pBuf = ImplAddUNum( pBuf, nYear, nYearLen );
1325 0 : pBuf = ImplAddString( pBuf, getDateSep() );
1326 0 : pBuf = ImplAdd2UNum( pBuf, nMonth, true /* IsDateMonthLeadingZero() */ );
1327 0 : pBuf = ImplAddString( pBuf, getDateSep() );
1328 0 : pBuf = ImplAdd2UNum( pBuf, nDay, true /* IsDateDayLeadingZero() */ );
1329 : }
1330 :
1331 532 : return OUString(aBuf, pBuf-aBuf);
1332 : }
1333 :
1334 828 : OUString LocaleDataWrapper::getTime( const tools::Time& rTime, bool bSec, bool b100Sec ) const
1335 : {
1336 828 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1337 : //!TODO: leading zeros et al
1338 : sal_Unicode aBuf[128];
1339 828 : sal_Unicode* pBuf = aBuf;
1340 828 : sal_uInt16 nHour = rTime.GetHour();
1341 :
1342 828 : nHour %= 24;
1343 :
1344 828 : pBuf = ImplAdd2UNum( pBuf, nHour, true /* IsTimeLeadingZero() */ );
1345 828 : pBuf = ImplAddString( pBuf, getTimeSep() );
1346 828 : pBuf = ImplAdd2UNum( pBuf, rTime.GetMin(), true );
1347 828 : if ( bSec )
1348 : {
1349 406 : pBuf = ImplAddString( pBuf, getTimeSep() );
1350 406 : pBuf = ImplAdd2UNum( pBuf, rTime.GetSec(), true );
1351 :
1352 406 : if ( b100Sec )
1353 : {
1354 0 : pBuf = ImplAddString( pBuf, getTime100SecSep() );
1355 0 : pBuf = ImplAdd9UNum( pBuf, rTime.GetNanoSec(), true );
1356 : }
1357 : }
1358 :
1359 828 : return OUString(aBuf, pBuf - aBuf);
1360 : }
1361 :
1362 70 : OUString LocaleDataWrapper::getLongDate( const Date& rDate, CalendarWrapper& rCal,
1363 : sal_Int16 nDisplayDayOfWeek, bool bDayOfMonthWithLeadingZero,
1364 : sal_Int16 nDisplayMonth, bool bTwoDigitYear ) const
1365 : {
1366 70 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1367 : using namespace ::com::sun::star::i18n;
1368 : sal_Unicode aBuf[20];
1369 : sal_Unicode* pBuf;
1370 70 : OUString aStr;
1371 : sal_Int16 nVal;
1372 70 : rCal.setGregorianDateTime( rDate );
1373 : // day of week
1374 70 : nVal = rCal.getValue( CalendarFieldIndex::DAY_OF_WEEK );
1375 70 : aStr += rCal.getDisplayName( CalendarDisplayIndex::DAY, nVal, nDisplayDayOfWeek );
1376 70 : aStr += getLongDateDayOfWeekSep();
1377 : // day of month
1378 70 : nVal = rCal.getValue( CalendarFieldIndex::DAY_OF_MONTH );
1379 70 : pBuf = ImplAdd2UNum( aBuf, nVal, bDayOfMonthWithLeadingZero );
1380 140 : OUString aDay(aBuf, pBuf-aBuf);
1381 : // month of year
1382 70 : nVal = rCal.getValue( CalendarFieldIndex::MONTH );
1383 140 : OUString aMonth( rCal.getDisplayName( CalendarDisplayIndex::MONTH, nVal, nDisplayMonth ) );
1384 : // year
1385 70 : nVal = rCal.getValue( CalendarFieldIndex::YEAR );
1386 70 : if ( bTwoDigitYear )
1387 0 : pBuf = ImplAddUNum( aBuf, nVal % 100, 2 );
1388 : else
1389 70 : pBuf = ImplAddUNum( aBuf, nVal );
1390 140 : OUString aYear(aBuf, pBuf-aBuf);
1391 : // concatenate
1392 70 : switch ( getLongDateFormat() )
1393 : {
1394 : case DMY :
1395 0 : aStr += aDay + getLongDateDaySep() + aMonth + getLongDateMonthSep() + aYear;
1396 0 : break;
1397 : case MDY :
1398 70 : aStr += aMonth + getLongDateMonthSep() + aDay + getLongDateDaySep() + aYear;
1399 70 : break;
1400 : default: // YMD
1401 0 : aStr += aYear + getLongDateYearSep() + aMonth + getLongDateMonthSep() + aDay;
1402 : }
1403 140 : return aStr;
1404 : }
1405 :
1406 12 : OUString LocaleDataWrapper::getDuration( const tools::Time& rTime, bool bSec, bool b100Sec ) const
1407 : {
1408 12 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1409 : sal_Unicode aBuf[128];
1410 12 : sal_Unicode* pBuf = aBuf;
1411 :
1412 12 : if ( rTime < tools::Time( 0 ) )
1413 0 : pBuf = ImplAddString( pBuf, ' ' );
1414 :
1415 : if ( true /* IsTimeLeadingZero() */ )
1416 12 : pBuf = ImplAddUNum( pBuf, rTime.GetHour(), 2 );
1417 : else
1418 : pBuf = ImplAddUNum( pBuf, rTime.GetHour() );
1419 12 : pBuf = ImplAddString( pBuf, getTimeSep() );
1420 12 : pBuf = ImplAdd2UNum( pBuf, rTime.GetMin(), true );
1421 12 : if ( bSec )
1422 : {
1423 2 : pBuf = ImplAddString( pBuf, getTimeSep() );
1424 2 : pBuf = ImplAdd2UNum( pBuf, rTime.GetSec(), true );
1425 :
1426 2 : if ( b100Sec )
1427 : {
1428 0 : pBuf = ImplAddString( pBuf, getTime100SecSep() );
1429 0 : pBuf = ImplAdd9UNum( pBuf, rTime.GetNanoSec(), true );
1430 : }
1431 : }
1432 :
1433 12 : return OUString(aBuf, pBuf-aBuf);
1434 : }
1435 :
1436 : // --- simple number formatting ---------------------------------------
1437 :
1438 134610 : inline size_t ImplGetNumberStringLengthGuess( const LocaleDataWrapper& rLoc, sal_uInt16 nDecimals )
1439 : {
1440 : // approximately 3.2 bits per digit
1441 134610 : const size_t nDig = ((sizeof(sal_Int64) * 8) / 3) + 1;
1442 : // digits, separators (pessimized for insane "every digit may be grouped"), leading zero, sign
1443 : size_t nGuess = ((nDecimals < nDig) ?
1444 134610 : (((nDig - nDecimals) * rLoc.getNumThousandSep().getLength()) + nDig) :
1445 269220 : nDecimals) + rLoc.getNumDecimalSep().getLength() + 3;
1446 134610 : return nGuess;
1447 : }
1448 :
1449 134610 : OUString LocaleDataWrapper::getNum( sal_Int64 nNumber, sal_uInt16 nDecimals,
1450 : bool bUseThousandSep, bool bTrailingZeros ) const
1451 : {
1452 134610 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1453 : sal_Unicode aBuf[128]; // big enough for 64-bit long and crazy grouping
1454 : // check if digits and separators will fit into fixed buffer or allocate
1455 134610 : size_t nGuess = ImplGetNumberStringLengthGuess( *this, nDecimals );
1456 : sal_Unicode* const pBuffer = (nGuess < 118 ? aBuf :
1457 134610 : new sal_Unicode[nGuess + 16]);
1458 :
1459 : sal_Unicode* pBuf = ImplAddFormatNum( pBuffer, nNumber, nDecimals,
1460 134610 : bUseThousandSep, bTrailingZeros );
1461 134610 : OUString aStr(pBuffer, pBuf-pBuffer);
1462 :
1463 134610 : if ( pBuffer != aBuf )
1464 0 : delete [] pBuffer;
1465 134610 : return aStr;
1466 : }
1467 :
1468 0 : OUString LocaleDataWrapper::getCurr( sal_Int64 nNumber, sal_uInt16 nDecimals,
1469 : const OUString& rCurrencySymbol, bool bUseThousandSep ) const
1470 : {
1471 0 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1472 : sal_Unicode aBuf[192];
1473 : sal_Unicode aNumBuf[128]; // big enough for 64-bit long and crazy grouping
1474 0 : sal_Unicode cZeroChar = getCurrZeroChar();
1475 :
1476 : // check if digits and separators will fit into fixed buffer or allocate
1477 0 : size_t nGuess = ImplGetNumberStringLengthGuess( *this, nDecimals );
1478 : sal_Unicode* const pNumBuffer = (nGuess < 118 ? aNumBuf :
1479 0 : new sal_Unicode[nGuess + 16]);
1480 :
1481 : sal_Unicode* const pBuffer =
1482 0 : ((size_t(rCurrencySymbol.getLength()) + nGuess + 20) < SAL_N_ELEMENTS(aBuf) ? aBuf :
1483 0 : new sal_Unicode[ rCurrencySymbol.getLength() + nGuess + 20 ]);
1484 0 : sal_Unicode* pBuf = pBuffer;
1485 :
1486 : bool bNeg;
1487 0 : if ( nNumber < 0 )
1488 : {
1489 0 : bNeg = true;
1490 0 : nNumber *= -1;
1491 : }
1492 : else
1493 0 : bNeg = false;
1494 :
1495 : // convert number
1496 : sal_Unicode* pEndNumBuf = ImplAddFormatNum( pNumBuffer, nNumber, nDecimals,
1497 0 : bUseThousandSep, true );
1498 0 : sal_Int32 nNumLen = (sal_Int32)(sal_uLong)(pEndNumBuf-pNumBuffer);
1499 :
1500 : // replace zeros with zero character
1501 0 : if ( (cZeroChar != '0') && nDecimals /* && IsNumTrailingZeros() */ )
1502 : {
1503 : sal_Unicode* pTempBuf;
1504 : sal_uInt16 i;
1505 0 : bool bZero = true;
1506 :
1507 0 : pTempBuf = pNumBuffer+nNumLen-nDecimals;
1508 0 : i = 0;
1509 0 : do
1510 : {
1511 0 : if ( *pTempBuf != '0' )
1512 : {
1513 0 : bZero = false;
1514 0 : break;
1515 : }
1516 :
1517 0 : pTempBuf++;
1518 0 : i++;
1519 : }
1520 : while ( i < nDecimals );
1521 :
1522 0 : if ( bZero )
1523 : {
1524 0 : pTempBuf = pNumBuffer+nNumLen-nDecimals;
1525 0 : i = 0;
1526 0 : do
1527 : {
1528 0 : *pTempBuf = cZeroChar;
1529 0 : pTempBuf++;
1530 0 : i++;
1531 : }
1532 : while ( i < nDecimals );
1533 : }
1534 : }
1535 :
1536 0 : if ( !bNeg )
1537 : {
1538 0 : switch( getCurrPositiveFormat() )
1539 : {
1540 : case 0:
1541 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1542 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1543 0 : break;
1544 : case 1:
1545 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1546 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1547 0 : break;
1548 : case 2:
1549 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1550 0 : pBuf = ImplAddString( pBuf, ' ' );
1551 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1552 0 : break;
1553 : case 3:
1554 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1555 0 : pBuf = ImplAddString( pBuf, ' ' );
1556 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1557 0 : break;
1558 : }
1559 : }
1560 : else
1561 : {
1562 0 : switch( getCurrNegativeFormat() )
1563 : {
1564 : case 0:
1565 0 : pBuf = ImplAddString( pBuf, '(' );
1566 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1567 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1568 0 : pBuf = ImplAddString( pBuf, ')' );
1569 0 : break;
1570 : case 1:
1571 0 : pBuf = ImplAddString( pBuf, '-' );
1572 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1573 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1574 0 : break;
1575 : case 2:
1576 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1577 0 : pBuf = ImplAddString( pBuf, '-' );
1578 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1579 0 : break;
1580 : case 3:
1581 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1582 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1583 0 : pBuf = ImplAddString( pBuf, '-' );
1584 0 : break;
1585 : case 4:
1586 0 : pBuf = ImplAddString( pBuf, '(' );
1587 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1588 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1589 0 : pBuf = ImplAddString( pBuf, ')' );
1590 0 : break;
1591 : case 5:
1592 0 : pBuf = ImplAddString( pBuf, '-' );
1593 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1594 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1595 0 : break;
1596 : case 6:
1597 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1598 0 : pBuf = ImplAddString( pBuf, '-' );
1599 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1600 0 : break;
1601 : case 7:
1602 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1603 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1604 0 : pBuf = ImplAddString( pBuf, '-' );
1605 0 : break;
1606 : case 8:
1607 0 : pBuf = ImplAddString( pBuf, '-' );
1608 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1609 0 : pBuf = ImplAddString( pBuf, ' ' );
1610 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1611 0 : break;
1612 : case 9:
1613 0 : pBuf = ImplAddString( pBuf, '-' );
1614 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1615 0 : pBuf = ImplAddString( pBuf, ' ' );
1616 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1617 0 : break;
1618 : case 10:
1619 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1620 0 : pBuf = ImplAddString( pBuf, ' ' );
1621 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1622 0 : pBuf = ImplAddString( pBuf, '-' );
1623 0 : break;
1624 : case 11:
1625 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1626 0 : pBuf = ImplAddString( pBuf, ' ' );
1627 0 : pBuf = ImplAddString( pBuf, '-' );
1628 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1629 0 : break;
1630 : case 12:
1631 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1632 0 : pBuf = ImplAddString( pBuf, ' ' );
1633 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1634 0 : pBuf = ImplAddString( pBuf, '-' );
1635 0 : break;
1636 : case 13:
1637 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1638 0 : pBuf = ImplAddString( pBuf, '-' );
1639 0 : pBuf = ImplAddString( pBuf, ' ' );
1640 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1641 0 : break;
1642 : case 14:
1643 0 : pBuf = ImplAddString( pBuf, '(' );
1644 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1645 0 : pBuf = ImplAddString( pBuf, ' ' );
1646 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1647 0 : pBuf = ImplAddString( pBuf, ')' );
1648 0 : break;
1649 : case 15:
1650 0 : pBuf = ImplAddString( pBuf, '(' );
1651 0 : pBuf = ImplAddString( pBuf, pNumBuffer, nNumLen );
1652 0 : pBuf = ImplAddString( pBuf, ' ' );
1653 0 : pBuf = ImplAddString( pBuf, rCurrencySymbol );
1654 0 : pBuf = ImplAddString( pBuf, ')' );
1655 0 : break;
1656 : }
1657 : }
1658 :
1659 0 : OUString aNumber(pBuffer, pBuf-pBuffer);
1660 :
1661 0 : if ( pBuffer != aBuf )
1662 0 : delete [] pBuffer;
1663 0 : if ( pNumBuffer != aNumBuf )
1664 0 : delete [] pNumBuffer;
1665 :
1666 0 : return aNumber;
1667 : }
1668 :
1669 : // --- mixed ----------------------------------------------------------
1670 :
1671 63364 : LanguageTag LocaleDataWrapper::getLoadedLanguageTag() const
1672 : {
1673 63364 : LanguageCountryInfo aLCInfo = getLanguageCountryInfo();
1674 63364 : return LanguageTag( lang::Locale( aLCInfo.Language, aLCInfo.Country, aLCInfo.Variant ));
1675 : }
1676 :
1677 0 : OUString LocaleDataWrapper::appendLocaleInfo(const OUString& rDebugMsg) const
1678 : {
1679 0 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nBlockCritical );
1680 0 : OUStringBuffer aDebugMsg(rDebugMsg);
1681 0 : aDebugMsg.append('\n');
1682 0 : aDebugMsg.append(maLanguageTag.getBcp47());
1683 0 : aDebugMsg.appendAscii(" requested\n");
1684 0 : LanguageTag aLoaded = getLoadedLanguageTag();
1685 0 : aDebugMsg.append(aLoaded.getBcp47());
1686 0 : aDebugMsg.appendAscii(" loaded");
1687 0 : return aDebugMsg.makeStringAndClear();
1688 : }
1689 :
1690 : // static
1691 0 : void LocaleDataWrapper::outputCheckMessage( const OUString& rMsg )
1692 : {
1693 0 : outputCheckMessage(OUStringToOString(rMsg, RTL_TEXTENCODING_UTF8).getStr());
1694 0 : }
1695 :
1696 : // static
1697 0 : void LocaleDataWrapper::outputCheckMessage( const char* pStr )
1698 : {
1699 0 : fprintf( stderr, "\n%s\n", pStr);
1700 0 : fflush( stderr);
1701 : OSL_TRACE("%s", pStr);
1702 0 : }
1703 :
1704 : // static
1705 178 : void LocaleDataWrapper::evaluateLocaleDataChecking()
1706 : {
1707 : // Using the rtl_Instance template here wouldn't solve all threaded write
1708 : // accesses, since we want to assign the result to the static member
1709 : // variable and would need to dereference the pointer returned and assign
1710 : // the value unguarded. This is the same pattern manually coded.
1711 178 : sal_uInt8 nCheck = nLocaleDataChecking;
1712 178 : if (!nCheck)
1713 : {
1714 178 : ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex());
1715 178 : nCheck = nLocaleDataChecking;
1716 178 : if (!nCheck)
1717 : {
1718 : #ifdef DBG_UTIL
1719 : nCheck = 1;
1720 : #else
1721 178 : const char* pEnv = getenv( "OOO_ENABLE_LOCALE_DATA_CHECKS");
1722 178 : if (pEnv && (pEnv[0] == 'Y' || pEnv[0] == 'y' || pEnv[0] == '1'))
1723 0 : nCheck = 1;
1724 : else
1725 178 : nCheck = 2;
1726 : #endif
1727 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1728 178 : nLocaleDataChecking = nCheck;
1729 178 : }
1730 : }
1731 : else {
1732 : OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1733 : }
1734 178 : }
1735 :
1736 : // --- XLocaleData3 ----------------------------------------------------------
1737 :
1738 76 : ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Calendar2 > LocaleDataWrapper::getAllCalendars() const
1739 : {
1740 : try
1741 : {
1742 76 : return xLD->getAllCalendars2( getMyLocale() );
1743 : }
1744 0 : catch (const Exception& e)
1745 : {
1746 : SAL_WARN( "unotools.i18n", "getAllCalendars: Exception caught " << e.Message );
1747 : }
1748 0 : return ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Calendar2 >(0);
1749 : }
1750 :
1751 : // --- XLocaleData4 ----------------------------------------------------------
1752 :
1753 130 : ::com::sun::star::uno::Sequence< OUString > LocaleDataWrapper::getDateAcceptancePatterns() const
1754 : {
1755 130 : ::utl::ReadWriteGuard aGuard( aMutex );
1756 :
1757 130 : if (aDateAcceptancePatterns.getLength())
1758 56 : return aDateAcceptancePatterns;
1759 :
1760 74 : aGuard.changeReadToWrite();
1761 :
1762 : try
1763 : {
1764 148 : const_cast<LocaleDataWrapper*>(this)->aDateAcceptancePatterns =
1765 148 : xLD->getDateAcceptancePatterns( getMyLocale() );
1766 74 : return aDateAcceptancePatterns;
1767 : }
1768 0 : catch (const Exception& e)
1769 : {
1770 : SAL_WARN( "unotools.i18n", "getDateAcceptancePatterns: Exception caught " << e.Message );
1771 : }
1772 0 : return ::com::sun::star::uno::Sequence< OUString >(0);
1773 : }
1774 :
1775 : // --- Override layer --------------------------------------------------------
1776 :
1777 349 : void LocaleDataWrapper::setDateAcceptancePatterns(
1778 : const ::com::sun::star::uno::Sequence< OUString > & rPatterns )
1779 : {
1780 349 : ::utl::ReadWriteGuard aGuard( aMutex, ::utl::ReadWriteGuardMode::nWrite );
1781 :
1782 349 : if (!aDateAcceptancePatterns.getLength() || !rPatterns.getLength())
1783 : {
1784 : try
1785 : {
1786 349 : aDateAcceptancePatterns = xLD->getDateAcceptancePatterns( getMyLocale() );
1787 : }
1788 0 : catch (const Exception& e)
1789 : {
1790 : SAL_WARN( "unotools.i18n", "setDateAcceptancePatterns: Exception caught " << e.Message );
1791 : }
1792 349 : if (!rPatterns.getLength())
1793 349 : return; // just a reset
1794 0 : if (!aDateAcceptancePatterns.getLength())
1795 : {
1796 0 : aDateAcceptancePatterns = rPatterns;
1797 0 : return;
1798 : }
1799 : }
1800 :
1801 : // Never overwrite the locale's full date pattern! The first.
1802 0 : if (aDateAcceptancePatterns[0] == rPatterns[0])
1803 0 : aDateAcceptancePatterns = rPatterns; // sane
1804 : else
1805 : {
1806 : // Copy existing full date pattern and append the sequence passed.
1807 : /* TODO: could check for duplicates and shrink target sequence */
1808 0 : Sequence< OUString > aTmp( rPatterns.getLength() + 1 );
1809 0 : OUString* pArray1 = aTmp.getArray();
1810 0 : const OUString* pArray2 = rPatterns.getConstArray();
1811 0 : pArray1[0] = aDateAcceptancePatterns[0];
1812 0 : for (sal_Int32 i=0; i < rPatterns.getLength(); ++i)
1813 0 : pArray1[i+1] = pArray2[i];
1814 0 : aDateAcceptancePatterns = aTmp;
1815 0 : }
1816 : }
1817 :
1818 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|