LCOV - code coverage report
Current view: top level - unotools/source/i18n - localedatawrapper.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 526 926 56.8 %
Date: 2014-11-03 Functions: 49 62 79.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10