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