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

Generated by: LCOV version 1.11