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

Generated by: LCOV version 1.10