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

Generated by: LCOV version 1.10