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