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