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