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