xref: /aoo41x/main/svl/source/numbers/zforlist.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 #ifndef GCC
31 #endif
32 
33 // #include <math.h>
34 #include <tools/debug.hxx>
35 #include <unotools/charclass.hxx>
36 #include <i18npool/mslangid.hxx>
37 #include <unotools/localedatawrapper.hxx>
38 #include <unotools/numberformatcodewrapper.hxx>
39 #include <unotools/calendarwrapper.hxx>
40 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
41 #include <com/sun/star/i18n/KNumberFormatType.hpp>
42 #include <comphelper/processfactory.hxx>
43 #include <unotools/misccfg.hxx>
44 
45 #define _SVSTDARR_USHORTS
46 #include <svl/svstdarr.hxx>
47 
48 #define _ZFORLIST_CXX
49 #include <osl/mutex.hxx>
50 #include <svl/zforlist.hxx>
51 #undef _ZFORLIST_CXX
52 
53 #include "zforscan.hxx"
54 #include "zforfind.hxx"
55 #include <svl/zformat.hxx>
56 #include "numhead.hxx"
57 
58 #include <unotools/syslocaleoptions.hxx>
59 #include <unotools/digitgroupingiterator.hxx>
60 #include <rtl/logfile.hxx>
61 #include <rtl/instance.hxx>
62 
63 #include <math.h>
64 #include <limits>
65 
66 using namespace ::com::sun::star;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::i18n;
69 using namespace ::com::sun::star::lang;
70 
71 
72 // Constants for type offsets per Country/Language (CL)
73 #define ZF_STANDARD              0
74 #define ZF_STANDARD_PERCENT     10
75 #define ZF_STANDARD_CURRENCY    20
76 #define ZF_STANDARD_DATE        30
77 #define ZF_STANDARD_TIME        40
78 #define ZF_STANDARD_DATETIME    50
79 #define ZF_STANDARD_SCIENTIFIC  60
80 #define ZF_STANDARD_FRACTION    70
81 #define ZF_STANDARD_NEWEXTENDED	75
82 #define ZF_STANDARD_NEWEXTENDEDMAX	SV_MAX_ANZ_STANDARD_FORMATE-2	// 98
83 #define ZF_STANDARD_LOGICAL     SV_MAX_ANZ_STANDARD_FORMATE-1 //  99
84 #define ZF_STANDARD_TEXT        SV_MAX_ANZ_STANDARD_FORMATE   // 100
85 
86 /* Locale that is set if an unknown locale (from another system) is loaded of
87  * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
88  * (old currency) is recognized as a date (#53155#). */
89 #define UNKNOWN_SUBSTITUTE		LANGUAGE_ENGLISH_US
90 
91 static sal_Bool bIndexTableInitialized = sal_False;
92 static sal_uInt32 __FAR_DATA theIndexTable[NF_INDEX_TABLE_ENTRIES];
93 
94 
95 // ====================================================================
96 
97 /**
98     instead of every number formatter being a listener we have a registry which
99     also handles one instance of the SysLocale options
100  */
101 
102 class SvNumberFormatterRegistry_Impl : public utl::ConfigurationListener
103 {
104     List                    aFormatters;
105     SvtSysLocaleOptions     aSysLocaleOptions;
106     LanguageType            eSysLanguage;
107 
108 public:
109                             SvNumberFormatterRegistry_Impl();
110     virtual                 ~SvNumberFormatterRegistry_Impl();
111 
112             void            Insert( SvNumberFormatter* pThis )
113                                 { aFormatters.Insert( pThis, LIST_APPEND ); }
114             SvNumberFormatter*  Remove( SvNumberFormatter* pThis )
115                                     { return (SvNumberFormatter*)aFormatters.Remove( pThis ); }
116             sal_uInt32           Count()
117                                 { return aFormatters.Count(); }
118 
119 			virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 );
120 };
121 
122 
123 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
124 {
125     eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
126     aSysLocaleOptions.AddListener( this );
127 }
128 
129 
130 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
131 {
132     aSysLocaleOptions.RemoveListener( this );
133 }
134 
135 
136 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 nHint )
137 {
138         if ( nHint & SYSLOCALEOPTIONS_HINT_LOCALE )
139         {
140             ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
141             for ( SvNumberFormatter* p = (SvNumberFormatter*)aFormatters.First();
142                     p; p = (SvNumberFormatter*)aFormatters.Next() )
143             {
144                 p->ReplaceSystemCL( eSysLanguage );
145             }
146             eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
147         }
148         if ( nHint & SYSLOCALEOPTIONS_HINT_CURRENCY )
149         {
150             ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
151             for ( SvNumberFormatter* p = (SvNumberFormatter*)aFormatters.First();
152                     p; p = (SvNumberFormatter*)aFormatters.Next() )
153             {
154                 p->ResetDefaultSystemCurrency();
155             }
156         }
157 }
158 
159 
160 // ====================================================================
161 
162 SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = NULL;
163 sal_Bool SvNumberFormatter::bCurrencyTableInitialized = sal_False;
164 namespace
165 {
166     struct theCurrencyTable :
167         public rtl::Static< NfCurrencyTable, theCurrencyTable > {};
168 
169     struct theLegacyOnlyCurrencyTable :
170         public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {};
171 }
172 sal_uInt16 SvNumberFormatter::nSystemCurrencyPosition = 0;
173 SV_IMPL_PTRARR( NfCurrencyTable, NfCurrencyEntry* );
174 SV_IMPL_PTRARR( NfWSStringsDtor, String* );
175 
176 // ob das BankSymbol immer am Ende ist (1 $;-1 $) oder sprachabhaengig
177 #define NF_BANKSYMBOL_FIX_POSITION 1
178 
179 
180 /***********************Funktionen SvNumberFormatter**************************/
181 
182 const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION   = ::std::numeric_limits<sal_uInt16>::max();
183 const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
184 
185 SvNumberFormatter::SvNumberFormatter(
186 			const Reference< XMultiServiceFactory >& xSMgr,
187 			LanguageType eLang )
188 		:
189 		xServiceManager( xSMgr )
190 {
191 	ImpConstruct( eLang );
192 }
193 
194 
195 SvNumberFormatter::SvNumberFormatter( LanguageType eLang )
196 {
197 	ImpConstruct( eLang );
198 }
199 
200 
201 SvNumberFormatter::~SvNumberFormatter()
202 {
203     {
204         ::osl::MutexGuard aGuard( GetMutex() );
205         pFormatterRegistry->Remove( this );
206         if ( !pFormatterRegistry->Count() )
207         {
208             delete pFormatterRegistry;
209             pFormatterRegistry = NULL;
210         }
211     }
212 
213 	SvNumberformat* pEntry = aFTable.First();
214 	while (pEntry)
215 	{
216 		delete pEntry;
217 		pEntry = aFTable.Next();
218 	}
219 	delete pFormatTable;
220 	delete pCharClass;
221 	delete pStringScanner;
222 	delete pFormatScanner;
223 	ClearMergeTable();
224 	delete pMergeTable;
225 }
226 
227 
228 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
229 {
230     RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svl", "er93726", "SvNumberFormatter::ImpConstruct" );
231 
232 	if ( eLang == LANGUAGE_DONTKNOW )
233 		eLang = UNKNOWN_SUBSTITUTE;
234     IniLnge = eLang;
235 	ActLnge = eLang;
236 	eEvalDateFormat = NF_EVALDATEFORMAT_INTL;
237 	nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
238 
239 	aLocale = MsLangId::convertLanguageToLocale( eLang );
240 	pCharClass = new CharClass( xServiceManager, aLocale );
241     xLocaleData.init( xServiceManager, aLocale, eLang );
242     xCalendar.init( xServiceManager, aLocale );
243     xTransliteration.init( xServiceManager, eLang,
244         ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE );
245     xNatNum.init( xServiceManager );
246 
247     // cached locale data items
248     const LocaleDataWrapper* pLoc = GetLocaleData();
249     aDecimalSep = pLoc->getNumDecimalSep();
250     aThousandSep = pLoc->getNumThousandSep();
251     aDateSep = pLoc->getDateSep();
252 
253 	pStringScanner = new ImpSvNumberInputScan( this );
254 	pFormatScanner = new ImpSvNumberformatScan( this );
255 	pFormatTable = NULL;
256 	MaxCLOffset = 0;
257     ImpGenerateFormats( 0, sal_False );     // 0 .. 999 for initialized language formats
258     pMergeTable = NULL;
259 	bNoZero = sal_False;
260 
261     ::osl::MutexGuard aGuard( GetMutex() );
262     GetFormatterRegistry().Insert( this );
263 }
264 
265 
266 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
267 {
268 	if (ActLnge != eLnge)
269 	{
270 		ActLnge = eLnge;
271 
272 		aLocale = MsLangId::convertLanguageToLocale( eLnge );
273 		pCharClass->setLocale( aLocale );
274         xLocaleData.changeLocale( aLocale, eLnge );
275         xCalendar.changeLocale( aLocale );
276         xTransliteration.changeLocale( eLnge );
277 
278         // cached locale data items, initialize BEFORE calling ChangeIntl below
279         const LocaleDataWrapper* pLoc = GetLocaleData();
280         aDecimalSep = pLoc->getNumDecimalSep();
281         aThousandSep = pLoc->getNumThousandSep();
282         aDateSep = pLoc->getDateSep();
283 
284 		pFormatScanner->ChangeIntl();
285 		pStringScanner->ChangeIntl();
286 	}
287 }
288 
289 
290 // static
291 ::osl::Mutex& SvNumberFormatter::GetMutex()
292 {
293     static ::osl::Mutex* pMutex = NULL;
294     if( !pMutex )
295     {
296         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
297         if( !pMutex )
298         {
299             // #i77768# Due to a static reference in the toolkit lib
300             // we need a mutex that lives longer than the svl library.
301             // Otherwise the dtor would use a destructed mutex!!
302             pMutex = new ::osl::Mutex;
303         }
304     }
305     return *pMutex;
306 }
307 
308 
309 // static
310 SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry()
311 {
312     ::osl::MutexGuard aGuard( GetMutex() );
313     if ( !pFormatterRegistry )
314         pFormatterRegistry = new SvNumberFormatterRegistry_Impl;
315     return *pFormatterRegistry;
316 }
317 
318 
319 Color* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex)
320 {
321     if( aColorLink.IsSet() )
322         return (Color*) ( aColorLink.Call( (void*) &nIndex ));
323 	else
324 		return NULL;
325 }
326 
327 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay,
328 									   sal_uInt16 nMonth,
329 									   sal_uInt16 nYear)
330 {
331 	pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
332 	pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
333 }
334 
335 Date* SvNumberFormatter::GetNullDate()
336 {
337 	return pFormatScanner->GetNullDate();
338 }
339 
340 void SvNumberFormatter::ChangeStandardPrec(short nPrec)
341 {
342 	pFormatScanner->ChangeStandardPrec(nPrec);
343 }
344 
345 sal_uInt16 SvNumberFormatter::GetStandardPrec()
346 {
347 	return pFormatScanner->GetStandardPrec();
348 }
349 
350 void SvNumberFormatter::ImpChangeSysCL( LanguageType eLnge, sal_Bool bLoadingSO5 )
351 {
352 	if (eLnge == LANGUAGE_DONTKNOW)
353 		eLnge = UNKNOWN_SUBSTITUTE;
354     if (eLnge != IniLnge)
355 	{
356         IniLnge = eLnge;
357 		ChangeIntl(eLnge);
358 		SvNumberformat* pEntry = aFTable.First();
359 		while (pEntry)							// delete old formats
360 		{
361 			pEntry = (SvNumberformat*) aFTable.Remove(aFTable.GetCurKey());
362 			delete pEntry;
363 			pEntry = (SvNumberformat*) aFTable.First();
364 		}
365 		ImpGenerateFormats( 0, bLoadingSO5 );	// new standard formats
366 	}
367 	else if ( bLoadingSO5 )
368 	{	// delete additional standard formats
369 		sal_uInt32 nKey;
370 		aFTable.Seek( SV_MAX_ANZ_STANDARD_FORMATE + 1 );
371 		while ( (nKey = aFTable.GetCurKey()) > SV_MAX_ANZ_STANDARD_FORMATE &&
372 				nKey < SV_COUNTRY_LANGUAGE_OFFSET )
373 		{
374 			SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey );
375 			delete pEntry;
376 		}
377 	}
378 }
379 
380 
381 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage )
382 {
383     sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
384     if ( nCLOffset > MaxCLOffset )
385         return ;    // no SYSTEM entries to replace
386 
387     const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_ANZ_STANDARD_FORMATE;
388     const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
389     sal_uInt32 nKey;
390 
391     // remove old builtin formats
392     aFTable.Seek( nCLOffset );
393     while ( (nKey = aFTable.GetCurKey()) >= nCLOffset && nKey <= nMaxBuiltin && aFTable.Count() )
394     {
395         SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey );
396         delete pEntry;
397     }
398 
399     // move additional and user defined to temporary table
400     Table aOldTable;
401     while ( (nKey = aFTable.GetCurKey()) >= nCLOffset && nKey < nNextCL && aFTable.Count() )
402     {
403         SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey );
404         aOldTable.Insert( nKey, pEntry );
405     }
406 
407     // generate new old builtin formats
408     // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
409     ActLnge = LANGUAGE_DONTKNOW;
410     ChangeIntl( LANGUAGE_SYSTEM );
411     ImpGenerateFormats( nCLOffset, sal_True );
412 
413     // convert additional and user defined from old system to new system
414     SvNumberformat* pStdFormat = (SvNumberformat*) aFTable.Get( nCLOffset + ZF_STANDARD );
415     sal_uInt32 nLastKey = nMaxBuiltin;
416     pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, sal_True );
417     aOldTable.First();
418     while ( aOldTable.Count() )
419     {
420         nKey = aOldTable.GetCurKey();
421         if ( nLastKey < nKey )
422             nLastKey = nKey;
423         SvNumberformat* pOldEntry = (SvNumberformat*) aOldTable.Remove( nKey );
424         String aString( pOldEntry->GetFormatstring() );
425         xub_StrLen nCheckPos = STRING_NOTFOUND;
426 
427         // Same as PutEntry() but assures key position even if format code is
428         // a duplicate. Also won't mix up any LastInsertKey.
429         ChangeIntl( eOldLanguage );
430         LanguageType eLge = eOldLanguage;   // ConvertMode changes this
431         sal_Bool bCheck = sal_False;
432         SvNumberformat* pNewEntry = new SvNumberformat( aString, pFormatScanner,
433             pStringScanner, nCheckPos, eLge );
434         if ( nCheckPos != 0 )
435             delete pNewEntry;
436         else
437         {
438             short eCheckType = pNewEntry->GetType();
439             if ( eCheckType != NUMBERFORMAT_UNDEFINED )
440                 pNewEntry->SetType( eCheckType | NUMBERFORMAT_DEFINED );
441             else
442                 pNewEntry->SetType( NUMBERFORMAT_DEFINED );
443 
444             if ( !aFTable.Insert( nKey, pNewEntry ) )
445                 delete pNewEntry;
446             else
447                 bCheck = sal_True;
448         }
449         DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
450 
451         delete pOldEntry;
452     }
453 	pFormatScanner->SetConvertMode(sal_False);
454     pStdFormat->SetLastInsertKey( sal_uInt16(nLastKey - nCLOffset) );
455 
456     // append new system additional formats
457 	NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
458     ImpGenerateAdditionalFormats( nCLOffset, aNumberFormatCode, sal_True );
459 }
460 
461 
462 sal_Bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
463 {
464 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index);
465 	if (!pFormat)
466 		return sal_False;
467 	else
468 		return pFormat->IsTextFormat();
469 }
470 
471 sal_Bool SvNumberFormatter::HasTextFormat(sal_uInt32 F_Index) const
472 {
473 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index);
474 	if (!pFormat)
475 		return sal_False;
476 	else
477 		return pFormat->HasTextFormat();
478 }
479 
480 sal_Bool SvNumberFormatter::PutEntry(String& rString,
481 								 xub_StrLen& nCheckPos,
482 								 short& nType,
483 								 sal_uInt32& nKey,			// Formatnummer
484 								 LanguageType eLnge)
485 {
486 	nKey = 0;
487 	if (rString.Len() == 0) 							// keinen Leerstring
488 	{
489 		nCheckPos = 1;									// -> Fehler
490 		return sal_False;
491 	}
492 	if (eLnge == LANGUAGE_DONTKNOW)
493         eLnge = IniLnge;
494 
495 	ChangeIntl(eLnge);									// ggfs. austauschen
496 	LanguageType eLge = eLnge;                          // Umgehung const fuer ConvertMode
497 	sal_Bool bCheck = sal_False;
498 	SvNumberformat* p_Entry = new SvNumberformat(rString,
499 												 pFormatScanner,
500 												 pStringScanner,
501 												 nCheckPos,
502 												 eLge);
503 	if (nCheckPos == 0)							// Format ok
504 	{											// Typvergleich:
505 		short eCheckType = p_Entry->GetType();
506 		if ( eCheckType != NUMBERFORMAT_UNDEFINED)
507 		{
508 			p_Entry->SetType(eCheckType | NUMBERFORMAT_DEFINED);
509 			nType = eCheckType;
510 		}
511 		else
512 		{
513 			p_Entry->SetType(NUMBERFORMAT_DEFINED);
514 			nType = NUMBERFORMAT_DEFINED;
515 		}
516 		sal_uInt32 CLOffset = ImpGenerateCL(eLge);				// ggfs. neu Standard-
517 														// formate anlegen
518 		nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
519 		if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND)				// schon vorhanden
520 			delete p_Entry;
521 		else
522 		{
523 			SvNumberformat* pStdFormat =
524 					 (SvNumberformat*) aFTable.Get(CLOffset + ZF_STANDARD);
525 			sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
526 			if (nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
527 			{
528 				DBG_ERROR("SvNumberFormatter:: Zu viele Formate pro CL");
529 				delete p_Entry;
530 			}
531 			else if (!aFTable.Insert(nPos+1,p_Entry))
532 				delete p_Entry;
533 			else
534 			{
535 				bCheck = sal_True;
536 				nKey = nPos+1;
537 				pStdFormat->SetLastInsertKey((sal_uInt16) (nKey-CLOffset));
538 			}
539 		}
540 	}
541 	else
542 		delete p_Entry;
543 	return bCheck;
544 }
545 
546 sal_Bool SvNumberFormatter::PutandConvertEntry(String& rString,
547 										   xub_StrLen& nCheckPos,
548 										   short& nType,
549 										   sal_uInt32& nKey,
550 										   LanguageType eLnge,
551 										   LanguageType eNewLnge)
552 {
553 	sal_Bool bRes;
554 	if (eNewLnge == LANGUAGE_DONTKNOW)
555         eNewLnge = IniLnge;
556 
557 	pFormatScanner->SetConvertMode(eLnge, eNewLnge);
558 	bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
559 	pFormatScanner->SetConvertMode(sal_False);
560 	return bRes;
561 }
562 
563 
564 sal_Bool SvNumberFormatter::PutandConvertEntrySystem(String& rString,
565 										   xub_StrLen& nCheckPos,
566 										   short& nType,
567 										   sal_uInt32& nKey,
568 										   LanguageType eLnge,
569 										   LanguageType eNewLnge)
570 {
571 	sal_Bool bRes;
572 	if (eNewLnge == LANGUAGE_DONTKNOW)
573         eNewLnge = IniLnge;
574 
575 	pFormatScanner->SetConvertMode(eLnge, eNewLnge, sal_True);
576 	bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
577 	pFormatScanner->SetConvertMode(sal_False);
578 	return bRes;
579 }
580 
581 
582 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( String & rString,
583         LanguageType eLnge, LanguageType eSysLnge, short & rType,
584         sal_Bool & rNewInserted, xub_StrLen & rCheckPos )
585 {
586     sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
587     rNewInserted = sal_False;
588     rCheckPos = 0;
589 
590     // #62389# empty format string (of Writer) => General standard format
591     if (!rString.Len())
592         ;   // nothing
593 	else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguage())
594     {
595         sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
596         if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
597             nKey = nOrig;   // none avaliable, maybe user-defined
598         else
599             nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguage() );
600 
601         if (nKey == nOrig)
602         {
603             // Not a builtin format, convert.
604             // The format code string may get modified and adapted to the real
605             // language and wouldn't match eSysLnge anymore, do that on a copy.
606             String aTmp( rString);
607             rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
608                     nKey, eLnge, SvtSysLocale().GetLanguage());
609             if (rCheckPos > 0)
610             {
611                 DBG_ERRORFILE("SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
612                 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
613             }
614         }
615     }
616     else
617     {
618         nKey = GetEntryKey( rString, eLnge);
619         if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
620         {
621             rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
622             if (rCheckPos > 0)
623             {
624                 DBG_ERRORFILE("SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
625                 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
626             }
627         }
628     }
629     if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
630         nKey = GetStandardIndex( eLnge);
631     rType = GetType( nKey);
632     // Convert any (!) old "automatic" currency format to new fixed currency
633     // default format.
634     if ((rType & NUMBERFORMAT_CURRENCY) != 0)
635     {
636         const SvNumberformat* pFormat = GetEntry( nKey);
637         if (!pFormat->HasNewCurrency())
638         {
639             if (rNewInserted)
640             {
641                 DeleteEntry( nKey);     // don't leave trails of rubbish
642                 rNewInserted = sal_False;
643             }
644             nKey = GetStandardFormat( NUMBERFORMAT_CURRENCY, eLnge);
645         }
646     }
647     return nKey;
648 }
649 
650 
651 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
652 {
653 	SvNumberformat* pEntry = aFTable.Remove(nKey);
654 	delete pEntry;
655 }
656 
657 void SvNumberFormatter::PrepareSave()
658 {
659 	 SvNumberformat* pFormat = aFTable.First();
660 	 while (pFormat)
661 	 {
662 		pFormat->SetUsed(sal_False);
663 		pFormat = aFTable.Next();
664 	 }
665 }
666 
667 void SvNumberFormatter::SetFormatUsed(sal_uInt32 nFIndex)
668 {
669 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
670 	if (pFormat)
671 		pFormat->SetUsed(sal_True);
672 }
673 
674 sal_Bool SvNumberFormatter::Load( SvStream& rStream )
675 {
676     LanguageType eSysLang = SvtSysLocale().GetLanguage();
677 	SvNumberFormatter* pConverter = NULL;
678 
679 	ImpSvNumMultipleReadHeader aHdr( rStream );
680 	sal_uInt16 nVersion;
681 	rStream >> nVersion;
682 	SvNumberformat* pEntry;
683 	sal_uInt32 nPos;
684 	LanguageType eSaveSysLang, eLoadSysLang;
685 	sal_uInt16 nSysOnStore, eLge, eDummy; 			// Dummy fuer kompatibles Format
686 	rStream >> nSysOnStore >> eLge;				// Systemeinstellung aus
687 												// Dokument
688 	eSaveSysLang = (nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE ?
689 		LANGUAGE_SYSTEM : (LanguageType) nSysOnStore);
690 	LanguageType eLnge = (LanguageType) eLge;
691 	ImpChangeSysCL( eLnge, sal_True );
692 
693 	rStream >> nPos;
694 	while (nPos != NUMBERFORMAT_ENTRY_NOT_FOUND)
695 	{
696 		rStream >> eDummy >> eLge;
697 		eLnge = (LanguageType) eLge;
698 		ImpGenerateCL( eLnge, sal_True );			// ggfs. neue Standardformate anlegen
699 
700 		sal_uInt32 nOffset = nPos % SV_COUNTRY_LANGUAGE_OFFSET;		// relativIndex
701 		sal_Bool bUserDefined = (nOffset > SV_MAX_ANZ_STANDARD_FORMATE);
702 		//! HACK! ER 29.07.97 15:15
703 		// SaveLang wurde bei SYSTEM nicht gespeichert sondern war auch SYSTEM,
704 		// erst ab 364i Unterscheidung moeglich
705 		sal_Bool bConversionHack;
706 		if ( eLnge == LANGUAGE_SYSTEM )
707 		{
708 			if ( nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE )
709 			{
710 				bConversionHack = bUserDefined;
711 				eLoadSysLang = eSaveSysLang;
712 			}
713 			else
714 			{
715 				bConversionHack = sal_False;
716 				eLoadSysLang = eSysLang;
717 			}
718 		}
719 		else
720 		{
721 			bConversionHack = sal_False;
722 			eLoadSysLang = eSaveSysLang;
723 		}
724 
725 		pEntry = new SvNumberformat(*pFormatScanner, eLnge);
726 		if ( bConversionHack )
727 		{	// SYSTEM
728 			// nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE
729 			// nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS
730 			if ( !pConverter )
731 				pConverter = new SvNumberFormatter( xServiceManager, eSysLang );
732 			NfHackConversion eHackConversion = pEntry->Load(
733 				rStream, aHdr, pConverter, *pStringScanner );
734 			switch ( eHackConversion )
735 			{
736 				case NF_CONVERT_GERMAN_ENGLISH :
737 					pEntry->ConvertLanguage( *pConverter,
738 						LANGUAGE_ENGLISH_US, eSysLang, sal_True );
739 				break;
740 				case NF_CONVERT_ENGLISH_GERMAN :
741 					switch ( eSysLang )
742 					{
743 						case LANGUAGE_GERMAN:
744 						case LANGUAGE_GERMAN_SWISS:
745 						case LANGUAGE_GERMAN_AUSTRIAN:
746 						case LANGUAGE_GERMAN_LUXEMBOURG:
747 						case LANGUAGE_GERMAN_LIECHTENSTEIN:
748 							// alles beim alten
749 						break;
750 						default:
751 							pEntry->ConvertLanguage( *pConverter,
752 								LANGUAGE_GERMAN, eSysLang, sal_True );
753 					}
754 				break;
755 				case NF_CONVERT_NONE :
756 				break;  // -Wall not handled.
757 			}
758 
759 		}
760 		else
761 		{
762 			pEntry->Load( rStream, aHdr, NULL, *pStringScanner );
763 			if ( !bUserDefined )
764 				bUserDefined = (pEntry->GetNewStandardDefined() > SV_NUMBERFORMATTER_VERSION);
765 			if ( bUserDefined )
766 			{
767 				if ( eSaveSysLang != eLoadSysLang )
768 				{	// SYSTEM verschieden
769 					if ( !pConverter )
770 						pConverter = new SvNumberFormatter( xServiceManager, eSysLang );
771 					if ( nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS )
772 					{
773 						switch ( eSaveSysLang )
774 						{
775 							case LANGUAGE_GERMAN:
776 							case LANGUAGE_GERMAN_SWISS:
777 							case LANGUAGE_GERMAN_AUSTRIAN:
778 							case LANGUAGE_GERMAN_LUXEMBOURG:
779 							case LANGUAGE_GERMAN_LIECHTENSTEIN:
780 								// alles beim alten
781 								pEntry->ConvertLanguage( *pConverter,
782 									eSaveSysLang, eLoadSysLang, sal_True );
783 							break;
784 							default:
785 								// alte english nach neuem anderen
786 								pEntry->ConvertLanguage( *pConverter,
787 									LANGUAGE_ENGLISH_US, eLoadSysLang, sal_True );
788 						}
789 					}
790 					else
791 						pEntry->ConvertLanguage( *pConverter,
792 							eSaveSysLang, eLoadSysLang, sal_True );
793 				}
794 				else
795 				{	// nicht SYSTEM oder gleiches SYSTEM
796 					if ( nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS )
797 					{
798 						LanguageType eLoadLang;
799 						sal_Bool bSystem;
800 						if ( eLnge == LANGUAGE_SYSTEM )
801 						{
802 							eLoadLang = eSysLang;
803 							bSystem = sal_True;
804 						}
805 						else
806 						{
807 							eLoadLang = eLnge;
808 							bSystem = sal_False;
809 						}
810 						switch ( eLoadLang )
811 						{
812 							case LANGUAGE_GERMAN:
813 							case LANGUAGE_GERMAN_SWISS:
814 							case LANGUAGE_GERMAN_AUSTRIAN:
815 							case LANGUAGE_GERMAN_LUXEMBOURG:
816 							case LANGUAGE_GERMAN_LIECHTENSTEIN:
817 								// alles beim alten
818 							break;
819 							default:
820 								// alte english nach neuem anderen
821 								if ( !pConverter )
822 									pConverter = new SvNumberFormatter( xServiceManager, eSysLang );
823 								pEntry->ConvertLanguage( *pConverter,
824 									LANGUAGE_ENGLISH_US, eLoadLang, bSystem );
825 						}
826 					}
827 				}
828 			}
829 		}
830 		if ( nOffset == 0 )		// StandardFormat
831 		{
832 			SvNumberformat* pEnt = aFTable.Get(nPos);
833 			if (pEnt)
834 				pEnt->SetLastInsertKey(pEntry->GetLastInsertKey());
835 		}
836 		if (!aFTable.Insert(nPos, pEntry))
837 			delete pEntry;
838 		rStream >> nPos;
839 	}
840 
841 	// ab SV_NUMBERFORMATTER_VERSION_YEAR2000
842 	if ( nVersion >= SV_NUMBERFORMATTER_VERSION_YEAR2000 )
843 	{
844 		aHdr.StartEntry();
845 		if ( aHdr.BytesLeft() >= sizeof(sal_uInt16) )
846 		{
847 			sal_uInt16 nY2k;
848 			rStream >> nY2k;
849 			if ( nVersion < SV_NUMBERFORMATTER_VERSION_TWODIGITYEAR && nY2k < 100 )
850 				nY2k += 1901;		// war vor src513e: 29, jetzt: 1930
851 			SetYear2000( nY2k );
852 		}
853 		aHdr.EndEntry();
854 	}
855 
856 	if ( pConverter )
857 		delete pConverter;
858 
859 	// generate additional i18n standard formats for all used locales
860 	LanguageType eOldLanguage = ActLnge;
861 	NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
862 	SvUShorts aList;
863 	GetUsedLanguages( aList );
864 	sal_uInt16 nCount = aList.Count();
865 	for ( sal_uInt16 j=0; j<nCount; j++ )
866 	{
867 		LanguageType eLang = aList[j];
868 		ChangeIntl( eLang );
869 		sal_uInt32 CLOffset = ImpGetCLOffset( eLang );
870 		ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, sal_True );
871 	}
872 	ChangeIntl( eOldLanguage );
873 
874 	if (rStream.GetError())
875 		return sal_False;
876 	else
877 		return sal_True;
878 }
879 
880 sal_Bool SvNumberFormatter::Save( SvStream& rStream ) const
881 {
882 	ImpSvNumMultipleWriteHeader aHdr( rStream );
883 	// ab 364i wird gespeichert was SYSTEM wirklich war, vorher hart LANGUAGE_SYSTEM
884 	rStream << (sal_uInt16) SV_NUMBERFORMATTER_VERSION;
885     rStream << (sal_uInt16) SvtSysLocale().GetLanguage() << (sal_uInt16) IniLnge;
886 	SvNumberFormatTable* pTable = (SvNumberFormatTable*) &aFTable;
887 	SvNumberformat* pEntry = (SvNumberformat*) pTable->First();
888 	while (pEntry)
889 	{
890 		// Gespeichert werden alle markierten, benutzerdefinierten Formate und
891 		// jeweils das Standardformat zu allen angewaehlten CL-Kombinationen
892 		// sowie NewStandardDefined
893 		if ( pEntry->GetUsed() || (pEntry->GetType() & NUMBERFORMAT_DEFINED) ||
894 				pEntry->GetNewStandardDefined() ||
895 				(pTable->GetCurKey() % SV_COUNTRY_LANGUAGE_OFFSET == 0) )
896 		{
897 			rStream << static_cast<sal_uInt32>(pTable->GetCurKey())
898 					<< (sal_uInt16) LANGUAGE_SYSTEM
899 					<< (sal_uInt16) pEntry->GetLanguage();
900 			pEntry->Save(rStream, aHdr);
901 		}
902 		pEntry = (SvNumberformat*) pTable->Next();
903 	}
904 	rStream << NUMBERFORMAT_ENTRY_NOT_FOUND;				// EndeKennung
905 
906 	// ab SV_NUMBERFORMATTER_VERSION_YEAR2000
907 	aHdr.StartEntry();
908 	rStream << (sal_uInt16) GetYear2000();
909 	aHdr.EndEntry();
910 
911 	if (rStream.GetError())
912 		return sal_False;
913 	else
914 		return sal_True;
915 }
916 
917 // static
918 void SvNumberFormatter::SkipNumberFormatterInStream( SvStream& rStream )
919 {
920 	ImpSvNumMultipleReadHeader::Skip( rStream );
921 }
922 
923 void SvNumberFormatter::GetUsedLanguages( SvUShorts& rList )
924 {
925 	rList.Remove( 0, rList.Count() );
926 
927 	sal_uInt32 nOffset = 0;
928 	while (nOffset <= MaxCLOffset)
929 	{
930 		SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nOffset);
931 		if (pFormat)
932 			rList.Insert( pFormat->GetLanguage(), rList.Count() );
933 		nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
934 	}
935 }
936 
937 
938 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
939         LanguageType eLang )
940 {
941 	ChangeIntl( eLang );
942     const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
943 	for ( sal_uInt16 i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
944     {
945         rKeywords[i] = rTable[i];
946     }
947 }
948 
949 
950 String SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
951 {
952 	ChangeIntl(eLnge);
953     const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
954 	if ( nIndex < NF_KEYWORD_ENTRIES_COUNT )
955 		return rTable[nIndex];
956 
957 	DBG_ERROR("GetKeyword: invalid index");
958 	return String();
959 }
960 
961 
962 String SvNumberFormatter::GetStandardName( LanguageType eLnge )
963 {
964     ChangeIntl( eLnge );
965     return pFormatScanner->GetStandardName();
966 }
967 
968 
969 sal_uInt32 SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge) const
970 {
971 	SvNumberformat* pFormat;
972 	sal_uInt32 nOffset = 0;
973 	while (nOffset <= MaxCLOffset)
974 	{
975 		pFormat = (SvNumberformat*) aFTable.Get(nOffset);
976 		if (pFormat && pFormat->GetLanguage() == eLnge)
977 			return nOffset;
978 		nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
979 	}
980 	return nOffset;
981 }
982 
983 sal_uInt32 SvNumberFormatter::ImpIsEntry(const String& rString,
984 									   sal_uInt32 nCLOffset,
985 									   LanguageType eLnge)
986 {
987 #ifndef NF_COMMENT_IN_FORMATSTRING
988 #error NF_COMMENT_IN_FORMATSTRING not defined (zformat.hxx)
989 #endif
990 #if NF_COMMENT_IN_FORMATSTRING
991 	String aStr( rString );
992 	SvNumberformat::EraseComment( aStr );
993 #endif
994 	sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND;
995 	SvNumberformat* pEntry;
996 	pEntry = (SvNumberformat*) aFTable.Seek(nCLOffset);
997 	while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND &&
998 			pEntry && pEntry->GetLanguage() == eLnge )
999 	{
1000 #if NF_COMMENT_IN_FORMATSTRING
1001 		if ( pEntry->GetComment().Len() )
1002 		{
1003 			String aFormat( pEntry->GetFormatstring() );
1004 			SvNumberformat::EraseComment( aFormat );
1005 			if ( aStr == aFormat )
1006 				res = aFTable.GetCurKey();
1007 			else
1008 				pEntry = (SvNumberformat*) aFTable.Next();
1009 		}
1010 		else
1011 		{
1012 			if ( aStr == pEntry->GetFormatstring() )
1013 				res = aFTable.GetCurKey();
1014 			else
1015 				pEntry = (SvNumberformat*) aFTable.Next();
1016 		}
1017 #else
1018 		if ( rString == pEntry->GetFormatstring() )
1019 			res = aFTable.GetCurKey();
1020 		else
1021 			pEntry = (SvNumberformat*) aFTable.Next();
1022 #endif
1023 	}
1024 	return res;
1025 }
1026 
1027 
1028 SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable(
1029 													  short& eType,
1030 													  sal_uInt32& FIndex,
1031 													  LanguageType& rLnge)
1032 {
1033 	short eTypetmp = eType;
1034 	if (eType == NUMBERFORMAT_ALL) 					// Leere Zelle oder don't care
1035         rLnge = IniLnge;
1036 	else
1037 	{
1038 		SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(FIndex);
1039 		if (!pFormat)
1040 		{
1041 //			DBG_ERROR("SvNumberFormatter:: Unbekanntes altes Zahlformat (1)");
1042             rLnge = IniLnge;
1043 			eType = NUMBERFORMAT_ALL;
1044 			eTypetmp = eType;
1045 		}
1046 		else
1047 		{
1048 			rLnge = pFormat->GetLanguage();
1049 			eType = pFormat->GetType()&~NUMBERFORMAT_DEFINED;
1050 			if (eType == 0)
1051 			{
1052 				eType = NUMBERFORMAT_DEFINED;
1053 				eTypetmp = eType;
1054 			}
1055 			else if (eType == NUMBERFORMAT_DATETIME)
1056 			{
1057 				eTypetmp = eType;
1058 				eType = NUMBERFORMAT_DATE;
1059 			}
1060 			else
1061 				eTypetmp = eType;
1062 		}
1063 	}
1064 	ChangeIntl(rLnge);
1065 	return GetEntryTable(eTypetmp, FIndex, rLnge);
1066 }
1067 
1068 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge, sal_Bool bLoadingSO5 )
1069 {
1070 	ChangeIntl(eLnge);
1071 	sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1072 	if (CLOffset > MaxCLOffset)
1073 	{	// new CL combination
1074         if (LocaleDataWrapper::areChecksEnabled())
1075         {
1076             Locale aLoadedLocale = xLocaleData->getLoadedLocale();
1077             if ( aLoadedLocale.Language != aLocale.Language ||
1078                     aLoadedLocale.Country != aLocale.Country )
1079             {
1080                 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1081                             "SvNumerFormatter::ImpGenerateCL: locales don't match:"));
1082                 LocaleDataWrapper::outputCheckMessage(
1083                         xLocaleData->appendLocaleInfo( aMsg ));
1084             }
1085             // test XML locale data FormatElement entries
1086             {
1087                 uno::Sequence< i18n::FormatElement > xSeq =
1088                     xLocaleData->getAllFormats();
1089                 // A test for completeness of formatindex="0" ...
1090                 // formatindex="47" is not needed here since it is done in
1091                 // ImpGenerateFormats().
1092 
1093                 // Test for dupes of formatindex="..."
1094                 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
1095                 {
1096                     sal_Int16 nIdx = xSeq[j].formatIndex;
1097                     String aDupes;
1098                     for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
1099                     {
1100                         if ( i != j && xSeq[i].formatIndex == nIdx )
1101                         {
1102                             aDupes += String::CreateFromInt32( i );
1103                             aDupes += '(';
1104                             aDupes += String( xSeq[i].formatKey );
1105                             aDupes += ')';
1106                             aDupes += ' ';
1107                         }
1108                     }
1109                     if ( aDupes.Len() )
1110                     {
1111                         String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1112                                     "XML locale data FormatElement formatindex dupe: "));
1113                         aMsg += String::CreateFromInt32( nIdx );
1114                         aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM(
1115                                     "\nFormatElements: "));
1116                         aMsg += String::CreateFromInt32( j );
1117                         aMsg += '(';
1118                         aMsg += String( xSeq[j].formatKey );
1119                         aMsg += ')';
1120                         aMsg += ' ';
1121                         aMsg += aDupes;
1122                         LocaleDataWrapper::outputCheckMessage(
1123                                 xLocaleData->appendLocaleInfo( aMsg ));
1124                     }
1125                 }
1126             }
1127         }
1128 
1129 		MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1130 		ImpGenerateFormats( MaxCLOffset, bLoadingSO5 );
1131 		CLOffset = MaxCLOffset;
1132 	}
1133 	return CLOffset;
1134 }
1135 
1136 SvNumberFormatTable& SvNumberFormatter::ChangeCL(short eType,
1137 												 sal_uInt32& FIndex,
1138 												 LanguageType eLnge)
1139 {
1140 	ImpGenerateCL(eLnge);
1141 	return GetEntryTable(eType, FIndex, ActLnge);
1142 }
1143 
1144 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
1145 													short eType,
1146 													sal_uInt32& FIndex,
1147 													LanguageType eLnge)
1148 {
1149 	if ( pFormatTable )
1150 		pFormatTable->Clear();
1151 	else
1152 		pFormatTable = new SvNumberFormatTable;
1153 	ChangeIntl(eLnge);
1154 	sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1155 
1156     // Might generate and insert a default format for the given type
1157     // (e.g. currency) => has to be done before collecting formats.
1158     sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
1159 
1160 	SvNumberformat* pEntry;
1161 	pEntry = (SvNumberformat*) aFTable.Seek(CLOffset);
1162 
1163 	if (eType == NUMBERFORMAT_ALL)
1164 	{
1165 		while (pEntry && pEntry->GetLanguage() == ActLnge)
1166         {   // copy all entries to output table
1167             pFormatTable->Insert( aFTable.GetCurKey(), pEntry );
1168 			pEntry = (SvNumberformat*) aFTable.Next();
1169 		}
1170 	}
1171 	else
1172 	{
1173 		while (pEntry && pEntry->GetLanguage() == ActLnge)
1174         {   // copy entries of queried type to output table
1175             if ((pEntry->GetType()) & eType)
1176                 pFormatTable->Insert(aFTable.GetCurKey(),pEntry);
1177 			pEntry = (SvNumberformat*) aFTable.Next();
1178 		}
1179 	}
1180     if ( pFormatTable->Count() > 0 )
1181     {   // select default if queried format doesn't exist or queried type or
1182         // language differ from existing format
1183         pEntry = aFTable.Get(FIndex);
1184         if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
1185             FIndex = nDefaultIndex;
1186     }
1187 	return *pFormatTable;
1188 }
1189 
1190 sal_Bool SvNumberFormatter::IsNumberFormat(const String& sString,
1191 									   sal_uInt32& F_Index,
1192 									   double& fOutNumber)
1193 {
1194 	short FType;
1195 	const SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index);
1196 	if (!pFormat)
1197 	{
1198 //		DBG_ERROR("SvNumberFormatter:: Unbekanntes altes Zahlformat (2)");
1199         ChangeIntl(IniLnge);
1200 		FType = NUMBERFORMAT_NUMBER;
1201 	}
1202 	else
1203 	{
1204 		FType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
1205 		if (FType == 0)
1206 			FType = NUMBERFORMAT_DEFINED;
1207 		ChangeIntl(pFormat->GetLanguage());
1208 	}
1209 	sal_Bool res;
1210 	short RType = FType;
1211 														// Ergebnistyp
1212 														// ohne def-Kennung
1213 	if (RType == NUMBERFORMAT_TEXT)							// Zahlzelle ->Stringz.
1214 		res = sal_False;
1215 	else
1216 		res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat);
1217 
1218 	if (res && !IsCompatible(FType, RType))		// unpassender Typ
1219 	{
1220 		switch ( RType )
1221 		{
1222 			case NUMBERFORMAT_TIME :
1223 			{
1224 				if ( pStringScanner->GetDecPos() )
1225 				{	// 100stel Sekunden
1226 					if ( pStringScanner->GetAnzNums() > 3 || fOutNumber < 0.0 )
1227 						F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
1228 					else
1229 						F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge );
1230 				}
1231 				else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1232 					F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge );
1233 				else
1234 					F_Index = GetStandardFormat( RType, ActLnge );
1235 			}
1236 			break;
1237 			default:
1238 				F_Index = GetStandardFormat( RType, ActLnge );
1239 		}
1240 	}
1241 	return res;
1242 }
1243 
1244 sal_Bool SvNumberFormatter::IsCompatible(short eOldType,
1245 									 short eNewType)
1246 {
1247 	if (eOldType == eNewType)
1248 		return sal_True;
1249 	else if (eOldType == NUMBERFORMAT_DEFINED)
1250 		return sal_True;
1251 	else
1252 	{
1253 		switch (eNewType)
1254 		{
1255 			case NUMBERFORMAT_NUMBER:
1256 			{
1257 				switch (eOldType)
1258 				{
1259 					case NUMBERFORMAT_PERCENT:
1260 					case NUMBERFORMAT_CURRENCY:
1261 					case NUMBERFORMAT_SCIENTIFIC:
1262 					case NUMBERFORMAT_FRACTION:
1263 //					case NUMBERFORMAT_LOGICAL:
1264 					case NUMBERFORMAT_DEFINED:
1265 						return sal_True;
1266 					default:
1267 						return sal_False;
1268 				}
1269 			}
1270 			break;
1271 			case NUMBERFORMAT_DATE:
1272 			{
1273 				switch (eOldType)
1274 				{
1275 					case NUMBERFORMAT_DATETIME:
1276 						return sal_True;
1277 					default:
1278 						return sal_False;
1279 				}
1280 			}
1281 			break;
1282 			case NUMBERFORMAT_TIME:
1283 			{
1284 				switch (eOldType)
1285 				{
1286 					case NUMBERFORMAT_DATETIME:
1287 						return sal_True;
1288 					default:
1289 						return sal_False;
1290 				}
1291 			}
1292 			break;
1293 			case NUMBERFORMAT_DATETIME:
1294 			{
1295 				switch (eOldType)
1296 				{
1297 					case NUMBERFORMAT_TIME:
1298 					case NUMBERFORMAT_DATE:
1299 						return sal_True;
1300 					default:
1301 						return sal_False;
1302 				}
1303 			}
1304 			break;
1305 			default:
1306 			return sal_False;
1307 		}
1308 		return sal_False;
1309 	}
1310 }
1311 
1312 
1313 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( short nType )
1314 {
1315 	sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1316 	sal_uInt32 nSearch;
1317 	switch( nType )
1318 	{
1319 		case NUMBERFORMAT_DATE		:
1320 			nSearch = CLOffset + ZF_STANDARD_DATE;
1321 		break;
1322 		case NUMBERFORMAT_TIME      :
1323 			nSearch = CLOffset + ZF_STANDARD_TIME;
1324 		break;
1325 		case NUMBERFORMAT_DATETIME  :
1326 			nSearch = CLOffset + ZF_STANDARD_DATETIME;
1327 		break;
1328 		case NUMBERFORMAT_PERCENT   :
1329 			nSearch = CLOffset + ZF_STANDARD_PERCENT;
1330 		break;
1331 		case NUMBERFORMAT_SCIENTIFIC:
1332 			nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1333 		break;
1334 		default:
1335 			nSearch = CLOffset + ZF_STANDARD;
1336 	}
1337 	sal_uInt32 nDefaultFormat = (sal_uInt32)(sal_uLong) aDefaultFormatKeys.Get( nSearch );
1338 	if ( !nDefaultFormat )
1339 		nDefaultFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
1340 	if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1341 	{	// look for a defined standard
1342 		sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1343 		sal_uInt32 nKey;
1344 		aFTable.Seek( CLOffset );
1345 		while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey )
1346 		{
1347 			const SvNumberformat* pEntry =
1348 				(const SvNumberformat*) aFTable.GetCurObject();
1349             if ( pEntry->IsStandard() && ((pEntry->GetType() &
1350                             ~NUMBERFORMAT_DEFINED) == nType) )
1351 			{
1352 				nDefaultFormat = nKey;
1353 				break;	// while
1354 			}
1355 			aFTable.Next();
1356 		}
1357 
1358 		if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1359 		{	// none found, use old fixed standards
1360 			switch( nType )
1361 			{
1362 				case NUMBERFORMAT_DATE		:
1363 					nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1364 				break;
1365 				case NUMBERFORMAT_TIME      :
1366 					nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1367 				break;
1368 				case NUMBERFORMAT_DATETIME  :
1369 					nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1370 				break;
1371 				case NUMBERFORMAT_PERCENT   :
1372 					nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1373 				break;
1374 				case NUMBERFORMAT_SCIENTIFIC:
1375 					nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1376 				break;
1377 				default:
1378 					nDefaultFormat = CLOffset + ZF_STANDARD;
1379 			}
1380 		}
1381 		aDefaultFormatKeys.Insert( nSearch, (void*) nDefaultFormat );
1382 	}
1383 	return nDefaultFormat;
1384 }
1385 
1386 
1387 sal_uInt32 SvNumberFormatter::GetStandardFormat( short eType, LanguageType eLnge )
1388 {
1389 	sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1390 	switch(eType)
1391 	{
1392 		case NUMBERFORMAT_CURRENCY  :
1393 		{
1394 			if ( eLnge == LANGUAGE_SYSTEM )
1395 				return ImpGetDefaultSystemCurrencyFormat();
1396 			else
1397 				return ImpGetDefaultCurrencyFormat();
1398 		}
1399 		case NUMBERFORMAT_DATE		:
1400 		case NUMBERFORMAT_TIME      :
1401 		case NUMBERFORMAT_DATETIME  :
1402 		case NUMBERFORMAT_PERCENT   :
1403 		case NUMBERFORMAT_SCIENTIFIC:
1404 			return ImpGetDefaultFormat( eType );
1405 
1406 		case NUMBERFORMAT_FRACTION  : return CLOffset + ZF_STANDARD_FRACTION;
1407 		case NUMBERFORMAT_LOGICAL   : return CLOffset + ZF_STANDARD_LOGICAL;
1408 		case NUMBERFORMAT_TEXT		: return CLOffset + ZF_STANDARD_TEXT;
1409 		case NUMBERFORMAT_ALL       :
1410 		case NUMBERFORMAT_DEFINED   :
1411 		case NUMBERFORMAT_NUMBER    :
1412 		case NUMBERFORMAT_UNDEFINED :
1413 		default               : return CLOffset + ZF_STANDARD;
1414 	}
1415 }
1416 
1417 sal_Bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1418 		LanguageType eLnge )
1419 {
1420 	return
1421 		nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1422 		nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1423 		nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1424 		;
1425 }
1426 
1427 sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, short eType,
1428 		LanguageType eLnge )
1429 {
1430 	if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1431 		return nFIndex;
1432 	else
1433 		return GetStandardFormat( eType, eLnge );
1434 }
1435 
1436 sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1437 		short eType, LanguageType eLnge )
1438 {
1439 	if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1440 		return nFIndex;
1441 
1442 	switch( eType )
1443 	{
1444 		case NUMBERFORMAT_TIME :
1445 		{
1446 			sal_Bool bSign;
1447 			if ( fNumber < 0.0 )
1448 			{
1449 				bSign = sal_True;
1450 				fNumber = -fNumber;
1451 			}
1452 			else
1453 				bSign = sal_False;
1454 			double fSeconds = fNumber * 86400;
1455 			if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1456 			{	// mit 100stel Sekunden
1457 				if ( bSign || fSeconds >= 3600 )
1458 					return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1459 				else
1460 					return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1461 			}
1462 			else
1463 			{
1464 				if ( bSign || fNumber >= 1.0 )
1465 					return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1466 				else
1467 					return GetStandardFormat( eType, eLnge );
1468 			}
1469 		}
1470 		default:
1471 			return GetStandardFormat( eType, eLnge );
1472 	}
1473 }
1474 
1475 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1476 										   sal_uInt32 nFIndex,
1477 										   String& sOutString)
1478 {
1479 	SvNumberformat* pFormat;
1480 	Color* pColor;
1481 	pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1482 	if (!pFormat)
1483 		pFormat = aFTable.Get(ZF_STANDARD);
1484 	LanguageType eLang = pFormat->GetLanguage();
1485 	ChangeIntl( eLang );
1486 	short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1487 	if (eType == 0)
1488 		eType = NUMBERFORMAT_DEFINED;
1489     sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
1490     bool bPrecChanged = false;
1491 	if (eType == NUMBERFORMAT_NUMBER || eType == NUMBERFORMAT_PERCENT
1492 									 || eType == NUMBERFORMAT_CURRENCY
1493 									 || eType == NUMBERFORMAT_SCIENTIFIC
1494 									 || eType == NUMBERFORMAT_FRACTION)
1495 	{
1496 		if (eType != NUMBERFORMAT_PERCENT)	// spaeter Sonderbehandlung %
1497 			eType = NUMBERFORMAT_NUMBER;
1498         ChangeStandardPrec(INPUTSTRING_PRECISION);
1499         bPrecChanged = true;
1500 	}
1501 	sal_uInt32 nKey = nFIndex;
1502 	switch ( eType )
1503 	{	// #61619# immer vierstelliges Jahr editieren
1504 		case NUMBERFORMAT_DATE :
1505 			nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1506 		break;
1507 		case NUMBERFORMAT_DATETIME :
1508 			nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1509 		break;
1510 		default:
1511 			nKey = GetStandardFormat( fOutNumber, nFIndex, eType, eLang );
1512 	}
1513 	if ( nKey != nFIndex )
1514 		pFormat = (SvNumberformat*) aFTable.Get( nKey );
1515 	if (pFormat)
1516 	{
1517 		if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() )
1518 		{
1519             ChangeStandardPrec(INPUTSTRING_PRECISION);
1520             bPrecChanged = true;
1521 		}
1522 		pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1523 	}
1524     if (bPrecChanged)
1525 		ChangeStandardPrec(nOldPrec);
1526 }
1527 
1528 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1529 										sal_uInt32 nFIndex,
1530 										String& sOutString,
1531 										Color** ppColor)
1532 {
1533 	if (bNoZero && fOutNumber == 0.0)
1534 	{
1535 		sOutString.Erase();
1536 		return;
1537 	}
1538 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1539 	if (!pFormat)
1540 		pFormat = aFTable.Get(ZF_STANDARD);
1541 	ChangeIntl(pFormat->GetLanguage());
1542 	pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1543 }
1544 
1545 void SvNumberFormatter::GetOutputString(String& sString,
1546 										sal_uInt32 nFIndex,
1547 										String& sOutString,
1548 										Color** ppColor)
1549 {
1550 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1551 	if (!pFormat)
1552 		pFormat = aFTable.Get(ZF_STANDARD_TEXT);
1553 	if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1554 	{
1555 		*ppColor = NULL;
1556 		sOutString = sString;
1557 	}
1558 	else
1559 	{
1560 		ChangeIntl(pFormat->GetLanguage());
1561 		pFormat->GetOutputString(sString, sOutString, ppColor);
1562 	}
1563 }
1564 
1565 sal_Bool SvNumberFormatter::GetPreviewString(const String& sFormatString,
1566 										 double fPreviewNumber,
1567 										 String& sOutString,
1568 										 Color** ppColor,
1569 										 LanguageType eLnge)
1570 {
1571 	if (sFormatString.Len() == 0) 						// keinen Leerstring
1572 		return sal_False;
1573 
1574 	xub_StrLen nCheckPos = STRING_NOTFOUND;
1575 	sal_uInt32 nKey;
1576 	if (eLnge == LANGUAGE_DONTKNOW)
1577         eLnge = IniLnge;
1578 	ChangeIntl(eLnge);							// ggfs. austauschen
1579 	eLnge = ActLnge;
1580 	String sTmpString = sFormatString;
1581 	SvNumberformat* p_Entry = new SvNumberformat(sTmpString,
1582 												 pFormatScanner,
1583 												 pStringScanner,
1584 												 nCheckPos,
1585 												 eLnge);
1586 	if (nCheckPos == 0)									// String ok
1587 	{
1588 		sal_uInt32 CLOffset = ImpGenerateCL(eLnge);				// ggfs. neu Standard-
1589 														// formate anlegen
1590 		nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1591 		if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND)				// schon vorhanden
1592 			GetOutputString(fPreviewNumber,nKey,sOutString,ppColor);
1593 		else
1594 			p_Entry->GetOutputString(fPreviewNumber,sOutString, ppColor);
1595 		delete p_Entry;
1596 		return sal_True;
1597 	}
1598 	else
1599 	{
1600 		delete p_Entry;
1601 		return sal_False;
1602 	}
1603 }
1604 
1605 sal_Bool SvNumberFormatter::GetPreviewStringGuess( const String& sFormatString,
1606 										 double fPreviewNumber,
1607 										 String& sOutString,
1608 										 Color** ppColor,
1609 										 LanguageType eLnge )
1610 {
1611 	if (sFormatString.Len() == 0) 						// keinen Leerstring
1612 		return sal_False;
1613 
1614 	if (eLnge == LANGUAGE_DONTKNOW)
1615         eLnge = IniLnge;
1616 
1617 	ChangeIntl( eLnge );
1618 	eLnge = ActLnge;
1619 	sal_Bool bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1620 
1621 	String aFormatStringUpper( pCharClass->upper( sFormatString ) );
1622 	sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1623 	sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1624 	if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1625 	{	// Zielformat vorhanden
1626 		GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1627 		return sal_True;
1628 	}
1629 
1630 	SvNumberformat *pEntry = NULL;
1631 	xub_StrLen nCheckPos = STRING_NOTFOUND;
1632 	String sTmpString;
1633 
1634 	if ( bEnglish )
1635 	{
1636 		sTmpString = sFormatString;
1637 		pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1638 			pStringScanner, nCheckPos, eLnge );
1639 	}
1640 	else
1641 	{
1642 		nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1643 		nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1644 		sal_Bool bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1645 
1646 		// try english --> other bzw. english nach other konvertieren
1647 		LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1648 		pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge );
1649 		sTmpString = sFormatString;
1650 		pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1651 			pStringScanner, nCheckPos, eFormatLang );
1652 		pFormatScanner->SetConvertMode( sal_False );
1653 		ChangeIntl( eLnge );
1654 
1655 		if ( !bEnglishFormat )
1656 		{
1657             if ( nCheckPos > 0 || xTransliteration->isEqual( sFormatString,
1658                     pEntry->GetFormatstring() ) )
1659 			{	// other Format
1660 				delete pEntry;
1661 				sTmpString = sFormatString;
1662 				pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1663 					pStringScanner, nCheckPos, eLnge );
1664 			}
1665 			else
1666 			{	// verify english
1667 				xub_StrLen nCheckPos2 = STRING_NOTFOUND;
1668 				// try other --> english
1669 				eFormatLang = eLnge;
1670 				pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US );
1671 				sTmpString = sFormatString;
1672 				SvNumberformat* pEntry2 = new SvNumberformat( sTmpString, pFormatScanner,
1673 					pStringScanner, nCheckPos2, eFormatLang );
1674 				pFormatScanner->SetConvertMode( sal_False );
1675 				ChangeIntl( eLnge );
1676                 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1677                         pEntry2->GetFormatstring() ) )
1678 				{	// other Format
1679 					delete pEntry;
1680 					sTmpString = sFormatString;
1681 					pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1682 						pStringScanner, nCheckPos, eLnge );
1683 				}
1684 				delete pEntry2;
1685 			}
1686 		}
1687 	}
1688 
1689 	if (nCheckPos == 0)									// String ok
1690 	{
1691 		ImpGenerateCL( eLnge );		// ggfs. neu Standardformate anlegen
1692 		pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1693 		delete pEntry;
1694 		return sal_True;
1695 	}
1696 	delete pEntry;
1697 	return sal_False;
1698 }
1699 
1700 sal_Bool SvNumberFormatter::GetPreviewString( const String& sFormatString,
1701                                           const String& sPreviewString,
1702                                           String& sOutString,
1703                                           Color** ppColor,
1704                                           LanguageType eLnge )
1705 {
1706     if (sFormatString.Len() == 0)               // no empty string
1707         return sal_False;
1708 
1709     xub_StrLen nCheckPos = STRING_NOTFOUND;
1710     sal_uInt32 nKey;
1711     if (eLnge == LANGUAGE_DONTKNOW)
1712         eLnge = IniLnge;
1713     ChangeIntl(eLnge);                          // switch if needed
1714     eLnge = ActLnge;
1715     String sTmpString = sFormatString;
1716     SvNumberformat* p_Entry = new SvNumberformat( sTmpString,
1717                                                   pFormatScanner,
1718                                                   pStringScanner,
1719                                                   nCheckPos,
1720                                                   eLnge);
1721     if (nCheckPos == 0)                          // String ok
1722     {
1723         String aNonConstPreview( sPreviewString);
1724         // May have to create standard formats for this locale.
1725         sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1726         nKey = ImpIsEntry( p_Entry->GetFormatstring(), CLOffset, eLnge);
1727         if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND)       // already present
1728             GetOutputString( aNonConstPreview, nKey, sOutString, ppColor);
1729         else
1730         {
1731             // If the format is valid but not a text format and does not
1732             // include a text subformat, an empty string would result. Same as
1733             // in SvNumberFormatter::GetOutputString()
1734             if (p_Entry->IsTextFormat() || p_Entry->HasTextFormat())
1735                 p_Entry->GetOutputString( aNonConstPreview, sOutString, ppColor);
1736             else
1737             {
1738                 *ppColor = NULL;
1739                 sOutString = sPreviewString;
1740             }
1741         }
1742         delete p_Entry;
1743         return sal_True;
1744     }
1745     else
1746     {
1747         delete p_Entry;
1748         return sal_False;
1749     }
1750 }
1751 
1752 sal_uInt32 SvNumberFormatter::TestNewString(const String& sFormatString,
1753 									  LanguageType eLnge)
1754 {
1755 	if (sFormatString.Len() == 0) 						// keinen Leerstring
1756 		return NUMBERFORMAT_ENTRY_NOT_FOUND;
1757 
1758 	xub_StrLen nCheckPos = STRING_NOTFOUND;
1759 	if (eLnge == LANGUAGE_DONTKNOW)
1760         eLnge = IniLnge;
1761 	ChangeIntl(eLnge);									// ggfs. austauschen
1762 	eLnge = ActLnge;
1763 	sal_uInt32 nRes;
1764 	String sTmpString = sFormatString;
1765 	SvNumberformat* pEntry = new SvNumberformat(sTmpString,
1766 												pFormatScanner,
1767 												pStringScanner,
1768 												nCheckPos,
1769 												eLnge);
1770 	if (nCheckPos == 0)									// String ok
1771 	{
1772 		sal_uInt32 CLOffset = ImpGenerateCL(eLnge);				// ggfs. neu Standard-
1773 														// formate anlegen
1774 		nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1775 														// schon vorhanden ?
1776 	}
1777 	else
1778 		nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1779 	delete pEntry;
1780 	return nRes;
1781 }
1782 
1783 SvNumberformat* SvNumberFormatter::ImpInsertFormat(
1784 			const ::com::sun::star::i18n::NumberFormatCode& rCode,
1785 			sal_uInt32 nPos, sal_Bool bAfterLoadingSO5, sal_Int16 nOrgIndex )
1786 {
1787 	String aCodeStr( rCode.Code );
1788 	if ( rCode.Index < NF_INDEX_TABLE_ENTRIES &&
1789 			rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY &&
1790 			rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1791 	{	// strip surrounding [$...] on automatic currency
1792 		if ( aCodeStr.SearchAscii( "[$" ) != STRING_NOTFOUND )
1793 			aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, sal_False );
1794 		else
1795 		{
1796 			if (LocaleDataWrapper::areChecksEnabled() &&
1797                     rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1798 			{
1799 				String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1800                             "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index "));
1801 				aMsg += String::CreateFromInt32( rCode.Index );
1802 				aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ":\n"));
1803 				aMsg += String( rCode.Code );
1804                 LocaleDataWrapper::outputCheckMessage(
1805                         xLocaleData->appendLocaleInfo( aMsg));
1806 			}
1807 		}
1808 	}
1809 	xub_StrLen nCheckPos = 0;
1810 	SvNumberformat* pFormat = new SvNumberformat(aCodeStr,
1811 												 pFormatScanner,
1812 												 pStringScanner,
1813 												 nCheckPos,
1814 												 ActLnge);
1815 	if ( !pFormat || nCheckPos > 0 )
1816 	{
1817         if (LocaleDataWrapper::areChecksEnabled())
1818         {
1819             String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1820                         "SvNumberFormatter::ImpInsertFormat: bad format code, index "));
1821             aMsg += String::CreateFromInt32( rCode.Index );
1822             aMsg += '\n';
1823             aMsg += String( rCode.Code );
1824             LocaleDataWrapper::outputCheckMessage(
1825                     xLocaleData->appendLocaleInfo( aMsg));
1826         }
1827 		delete pFormat;
1828 		return NULL;
1829 	}
1830 	if ( rCode.Index >= NF_INDEX_TABLE_ENTRIES )
1831 	{
1832 		sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
1833 		sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
1834 		if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1835 		{
1836             if (LocaleDataWrapper::areChecksEnabled())
1837             {
1838                 switch ( nOrgIndex )
1839                 {
1840                     // These may be dupes of integer versions for locales where
1841                     // currencies have no decimals like Italian Lira.
1842                     case NF_CURRENCY_1000DEC2 :			// NF_CURRENCY_1000INT
1843                     case NF_CURRENCY_1000DEC2_RED :		// NF_CURRENCY_1000INT_RED
1844                     case NF_CURRENCY_1000DEC2_DASHED :	// NF_CURRENCY_1000INT_RED
1845                     break;
1846                     default:
1847                         if ( !bAfterLoadingSO5 )
1848                         {	// If bAfterLoadingSO5 there will definitely be some dupes,
1849                             // don't cry. But we need this test for verification of locale
1850                             // data if not loading old SO5 documents.
1851                             String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1852                                         "SvNumberFormatter::ImpInsertFormat: dup format code, index "));
1853                             aMsg += String::CreateFromInt32( rCode.Index );
1854                             aMsg += '\n';
1855                             aMsg += String( rCode.Code );
1856                             LocaleDataWrapper::outputCheckMessage(
1857                                     xLocaleData->appendLocaleInfo( aMsg));
1858                         }
1859                 }
1860             }
1861 			delete pFormat;
1862 			return NULL;
1863 		}
1864 		else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
1865 		{
1866             if (LocaleDataWrapper::areChecksEnabled())
1867             {
1868                 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1869                             "SvNumberFormatter::ImpInsertFormat: too many format codes, index "));
1870                 aMsg += String::CreateFromInt32( rCode.Index );
1871                 aMsg += '\n';
1872                 aMsg += String( rCode.Code );
1873                 LocaleDataWrapper::outputCheckMessage(
1874                         xLocaleData->appendLocaleInfo( aMsg));
1875             }
1876 			delete pFormat;
1877 			return NULL;
1878 		}
1879 	}
1880 	if ( !aFTable.Insert( nPos, pFormat ) )
1881 	{
1882         if (LocaleDataWrapper::areChecksEnabled())
1883         {
1884             String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1885                         "ImpInsertFormat: can't insert number format key pos: "));
1886             aMsg += String::CreateFromInt32( nPos );
1887             aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", code index "));
1888             aMsg += String::CreateFromInt32( rCode.Index );
1889             aMsg += '\n';
1890             aMsg += String( rCode.Code );
1891             LocaleDataWrapper::outputCheckMessage(
1892                     xLocaleData->appendLocaleInfo( aMsg));
1893         }
1894 		delete pFormat;
1895 		return NULL;
1896 	}
1897 	if ( rCode.Default )
1898 		pFormat->SetStandard();
1899 	if ( rCode.DefaultName.getLength() )
1900 		pFormat->SetComment( rCode.DefaultName );
1901 	return pFormat;
1902 }
1903 
1904 SvNumberformat* SvNumberFormatter::ImpInsertNewStandardFormat(
1905 			const ::com::sun::star::i18n::NumberFormatCode& rCode,
1906 			sal_uInt32 nPos, sal_uInt16 nVersion, sal_Bool bAfterLoadingSO5,
1907 			sal_Int16 nOrgIndex )
1908 {
1909 	SvNumberformat* pNewFormat = ImpInsertFormat( rCode, nPos,
1910 		bAfterLoadingSO5, nOrgIndex );
1911 	if (pNewFormat)
1912 		pNewFormat->SetNewStandardDefined( nVersion );
1913 		// so that it gets saved, displayed properly, and converted by old versions
1914 	return pNewFormat;
1915 }
1916 
1917 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
1918 											 sal_Bool& bThousand,
1919 											 sal_Bool& IsRed,
1920 											 sal_uInt16& nPrecision,
1921 											 sal_uInt16& nAnzLeading)
1922 
1923 {
1924 	const SvNumberformat* pFormat = aFTable.Get(nFormat);
1925 	if (pFormat)
1926 		pFormat->GetFormatSpecialInfo(bThousand, IsRed,
1927 									  nPrecision, nAnzLeading);
1928 	else
1929 	{
1930 		bThousand = sal_False;
1931 		IsRed = sal_False;
1932 		nPrecision = pFormatScanner->GetStandardPrec();
1933 		nAnzLeading = 0;
1934 	}
1935 }
1936 
1937 sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
1938 {
1939 	const SvNumberformat* pFormat = aFTable.Get( nFormat );
1940 	if ( pFormat )
1941 		return pFormat->GetFormatPrecision();
1942 	else
1943 		return pFormatScanner->GetStandardPrec();
1944 }
1945 
1946 
1947 String SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
1948 {
1949 	const SvNumberformat* pFormat = aFTable.Get( nFormat );
1950 	if ( !pFormat || pFormat->GetLanguage() == ActLnge )
1951         return GetNumDecimalSep();
1952 
1953     String aRet;
1954     LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
1955     if ( pFormat->GetLanguage() == eSaveLang )
1956         aRet = xLocaleData->getNumDecimalSep();
1957     else
1958     {
1959         ::com::sun::star::lang::Locale aSaveLocale( xLocaleData->getLocale() );
1960         ::com::sun::star::lang::Locale aTmpLocale(MsLangId::convertLanguageToLocale(pFormat->GetLanguage()));
1961         ((SvNumberFormatter*)this)->xLocaleData.changeLocale(aTmpLocale, pFormat->GetLanguage() );
1962         aRet = xLocaleData->getNumDecimalSep();
1963         ((SvNumberFormatter*)this)->xLocaleData.changeLocale( aSaveLocale, eSaveLang );
1964     }
1965 	return aRet;
1966 }
1967 
1968 
1969 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const String& rFormatString,
1970 			sal_Bool& bThousand, sal_Bool& IsRed, sal_uInt16& nPrecision,
1971 			sal_uInt16& nAnzLeading, LanguageType eLnge )
1972 
1973 {
1974 	xub_StrLen nCheckPos = 0;
1975 	if (eLnge == LANGUAGE_DONTKNOW)
1976         eLnge = IniLnge;
1977 	ChangeIntl(eLnge);									// ggfs. austauschen
1978 	eLnge = ActLnge;
1979 	String aTmpStr( rFormatString );
1980 	SvNumberformat* pFormat = new SvNumberformat( aTmpStr,
1981 		pFormatScanner, pStringScanner, nCheckPos, eLnge );
1982 	if ( nCheckPos == 0 )
1983 		pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading );
1984 	else
1985 	{
1986 		bThousand = sal_False;
1987 		IsRed = sal_False;
1988 		nPrecision = pFormatScanner->GetStandardPrec();
1989 		nAnzLeading = 0;
1990 	}
1991 	delete pFormat;
1992 	return nCheckPos;
1993 }
1994 
1995 
1996 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
1997 {
1998 	if ( !bIndexTableInitialized )
1999 	{
2000 		DBG_ASSERT( theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
2001 			"SetIndexTable: theIndexTable[nTabOff] already occupied" );
2002 		theIndexTable[nTabOff] = nIndOff;
2003 	}
2004 	return nIndOff;
2005 }
2006 
2007 
2008 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
2009 			::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq,
2010 			const NfIndexTableOffset nTabOff )
2011 {
2012 	const sal_Int32 nLen = rSeq.getLength();
2013 	for ( sal_Int32 j=0; j<nLen; j++ )
2014 	{
2015 		if ( rSeq[j].Index == nTabOff )
2016 			return j;
2017 	}
2018     if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
2019                 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
2020                 || nTabOff == NF_CURRENCY_1000INT_RED
2021                 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
2022 	{	// currency entries with decimals might not exist, e.g. Italian Lira
2023 		String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2024                     "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "));
2025 		aMsg += String::CreateFromInt32( nTabOff );
2026         LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(
2027                     aMsg));
2028 	}
2029 	if ( nLen )
2030 	{
2031 		sal_Int32 j;
2032 		// look for a preset default
2033 		for ( j=0; j<nLen; j++ )
2034 		{
2035 			if ( rSeq[j].Default )
2036 				return j;
2037 		}
2038 		// currencies are special, not all format codes must exist, but all
2039 		// builtin number format key index positions must have a format assigned
2040 		if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2041 		{
2042 			// look for a format with decimals
2043 			for ( j=0; j<nLen; j++ )
2044 			{
2045 				if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 )
2046 					return j;
2047 			}
2048 			// last resort: look for a format without decimals
2049 			for ( j=0; j<nLen; j++ )
2050 			{
2051 				if ( rSeq[j].Index == NF_CURRENCY_1000INT )
2052 					return j;
2053 			}
2054 		}
2055 	}
2056 	else
2057 	{	// we need at least _some_ format
2058 		rSeq.realloc(1);
2059 		rSeq[0] = ::com::sun::star::i18n::NumberFormatCode();
2060 		String aTmp( '0' );
2061         aTmp += GetNumDecimalSep();
2062 		aTmp.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "############" ) );
2063 		rSeq[0].Code = aTmp;
2064 	}
2065 	return 0;
2066 }
2067 
2068 
2069 sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault(
2070         ::com::sun::star::i18n::NumberFormatCode * pFormatArr,
2071         sal_Int32 nCnt, sal_Bool bCheckCorrectness )
2072 {
2073 	using namespace ::com::sun::star;
2074 
2075     if ( !nCnt )
2076         return -1;
2077     if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled())
2078     {   // check the locale data for correctness
2079         ByteString aMsg;
2080         sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2081         nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2082         for ( nElem = 0; nElem < nCnt; nElem++ )
2083         {
2084             switch ( pFormatArr[nElem].Type )
2085             {
2086                 case i18n::KNumberFormatType::SHORT :
2087                     nShort = nElem;
2088                 break;
2089                 case i18n::KNumberFormatType::MEDIUM :
2090                     nMedium = nElem;
2091                 break;
2092                 case i18n::KNumberFormatType::LONG :
2093                     nLong = nElem;
2094                 break;
2095                 default:
2096                     aMsg = "unknown type";
2097             }
2098             if ( pFormatArr[nElem].Default )
2099             {
2100                 switch ( pFormatArr[nElem].Type )
2101                 {
2102                     case i18n::KNumberFormatType::SHORT :
2103                         if ( nShortDef != -1 )
2104                             aMsg = "dupe short type default";
2105                         nShortDef = nElem;
2106                     break;
2107                     case i18n::KNumberFormatType::MEDIUM :
2108                         if ( nMediumDef != -1 )
2109                             aMsg = "dupe medium type default";
2110                         nMediumDef = nElem;
2111                     break;
2112                     case i18n::KNumberFormatType::LONG :
2113                         if ( nLongDef != -1 )
2114                             aMsg = "dupe long type default";
2115                         nLongDef = nElem;
2116                     break;
2117                 }
2118             }
2119             if ( aMsg.Len() )
2120             {
2121                 aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 );
2122                 aMsg += "\nXML locale data FormatElement formatindex: ";
2123                 aMsg += ByteString::CreateFromInt32( pFormatArr[nElem].Index );
2124                 String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US);
2125                 LocaleDataWrapper::outputCheckMessage(
2126                         xLocaleData->appendLocaleInfo( aUMsg));
2127                 aMsg.Erase();
2128             }
2129         }
2130         if ( nShort != -1 && nShortDef == -1 )
2131             aMsg += "no short type default  ";
2132         if ( nMedium != -1 && nMediumDef == -1 )
2133             aMsg += "no medium type default  ";
2134         if ( nLong != -1 && nLongDef == -1 )
2135             aMsg += "no long type default  ";
2136         if ( aMsg.Len() )
2137         {
2138             aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 );
2139             aMsg += "\nXML locale data FormatElement group of: ";
2140             String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US);
2141             aUMsg += String( pFormatArr[0].NameID );
2142             LocaleDataWrapper::outputCheckMessage(
2143                     xLocaleData->appendLocaleInfo( aUMsg));
2144             aMsg.Erase();
2145         }
2146     }
2147     // find the default (medium preferred, then long) and reset all other defaults
2148     sal_Int32 nElem, nDef, nMedium;
2149     nDef = nMedium = -1;
2150 	for ( nElem = 0; nElem < nCnt; nElem++ )
2151 	{
2152         if ( pFormatArr[nElem].Default )
2153         {
2154             switch ( pFormatArr[nElem].Type )
2155             {
2156                 case i18n::KNumberFormatType::MEDIUM :
2157                     nDef = nMedium = nElem;
2158                 break;
2159                 case i18n::KNumberFormatType::LONG :
2160                     if ( nMedium == -1 )
2161                         nDef = nElem;
2162                 // fallthru
2163                 default:
2164                     if ( nDef == -1 )
2165                         nDef = nElem;
2166                     pFormatArr[nElem].Default = sal_False;
2167             }
2168         }
2169 	}
2170     if ( nDef == -1 )
2171         nDef = 0;
2172     pFormatArr[nDef].Default = sal_True;
2173     return nDef;
2174 }
2175 
2176 
2177 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, sal_Bool bLoadingSO5 )
2178 {
2179 	using namespace ::com::sun::star;
2180 
2181 	if ( !bIndexTableInitialized )
2182 	{
2183 		for ( sal_uInt16 j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
2184 		{
2185 			theIndexTable[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
2186 		}
2187 	}
2188 	sal_Bool bOldConvertMode = pFormatScanner->GetConvertMode();
2189 	if (bOldConvertMode)
2190 		pFormatScanner->SetConvertMode(sal_False);		// switch off for this function
2191 
2192 	NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
2193 
2194 	xub_StrLen nCheckPos = 0;
2195 	SvNumberformat* pNewFormat = NULL;
2196 	String aFormatCode;
2197 	sal_Int32 nIdx;
2198 	sal_Bool bDefault;
2199 
2200 	// Counter for additional builtin formats not fitting into the first 10
2201 	// of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2202 	// Has to be incremented on each ImpInsertNewStandardformat, new formats
2203 	// must be appended, not inserted!
2204 	sal_uInt16 nNewExtended = ZF_STANDARD_NEWEXTENDED;
2205 
2206     // Number
2207     uno::Sequence< i18n::NumberFormatCode > aFormatSeq
2208         = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER );
2209     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2210 
2211     // General
2212     nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2213     SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2214             CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD ));
2215     if (pStdFormat)
2216     {
2217         // This is _the_ standard format.
2218         if (LocaleDataWrapper::areChecksEnabled() &&
2219                 pStdFormat->GetType() != NUMBERFORMAT_NUMBER)
2220         {
2221             String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2222                         "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2223             LocaleDataWrapper::outputCheckMessage(
2224                     xLocaleData->appendLocaleInfo( aMsg));
2225         }
2226         pStdFormat->SetType( NUMBERFORMAT_NUMBER );
2227         pStdFormat->SetStandard();
2228         pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE );
2229     }
2230     else
2231     {
2232         if (LocaleDataWrapper::areChecksEnabled())
2233         {
2234             String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2235                         "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2236             LocaleDataWrapper::outputCheckMessage(
2237                     xLocaleData->appendLocaleInfo( aMsg));
2238         }
2239     }
2240 
2241 	// Boolean
2242 	aFormatCode = pFormatScanner->GetBooleanString();
2243 	pNewFormat = new SvNumberformat( aFormatCode,
2244 		pFormatScanner, pStringScanner,	nCheckPos, ActLnge );
2245 	pNewFormat->SetType(NUMBERFORMAT_LOGICAL);
2246 	pNewFormat->SetStandard();
2247 	if ( !aFTable.Insert(
2248 			CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ),
2249 			pNewFormat))
2250 		delete pNewFormat;
2251 
2252 	// Text
2253 	aFormatCode = '@';
2254 	pNewFormat = new SvNumberformat( aFormatCode,
2255 		pFormatScanner, pStringScanner, nCheckPos, ActLnge );
2256 	pNewFormat->SetType(NUMBERFORMAT_TEXT);
2257 	pNewFormat->SetStandard();
2258 	if ( !aFTable.Insert(
2259 			CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ),
2260 			pNewFormat))
2261 		delete pNewFormat;
2262 
2263 
2264 
2265 	// 0
2266 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2267 	ImpInsertFormat( aFormatSeq[nIdx],
2268 		CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 ));
2269 
2270 	// 0.00
2271 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2272 	ImpInsertFormat( aFormatSeq[nIdx],
2273 		CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 ));
2274 
2275 	// #,##0
2276 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2277 	ImpInsertFormat( aFormatSeq[nIdx],
2278 			CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 ));
2279 
2280 	// #,##0.00
2281 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2282 	ImpInsertFormat( aFormatSeq[nIdx],
2283 		CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 ));
2284 
2285 	// #.##0,00 System country/language dependent   since number formatter version 6
2286 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2287 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2288 		CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ),
2289 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2290 
2291 
2292 	// Percent number
2293 	aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER );
2294     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2295 
2296 	// 0%
2297 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2298 	ImpInsertFormat( aFormatSeq[nIdx],
2299 		CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT ));
2300 
2301 	// 0.00%
2302 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2303 	ImpInsertFormat( aFormatSeq[nIdx],
2304 		CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 ));
2305 
2306 
2307 
2308     // Currency. NO default standard option! Default is determined of locale
2309     // data default currency and format is generated if needed.
2310 	aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2311     if (LocaleDataWrapper::areChecksEnabled())
2312     {
2313         // though no default desired here, test for correctness of locale data
2314         ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2315     }
2316 
2317 	// #,##0
2318 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2319 	bDefault = aFormatSeq[nIdx].Default;
2320 	aFormatSeq[nIdx].Default = sal_False;
2321 	ImpInsertFormat( aFormatSeq[nIdx],
2322 		CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY ));
2323 	aFormatSeq[nIdx].Default = bDefault;
2324 
2325 	// #,##0.00
2326 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2327 	bDefault = aFormatSeq[nIdx].Default;
2328 	aFormatSeq[nIdx].Default = sal_False;
2329 	ImpInsertFormat( aFormatSeq[nIdx],
2330 		CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 ));
2331 	aFormatSeq[nIdx].Default = bDefault;
2332 
2333 	// #,##0 negative red
2334 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2335 	bDefault = aFormatSeq[nIdx].Default;
2336 	aFormatSeq[nIdx].Default = sal_False;
2337 	ImpInsertFormat( aFormatSeq[nIdx],
2338 		CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 ));
2339 	aFormatSeq[nIdx].Default = bDefault;
2340 
2341 	// #,##0.00 negative red
2342 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2343 	bDefault = aFormatSeq[nIdx].Default;
2344 	aFormatSeq[nIdx].Default = sal_False;
2345 	ImpInsertFormat( aFormatSeq[nIdx],
2346 		CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 ));
2347 	aFormatSeq[nIdx].Default = bDefault;
2348 
2349 	// #,##0.00 USD   since number formatter version 3
2350 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2351 	bDefault = aFormatSeq[nIdx].Default;
2352 	aFormatSeq[nIdx].Default = sal_False;
2353 	pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2354 		CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 ));
2355 	if ( pNewFormat )
2356 		pNewFormat->SetUsed(sal_True);		// must be saved for older versions
2357 	aFormatSeq[nIdx].Default = bDefault;
2358 
2359 	// #.##0,--   since number formatter version 6
2360 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2361 	bDefault = aFormatSeq[nIdx].Default;
2362 	aFormatSeq[nIdx].Default = sal_False;
2363 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2364 		CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ),
2365 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2366 	aFormatSeq[nIdx].Default = bDefault;
2367 
2368 
2369 
2370 	// Date
2371 	aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE );
2372     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2373 
2374 	// DD.MM.YY   System
2375 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2376 	ImpInsertFormat( aFormatSeq[nIdx],
2377 		CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE ));
2378 
2379 	// NN DD.MMM YY
2380 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2381 	ImpInsertFormat( aFormatSeq[nIdx],
2382 		CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 ));
2383 
2384 	// DD.MM.YY   def/System
2385 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2386 	ImpInsertFormat( aFormatSeq[nIdx],
2387 		CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 ));
2388 
2389 	// DD MMM
2390 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2391 	ImpInsertFormat( aFormatSeq[nIdx],
2392 		CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 ));
2393 
2394 	// MMMM
2395 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2396 	ImpInsertFormat( aFormatSeq[nIdx],
2397 		CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 ));
2398 
2399 	// QQ YY
2400 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2401 	ImpInsertFormat( aFormatSeq[nIdx],
2402 		CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 ));
2403 
2404 	// DD.MM.YYYY   since number formatter version 2, was DD.MM.[YY]YY
2405 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2406 	pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2407 		CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 ));
2408 	if ( pNewFormat )
2409 		pNewFormat->SetUsed(sal_True);		// must be saved for older versions
2410 
2411 	// DD.MM.YY   def/System, since number formatter version 6
2412 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2413 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2414 		CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ),
2415 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2416 
2417 	// NNN, D. MMMM YYYY   System
2418 	// Long day of week: "NNNN" instead of "NNN," because of compatibility
2419 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2420 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2421 		CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ),
2422 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2423 
2424 	// Hard coded but system (regional settings) delimiters dependent long date formats
2425 	// since numberformatter version 6
2426 
2427 	// D. MMM YY   def/System
2428 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2429 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2430 		CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ),
2431 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2432 
2433 	//! Unfortunally TLOT intended only 10 builtin formats per category, more
2434 	//! would overwrite the next category (ZF_STANDARD_TIME) :-((
2435 	//! Therefore they are inserted with nNewExtended++ (which is also limited)
2436 
2437 	// D. MMM YYYY   def/System
2438 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2439 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2440 		CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ),
2441 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2442 
2443 	// D. MMMM YYYY   def/System
2444 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2445 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2446 		CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ),
2447 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2448 
2449 	// NN, D. MMM YY   def/System
2450 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2451 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2452 		CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ),
2453 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2454 
2455 	// NN, D. MMMM YYYY   def/System
2456 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2457 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2458 		CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ),
2459 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2460 
2461 	// NNN, D. MMMM YYYY   def/System
2462 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2463 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2464 		CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ),
2465 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2466 
2467 	// Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2468 
2469 	// D. MMM. YYYY   DIN/EN
2470 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2471 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2472 		CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ),
2473 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2474 
2475 	// D. MMMM YYYY   DIN/EN
2476 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2477 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2478 		CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ),
2479 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2480 
2481 	// MM-DD   DIN/EN
2482 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2483 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2484 		CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ),
2485 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2486 
2487 	// YY-MM-DD   DIN/EN
2488 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2489 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2490 		CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ),
2491 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2492 
2493 	// YYYY-MM-DD   DIN/EN
2494 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2495 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2496 		CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ),
2497 		SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2498 
2499 
2500 
2501 	// Time
2502 	aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME );
2503     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2504 
2505 	// HH:MM
2506 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2507 	ImpInsertFormat( aFormatSeq[nIdx],
2508 		CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME ));
2509 
2510 	// HH:MM:SS
2511 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2512 	ImpInsertFormat( aFormatSeq[nIdx],
2513 		CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 ));
2514 
2515 	// HH:MM AM/PM
2516 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2517 	ImpInsertFormat( aFormatSeq[nIdx],
2518 		CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 ));
2519 
2520 	// HH:MM:SS AM/PM
2521 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2522 	ImpInsertFormat( aFormatSeq[nIdx],
2523 		CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 ));
2524 
2525 	// [HH]:MM:SS
2526 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2527 	ImpInsertFormat( aFormatSeq[nIdx],
2528 		CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 ));
2529 
2530 	// MM:SS,00
2531 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2532 	ImpInsertFormat( aFormatSeq[nIdx],
2533 		CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 ));
2534 
2535 	// [HH]:MM:SS,00
2536 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2537 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2538 		CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ),
2539 		SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00 );
2540 
2541 
2542 
2543 	// DateTime
2544 	aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME );
2545     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2546 
2547 	// DD.MM.YY HH:MM   System
2548 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2549 	ImpInsertFormat( aFormatSeq[nIdx],
2550 		CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME ));
2551 
2552 	// DD.MM.YYYY HH:MM:SS   System
2553 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2554 	ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2555 		CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ),
2556 		SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2557 
2558 
2559 
2560 	// Scientific number
2561 	aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER );
2562     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2563 
2564 	// 0.00E+000
2565 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2566 	ImpInsertFormat( aFormatSeq[nIdx],
2567 		CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC ));
2568 
2569 	// 0.00E+00
2570 	nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2571 	ImpInsertFormat( aFormatSeq[nIdx],
2572 		CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 ));
2573 
2574 
2575 
2576 	// Fraction number (no default option)
2577 	i18n::NumberFormatCode aSingleFormatCode;
2578 
2579 	 // # ?/?
2580 	aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) );
2581 	String s25( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) );			// # ?/?
2582 	ImpInsertFormat( aSingleFormatCode,
2583 		CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION ));
2584 
2585 	// # ??/??
2586 	//! "??/" would be interpreted by the compiler as a trigraph for '\'
2587 	aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?\?/?\?" ) );
2588 	ImpInsertFormat( aSingleFormatCode,
2589 		CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 ));
2590 
2591 	// Week of year   must be appended here because of nNewExtended
2592     const NfKeywordTable & rKeyword = pFormatScanner->GetKeywords();
2593 	aSingleFormatCode.Code = rKeyword[NF_KEY_WW];
2594 	ImpInsertNewStandardFormat( aSingleFormatCode,
2595 		CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ),
2596 		SV_NUMBERFORMATTER_VERSION_NF_DATE_WW );
2597 
2598 
2599 
2600 	bIndexTableInitialized = sal_True;
2601 	DBG_ASSERT( nNewExtended <= ZF_STANDARD_NEWEXTENDEDMAX,
2602 		"ImpGenerateFormats: overflow of nNewExtended standard formats" );
2603 
2604 	// Now all additional format codes provided by I18N, but only if not
2605 	// loading from old SO5 file format, then they are appended last.
2606 	if ( !bLoadingSO5 )
2607 		ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, sal_False );
2608 
2609 	if (bOldConvertMode)
2610 		pFormatScanner->SetConvertMode(sal_True);
2611 }
2612 
2613 
2614 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2615 			NumberFormatCodeWrapper& rNumberFormatCode, sal_Bool bAfterLoadingSO5 )
2616 {
2617 	using namespace ::com::sun::star;
2618 
2619 	SvNumberformat* pStdFormat =
2620 		(SvNumberformat*) aFTable.Get( CLOffset + ZF_STANDARD );
2621 	if ( !pStdFormat )
2622 	{
2623 		DBG_ERRORFILE( "ImpGenerateAdditionalFormats: no GENERAL format" );
2624 		return ;
2625 	}
2626 	sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
2627 	rNumberFormatCode.setLocale( GetLocale() );
2628 	sal_Int32 j;
2629 
2630 	// All currencies, this time with [$...] which was stripped in
2631 	// ImpGenerateFormats for old "automatic" currency formats.
2632 	uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2633 		rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2634     i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray();
2635 	sal_Int32 nCodes = aFormatSeq.getLength();
2636     ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2637 	for ( j = 0; j < nCodes; j++ )
2638 	{
2639 		if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2640 		{
2641 			DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" );
2642 			break;	// for
2643 		}
2644         if ( pFormatArr[j].Index < NF_INDEX_TABLE_ENTRIES &&
2645                 pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC )
2646 		{	// Insert only if not already inserted, but internal index must be
2647 			// above so ImpInsertFormat can distinguish it.
2648             sal_Int16 nOrgIndex = pFormatArr[j].Index;
2649             pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >(
2650                 pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2651             //! no default on currency
2652             sal_Bool bDefault = aFormatSeq[j].Default;
2653             aFormatSeq[j].Default = sal_False;
2654             if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2655 					SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2656 					bAfterLoadingSO5, nOrgIndex ) )
2657 				nPos++;
2658             pFormatArr[j].Index = nOrgIndex;
2659             aFormatSeq[j].Default = bDefault;
2660 		}
2661 	}
2662 
2663 	// all additional format codes provided by I18N that are not old standard index
2664 	aFormatSeq = rNumberFormatCode.getAllFormatCodes();
2665 	nCodes = aFormatSeq.getLength();
2666     if ( nCodes )
2667     {
2668         pFormatArr = aFormatSeq.getArray();
2669         // don't check ALL
2670         sal_Int32 nDef = ImpAdjustFormatCodeDefault( pFormatArr, nCodes, sal_False);
2671         // don't have any defaults here
2672         pFormatArr[nDef].Default = sal_False;
2673         for ( j = 0; j < nCodes; j++ )
2674         {
2675             if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2676             {
2677                 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" );
2678                 break;  // for
2679             }
2680             if ( pFormatArr[j].Index >= NF_INDEX_TABLE_ENTRIES )
2681                 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2682                         SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2683                         bAfterLoadingSO5 ) )
2684                     nPos++;
2685         }
2686     }
2687 
2688 	pStdFormat->SetLastInsertKey( (sal_uInt16)(nPos - CLOffset) );
2689 }
2690 
2691 
2692 void SvNumberFormatter::ImpGetPosCurrFormat( String& sPosStr, const String& rCurrSymbol )
2693 {
2694 	NfCurrencyEntry::CompletePositiveFormatString( sPosStr,
2695         rCurrSymbol, xLocaleData->getCurrPositiveFormat() );
2696 }
2697 
2698 void SvNumberFormatter::ImpGetNegCurrFormat( String& sNegStr, const String& rCurrSymbol )
2699 {
2700 	NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
2701         rCurrSymbol, xLocaleData->getCurrNegativeFormat() );
2702 }
2703 
2704 void SvNumberFormatter::GenerateFormat(String& sString,
2705 									   sal_uInt32 nIndex,
2706 									   LanguageType eLnge,
2707 									   sal_Bool bThousand,
2708 									   sal_Bool IsRed,
2709 									   sal_uInt16 nPrecision,
2710 									   sal_uInt16 nAnzLeading)
2711 {
2712 	if (eLnge == LANGUAGE_DONTKNOW)
2713         eLnge = IniLnge;
2714 	short eType = GetType(nIndex);
2715 	sal_uInt16 i;
2716 	ImpGenerateCL(eLnge);				// ggfs. neu Standard-
2717 									// formate anlegen
2718 	sString.Erase();
2719 
2720     utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2721     const xub_StrLen nDigitsInFirstGroup = static_cast<xub_StrLen>(aGrouping.get());
2722     const String& rThSep = GetNumThousandSep();
2723 	if (nAnzLeading == 0)
2724 	{
2725 		if (!bThousand)
2726 			sString += '#';
2727 		else
2728 		{
2729 			sString += '#';
2730 			sString += rThSep;
2731             sString.Expand( sString.Len() + nDigitsInFirstGroup, '#' );
2732 		}
2733 	}
2734 	else
2735 	{
2736 		for (i = 0; i < nAnzLeading; i++)
2737 		{
2738 			if (bThousand && i > 0 && i == aGrouping.getPos())
2739             {
2740 				sString.Insert( rThSep, 0 );
2741                 aGrouping.advance();
2742             }
2743 			sString.Insert('0',0);
2744 		}
2745 		if (bThousand && nAnzLeading < nDigitsInFirstGroup + 1)
2746 		{
2747 			for (i = nAnzLeading; i < nDigitsInFirstGroup + 1; i++)
2748 			{
2749 				if (bThousand && i % nDigitsInFirstGroup == 0)
2750 					sString.Insert( rThSep, 0 );
2751 				sString.Insert('#',0);
2752 			}
2753 		}
2754 	}
2755 	if (nPrecision > 0)
2756 	{
2757         sString += GetNumDecimalSep();
2758         sString.Expand( sString.Len() + nPrecision, '0' );
2759 	}
2760 	if (eType == NUMBERFORMAT_PERCENT)
2761 		sString += '%';
2762 	else if (eType == NUMBERFORMAT_CURRENCY)
2763 	{
2764 		String sNegStr = sString;
2765 		String aCurr;
2766 		const NfCurrencyEntry* pEntry;
2767 		sal_Bool bBank;
2768 		if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2769 		{
2770 			if ( pEntry )
2771 			{
2772 				sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2773                     xLocaleData->getCurrPositiveFormat(),
2774 					pEntry->GetPositiveFormat(), bBank );
2775 				sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2776                     xLocaleData->getCurrNegativeFormat(),
2777 					pEntry->GetNegativeFormat(), bBank );
2778 				pEntry->CompletePositiveFormatString( sString, bBank,
2779 					nPosiForm );
2780 				pEntry->CompleteNegativeFormatString( sNegStr, bBank,
2781 					nNegaForm );
2782 			}
2783 			else
2784             {   // assume currency abbreviation (AKA banking symbol), not symbol
2785 				sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2786                     xLocaleData->getCurrPositiveFormat(),
2787                     xLocaleData->getCurrPositiveFormat(), sal_True );
2788 				sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2789                     xLocaleData->getCurrNegativeFormat(),
2790                     xLocaleData->getCurrNegativeFormat(), sal_True );
2791 				NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr,
2792 					nPosiForm );
2793 				NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr,
2794 					nNegaForm );
2795 			}
2796 		}
2797 		else
2798         {   // "automatic" old style
2799             String aSymbol, aAbbrev;
2800             GetCompatibilityCurrency( aSymbol, aAbbrev );
2801             ImpGetPosCurrFormat( sString, aSymbol );
2802             ImpGetNegCurrFormat( sNegStr, aSymbol );
2803 		}
2804 		if (IsRed)
2805 		{
2806 			sString += ';';
2807 			sString += '[';
2808 			sString += pFormatScanner->GetRedString();
2809 			sString += ']';
2810 		}
2811 		else
2812 			sString += ';';
2813 		sString += sNegStr;
2814 	}
2815 	if (IsRed && eType != NUMBERFORMAT_CURRENCY)
2816 	{
2817 		String sTmpStr = sString;
2818 		sTmpStr += ';';
2819 		sTmpStr += '[';
2820 		sTmpStr += pFormatScanner->GetRedString();
2821 		sTmpStr += ']';
2822 		sTmpStr += '-';
2823 		sTmpStr +=sString;
2824 		sString = sTmpStr;
2825 	}
2826 }
2827 
2828 sal_Bool SvNumberFormatter::IsUserDefined(const String& sStr,
2829 									  LanguageType eLnge)
2830 {
2831 	if (eLnge == LANGUAGE_DONTKNOW)
2832         eLnge = IniLnge;
2833 	sal_uInt32 CLOffset = ImpGenerateCL(eLnge);				// ggfs. neu Standard-
2834 													// formate anlegen
2835 	eLnge = ActLnge;
2836 	sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
2837 	if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
2838 		return sal_True;
2839 	SvNumberformat* pEntry = aFTable.Get(nKey);
2840 	if ( pEntry && ((pEntry->GetType() & NUMBERFORMAT_DEFINED) != 0) )
2841 		return sal_True;
2842 	return sal_False;
2843 }
2844 
2845 sal_uInt32 SvNumberFormatter::GetEntryKey(const String& sStr,
2846 									 LanguageType eLnge)
2847 {
2848 	if (eLnge == LANGUAGE_DONTKNOW)
2849         eLnge = IniLnge;
2850 	sal_uInt32 CLOffset = ImpGenerateCL(eLnge);				// ggfs. neu Standard-
2851 													// formate anlegen
2852 	return ImpIsEntry(sStr, CLOffset, eLnge);
2853 }
2854 
2855 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
2856 {
2857 	if (eLnge == LANGUAGE_DONTKNOW)
2858         eLnge = IniLnge;
2859 	return GetStandardFormat(NUMBERFORMAT_NUMBER, eLnge);
2860 }
2861 
2862 short SvNumberFormatter::GetType(sal_uInt32 nFIndex)
2863 {
2864 	short eType;
2865 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
2866 	if (!pFormat)
2867 		eType = NUMBERFORMAT_UNDEFINED;
2868 	else
2869 	{
2870 		eType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
2871 		if (eType == 0)
2872 			eType = NUMBERFORMAT_DEFINED;
2873 	}
2874 	return eType;
2875 }
2876 
2877 void SvNumberFormatter::ClearMergeTable()
2878 {
2879     if ( pMergeTable )
2880     {
2881         sal_uInt32* pIndex = (sal_uInt32*) pMergeTable->First();
2882         while (pIndex)
2883         {
2884             delete pIndex;
2885             pIndex = pMergeTable->Next();
2886         }
2887         pMergeTable->Clear();
2888     }
2889 }
2890 
2891 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
2892 {
2893     if ( pMergeTable )
2894         ClearMergeTable();
2895     else
2896         pMergeTable = new SvNumberFormatterIndexTable;
2897 	sal_uInt32 nCLOffset = 0;
2898 	sal_uInt32 nOldKey, nOffset, nNewKey;
2899 	sal_uInt32* pNewIndex;
2900 	SvNumberformat* pNewEntry;
2901 	SvNumberformat* pFormat = rTable.aFTable.First();
2902 	while (pFormat)
2903 	{
2904 		nOldKey = rTable.aFTable.GetCurKey();
2905 		nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET;		// relativIndex
2906 		if (nOffset == 0)									// 1. Format von CL
2907 			nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
2908 
2909 		if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE)		// Std.form.
2910 		{
2911 			nNewKey = nCLOffset + nOffset;
2912 			if (!aFTable.Get(nNewKey))					// noch nicht da
2913 			{
2914 //				pNewEntry = new SvNumberformat(*pFormat);	// Copy reicht nicht !!!
2915 				pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2916 				if (!aFTable.Insert(nNewKey, pNewEntry))
2917 					delete pNewEntry;
2918 			}
2919 			if (nNewKey != nOldKey)						// neuer Index
2920 			{
2921 				pNewIndex = new sal_uInt32(nNewKey);
2922 				if (!pMergeTable->Insert(nOldKey,pNewIndex))
2923 					delete pNewIndex;
2924 			}
2925 		}
2926 		else											// benutzerdef.
2927 		{
2928 //			pNewEntry = new SvNumberformat(*pFormat);	// Copy reicht nicht !!!
2929 			pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2930 			nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
2931 							  nCLOffset,
2932 							  pFormat->GetLanguage());
2933 			if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden
2934 				delete pNewEntry;
2935 			else
2936 			{
2937 				SvNumberformat* pStdFormat =
2938 						(SvNumberformat*) aFTable.Get(nCLOffset + ZF_STANDARD);
2939 				sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey();
2940 				nNewKey = nPos+1;
2941 				if (nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
2942 				{
2943 					DBG_ERROR(
2944 						"SvNumberFormatter:: Zu viele Formate pro CL");
2945 					delete pNewEntry;
2946 				}
2947 				else if (!aFTable.Insert(nNewKey, pNewEntry))
2948 						delete pNewEntry;
2949 				else
2950 					pStdFormat->SetLastInsertKey((sal_uInt16) (nNewKey - nCLOffset));
2951 			}
2952 			if (nNewKey != nOldKey)						// neuer Index
2953 			{
2954 				pNewIndex = new sal_uInt32(nNewKey);
2955 				if (!pMergeTable->Insert(nOldKey,pNewIndex))
2956 					delete pNewIndex;
2957 			}
2958 		}
2959 		pFormat = rTable.aFTable.Next();
2960 	}
2961 	return pMergeTable;
2962 }
2963 
2964 
2965 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
2966 {
2967     if (!HasMergeFmtTbl())
2968         return SvNumberFormatterMergeMap();
2969 
2970     SvNumberFormatterMergeMap aMap;
2971     for (sal_uInt32* pIndex = pMergeTable->First(); pIndex; pIndex = pMergeTable->Next())
2972     {
2973         sal_uInt32 nOldKey = pMergeTable->GetCurKey();
2974         aMap.insert( SvNumberFormatterMergeMap::value_type( nOldKey, *pIndex));
2975     }
2976     ClearMergeTable();
2977 	return aMap;
2978 }
2979 
2980 
2981 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
2982 		LanguageType eLnge )
2983 {
2984 	if ( eLnge == LANGUAGE_DONTKNOW )
2985         eLnge = IniLnge;
2986     if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
2987 		return nFormat;		// es bleibt wie es ist
2988 	sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET;		// relativIndex
2989 	if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
2990 		return nFormat;					// kein eingebautes Format
2991 	sal_uInt32 nCLOffset = ImpGenerateCL(eLnge);		// ggbf. generieren
2992 	return nCLOffset + nOffset;
2993 }
2994 
2995 
2996 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
2997 		LanguageType eLnge )
2998 {
2999 	if ( nTabOff >= NF_INDEX_TABLE_ENTRIES
3000 			|| theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND )
3001 		return NUMBERFORMAT_ENTRY_NOT_FOUND;
3002 	if ( eLnge == LANGUAGE_DONTKNOW )
3003         eLnge = IniLnge;
3004 	sal_uInt32 nCLOffset = ImpGenerateCL(eLnge);		// ggbf. generieren
3005 	return nCLOffset + theIndexTable[nTabOff];
3006 }
3007 
3008 
3009 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
3010 {
3011 	sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET;		// relativIndex
3012 	if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3013 		return NF_INDEX_TABLE_ENTRIES;		// kein eingebautes Format
3014 	for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3015 	{
3016 		if ( theIndexTable[j] == nOffset )
3017 			return (NfIndexTableOffset) j;
3018 	}
3019 	return NF_INDEX_TABLE_ENTRIES;		// bad luck
3020 }
3021 
3022 
3023 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal )
3024 {
3025 	pStringScanner->SetYear2000( nVal );
3026 }
3027 
3028 
3029 sal_uInt16 SvNumberFormatter::GetYear2000() const
3030 {
3031 	return pStringScanner->GetYear2000();
3032 }
3033 
3034 
3035 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear ) const
3036 {
3037 	if ( nYear < 100 )
3038 		return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3039 			pStringScanner->GetYear2000() );
3040 	return nYear;
3041 }
3042 
3043 
3044 // static
3045 sal_uInt16 SvNumberFormatter::GetYear2000Default()
3046 {
3047 	return (sal_uInt16) ::utl::MiscCfg().GetYear2000();
3048 }
3049 
3050 
3051 // static
3052 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3053 {
3054     ::osl::MutexGuard aGuard( GetMutex() );
3055 	while ( !bCurrencyTableInitialized )
3056 		ImpInitCurrencyTable();
3057 	return theCurrencyTable::get();
3058 }
3059 
3060 
3061 // static
3062 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3063 {
3064     // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3065 	const NfCurrencyTable& rTable = GetTheCurrencyTable();
3066 	return nSystemCurrencyPosition ? rTable[nSystemCurrencyPosition] : NULL;
3067 }
3068 
3069 
3070 // static
3071 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3072 {
3073     if ( eLang == LANGUAGE_SYSTEM )
3074 	{
3075 		const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3076 		return pCurr ? *pCurr : *(GetTheCurrencyTable()[0]);
3077 	}
3078 	else
3079 	{
3080         eLang = MsLangId::getRealLanguage( eLang );
3081 		const NfCurrencyTable& rTable = GetTheCurrencyTable();
3082 		sal_uInt16 nCount = rTable.Count();
3083 		const NfCurrencyEntryPtr* ppData = rTable.GetData();
3084 		for ( sal_uInt16 j = 0; j < nCount; j++, ppData++ )
3085 		{
3086 			if ( (*ppData)->GetLanguage() == eLang )
3087 				return **ppData;
3088 		}
3089 		return *(rTable[0]);
3090 	}
3091 }
3092 
3093 
3094 // static
3095 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(
3096         const String& rAbbrev, LanguageType eLang )
3097 {
3098     eLang = MsLangId::getRealLanguage( eLang );
3099     const NfCurrencyTable& rTable = GetTheCurrencyTable();
3100     sal_uInt16 nCount = rTable.Count();
3101     const NfCurrencyEntryPtr* ppData = rTable.GetData();
3102     for ( sal_uInt16 j = 0; j < nCount; j++, ppData++ )
3103     {
3104         if ( (*ppData)->GetLanguage() == eLang &&
3105                 (*ppData)->GetBankSymbol() == rAbbrev )
3106             return *ppData;
3107     }
3108     return NULL;
3109 }
3110 
3111 
3112 // static
3113 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry(
3114         const String& rSymbol, const String& rAbbrev )
3115 {
3116 	if (!bCurrencyTableInitialized)
3117         GetTheCurrencyTable();      // just for initialization
3118     const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3119     sal_uInt16 nCount = rTable.Count();
3120     const NfCurrencyEntryPtr* ppData = rTable.GetData();
3121     for ( sal_uInt16 j = 0; j < nCount; j++, ppData++ )
3122     {
3123         if ( (*ppData)->GetSymbol() == rSymbol &&
3124                 (*ppData)->GetBankSymbol() == rAbbrev )
3125             return *ppData;
3126     }
3127     return NULL;
3128 }
3129 
3130 
3131 // static
3132 IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter, CurrencyChangeLink, void*, EMPTYARG )
3133 {
3134     ::osl::MutexGuard aGuard( GetMutex() );
3135     String aAbbrev;
3136     LanguageType eLang = LANGUAGE_SYSTEM;
3137     SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3138     SetDefaultSystemCurrency( aAbbrev, eLang );
3139     return 0;
3140 }
3141 
3142 
3143 // static
3144 void SvNumberFormatter::SetDefaultSystemCurrency( const String& rAbbrev, LanguageType eLang )
3145 {
3146     ::osl::MutexGuard aGuard( GetMutex() );
3147     if ( eLang == LANGUAGE_SYSTEM )
3148         eLang = SvtSysLocale().GetLanguage();
3149     const NfCurrencyTable& rTable = GetTheCurrencyTable();
3150     sal_uInt16 nCount = rTable.Count();
3151     const NfCurrencyEntryPtr* ppData = rTable.GetData();
3152     if ( rAbbrev.Len() )
3153     {
3154         for ( sal_uInt16 j = 0; j < nCount; j++, ppData++ )
3155         {
3156             if ( (*ppData)->GetLanguage() == eLang && (*ppData)->GetBankSymbol() == rAbbrev )
3157             {
3158                 nSystemCurrencyPosition = j;
3159                 return ;
3160             }
3161         }
3162     }
3163     else
3164     {
3165         for ( sal_uInt16 j = 0; j < nCount; j++, ppData++ )
3166         {
3167             if ( (*ppData)->GetLanguage() == eLang )
3168             {
3169                 nSystemCurrencyPosition = j;
3170                 return ;
3171             }
3172         }
3173     }
3174     nSystemCurrencyPosition = 0;    // not found => simple SYSTEM
3175 }
3176 
3177 
3178 void SvNumberFormatter::ResetDefaultSystemCurrency()
3179 {
3180     nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3181 }
3182 
3183 
3184 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3185 {
3186 	if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3187 	{
3188 		xub_StrLen nCheck;
3189 		short nType;
3190 		NfWSStringsDtor aCurrList;
3191 		sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3192 			GetCurrencyEntry( LANGUAGE_SYSTEM ), sal_False );
3193 		DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency System standard format?!?" );
3194 		// if already loaded or user defined nDefaultSystemCurrencyFormat
3195 		// will be set to the right value
3196 		PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType,
3197 			nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3198 		DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3199 		DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3200 			"nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3201 	}
3202 	return nDefaultSystemCurrencyFormat;
3203 }
3204 
3205 
3206 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3207 {
3208 	sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3209 	sal_uInt32 nDefaultCurrencyFormat =
3210 		(sal_uInt32)(sal_uLong) aDefaultFormatKeys.Get( CLOffset + ZF_STANDARD_CURRENCY );
3211 	if ( !nDefaultCurrencyFormat )
3212 		nDefaultCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3213 	if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3214 	{
3215 		// look for a defined standard
3216 		sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3217 		sal_uInt32 nKey;
3218 		aFTable.Seek( CLOffset );
3219 		while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey )
3220 		{
3221 			const SvNumberformat* pEntry =
3222 				(const SvNumberformat*) aFTable.GetCurObject();
3223 			if ( pEntry->IsStandard() && (pEntry->GetType() & NUMBERFORMAT_CURRENCY) )
3224 			{
3225 				nDefaultCurrencyFormat = nKey;
3226 				break;	// while
3227 			}
3228 			aFTable.Next();
3229 		}
3230 
3231 		if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3232 		{	// none found, create one
3233 			xub_StrLen nCheck;
3234 			short nType;
3235 			NfWSStringsDtor aCurrList;
3236 			sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3237 				GetCurrencyEntry( ActLnge ), sal_False );
3238 			DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency standard format?" );
3239 			if ( aCurrList.Count() )
3240 			{
3241 				// if already loaded or user defined nDefaultSystemCurrencyFormat
3242 				// will be set to the right value
3243 				PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType,
3244 					nDefaultCurrencyFormat, ActLnge );
3245 				DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3246 				DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3247 					"nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3248 			}
3249 			// old automatic currency format as a last resort
3250 			if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3251 				nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3252 			else
3253 			{	// mark as standard so that it is found next time
3254 				SvNumberformat* pEntry = aFTable.Get( nDefaultCurrencyFormat );
3255 				if ( pEntry )
3256 					pEntry->SetStandard();
3257 			}
3258 		}
3259 		aDefaultFormatKeys.Insert( CLOffset + ZF_STANDARD_CURRENCY,
3260 			(void*) nDefaultCurrencyFormat );
3261 	}
3262 	return nDefaultCurrencyFormat;
3263 }
3264 
3265 
3266 // static
3267 // try to make it inline if possible since this a loop body
3268 // sal_True: continue; sal_False: break loop, if pFoundEntry==NULL dupe found
3269 #ifndef DBG_UTIL
3270 inline
3271 #endif
3272 	sal_Bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3273 		const NfCurrencyEntry*& pFoundEntry, sal_Bool& bFoundBank,
3274         const NfCurrencyEntry* pData, sal_uInt16 nPos, const String& rSymbol )
3275 {
3276 	sal_Bool bFound;
3277 	if ( pData->GetSymbol() == rSymbol )
3278 	{
3279 		bFound = sal_True;
3280 		bFoundBank = sal_False;
3281 	}
3282 	else if ( pData->GetBankSymbol() == rSymbol )
3283 	{
3284 		bFound = sal_True;
3285 		bFoundBank = sal_True;
3286 	}
3287 	else
3288 		bFound = sal_False;
3289 	if ( bFound )
3290 	{
3291 		if ( pFoundEntry && pFoundEntry != pData )
3292 		{
3293 			pFoundEntry = NULL;
3294 			return sal_False;	// break loop, not unique
3295 		}
3296 		if ( nPos == 0 )
3297 		{	// first entry is SYSTEM
3298 			pFoundEntry = MatchSystemCurrency();
3299 			if ( pFoundEntry )
3300 				return sal_False;	// break loop
3301 				// even if there are more matching entries
3302 				// this one is propably the one we are looking for
3303 			else
3304 				pFoundEntry = pData;
3305 		}
3306 		else
3307 			pFoundEntry = pData;
3308 	}
3309 	return sal_True;
3310 }
3311 
3312 
3313 sal_Bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat,
3314 			String& rStr, const NfCurrencyEntry** ppEntry /* = NULL */,
3315 			sal_Bool* pBank /* = NULL */ ) const
3316 {
3317 	rStr.Erase();
3318 	if ( ppEntry )
3319 		*ppEntry = NULL;
3320 	if ( pBank )
3321 		*pBank = sal_False;
3322 	SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get( nFormat );
3323 	if ( pFormat )
3324 	{
3325 		String aSymbol, aExtension;
3326 		if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3327 		{
3328 			if ( ppEntry )
3329 			{
3330 				sal_Bool bFoundBank = sal_False;
3331 				// we definiteley need an entry matching the format code string
3332 				const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3333 					bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3334 					sal_True );
3335 				if ( pFoundEntry )
3336 				{
3337 					*ppEntry = pFoundEntry;
3338 					if ( pBank )
3339 						*pBank = bFoundBank;
3340 					pFoundEntry->BuildSymbolString( rStr, bFoundBank );
3341 				}
3342 			}
3343 			if ( !rStr.Len() )
3344 			{	// analog zu BuildSymbolString
3345 				rStr  = '[';
3346 				rStr += '$';
3347 				if ( aSymbol.Search( '-' ) != STRING_NOTFOUND ||
3348 						aSymbol.Search( ']' ) != STRING_NOTFOUND )
3349 				{
3350 					rStr += '"';
3351 					rStr += aSymbol;
3352 					rStr += '"';
3353 				}
3354 				else
3355 					rStr += aSymbol;
3356 				if ( aExtension.Len() )
3357 					rStr += aExtension;
3358 				rStr += ']';
3359 			}
3360 			return sal_True;
3361 		}
3362 	}
3363 	return sal_False;
3364 }
3365 
3366 
3367 // static
3368 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( sal_Bool & bFoundBank,
3369 			const String& rSymbol, const String& rExtension,
3370             LanguageType eFormatLanguage, sal_Bool bOnlyStringLanguage )
3371 {
3372 	xub_StrLen nExtLen = rExtension.Len();
3373 	LanguageType eExtLang;
3374 	if ( nExtLen )
3375 	{
3376 		sal_Int32 nExtLang = ::rtl::OUString( rExtension ).toInt32( 16 );
3377 		if ( !nExtLang )
3378 			eExtLang = LANGUAGE_DONTKNOW;
3379 		else
3380 			eExtLang = (LanguageType) ((nExtLang < 0) ?
3381 				-nExtLang : nExtLang);
3382 	}
3383 	else
3384 		eExtLang = LANGUAGE_DONTKNOW;
3385 	const NfCurrencyEntry* pFoundEntry = NULL;
3386 	const NfCurrencyTable& rTable = GetTheCurrencyTable();
3387 	sal_uInt16 nCount = rTable.Count();
3388 	sal_Bool bCont = sal_True;
3389 
3390 	// first try with given extension language/country
3391 	if ( nExtLen )
3392 	{
3393 		const NfCurrencyEntryPtr* ppData = rTable.GetData();
3394 		for ( sal_uInt16 j = 0; j < nCount && bCont; j++, ppData++ )
3395 		{
3396 			LanguageType eLang = (*ppData)->GetLanguage();
3397 			if ( eLang == eExtLang ||
3398 					((eExtLang == LANGUAGE_DONTKNOW) &&
3399 					(eLang == LANGUAGE_SYSTEM))
3400 				)
3401 			{
3402 				bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3403 					*ppData, j, rSymbol );
3404 			}
3405 		}
3406 	}
3407 
3408 	// ok?
3409 	if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3410 		return pFoundEntry;
3411 
3412 	if ( !bOnlyStringLanguage )
3413 	{
3414 		// now try the language/country of the number format
3415 		const NfCurrencyEntryPtr* ppData = rTable.GetData();
3416 		for ( sal_uInt16 j = 0; j < nCount && bCont; j++, ppData++ )
3417 		{
3418 			LanguageType eLang = (*ppData)->GetLanguage();
3419 			if ( eLang == eFormatLanguage ||
3420 					((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3421 					(eLang == LANGUAGE_SYSTEM))
3422 				)
3423 			{
3424 				bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3425 					*ppData, j, rSymbol );
3426 			}
3427 		}
3428 
3429 		// ok?
3430 		if ( pFoundEntry || !bCont )
3431 			return pFoundEntry;
3432 	}
3433 
3434     // then try without language/country if no extension specified
3435     if ( !nExtLen )
3436 	{
3437 		const NfCurrencyEntryPtr* ppData = rTable.GetData();
3438 		for ( sal_uInt16 j = 0; j < nCount && bCont; j++, ppData++ )
3439 		{
3440 			bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3441 				*ppData, j, rSymbol );
3442 		}
3443 	}
3444 
3445 	return pFoundEntry;
3446 }
3447 
3448 
3449 void SvNumberFormatter::GetCompatibilityCurrency( String& rSymbol, String& rAbbrev ) const
3450 {
3451     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >
3452         xCurrencies = xLocaleData->getAllCurrencies();
3453     sal_Int32 nCurrencies = xCurrencies.getLength();
3454     sal_Int32 j;
3455     for ( j=0; j < nCurrencies; ++j )
3456     {
3457         if ( xCurrencies[j].UsedInCompatibleFormatCodes )
3458         {
3459             rSymbol = xCurrencies[j].Symbol;
3460             rAbbrev = xCurrencies[j].BankSymbol;
3461             break;
3462         }
3463     }
3464     if ( j >= nCurrencies )
3465     {
3466         if (LocaleDataWrapper::areChecksEnabled())
3467         {
3468             String aMsg( RTL_CONSTASCII_USTRINGPARAM(
3469                         "GetCompatibilityCurrency: none?"));
3470             LocaleDataWrapper::outputCheckMessage(
3471                     xLocaleData->appendLocaleInfo( aMsg));
3472         }
3473         rSymbol = xLocaleData->getCurrSymbol();
3474         rAbbrev = xLocaleData->getCurrBankSymbol();
3475     }
3476 }
3477 
3478 
3479 void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3480 {
3481 	short nPos = -1;		// -1:=unknown, 0:=vorne, 1:=hinten
3482 	short nNeg = -1;
3483 	switch ( rCurr.GetPositiveFormat() )
3484 	{
3485 		case 0:                                        	// $1
3486 			nPos = 0;
3487 		break;
3488 		case 1:											// 1$
3489 			nPos = 1;
3490 		break;
3491 		case 2:											// $ 1
3492 			nPos = 0;
3493 		break;
3494 		case 3:											// 1 $
3495 			nPos = 1;
3496 		break;
3497 		default:
3498 			LocaleDataWrapper::outputCheckMessage(
3499                     "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3500 		break;
3501 	}
3502 	switch ( rCurr.GetNegativeFormat() )
3503 	{
3504 		case 0:                                        	// ($1)
3505 			nNeg = 0;
3506 		break;
3507 		case 1:                                        	// -$1
3508 			nNeg = 0;
3509 		break;
3510 		case 2:                                        	// $-1
3511 			nNeg = 0;
3512 		break;
3513 		case 3:                                        	// $1-
3514 			nNeg = 0;
3515 		break;
3516 		case 4:                                        	// (1$)
3517 			nNeg = 1;
3518 		break;
3519 		case 5:                                        	// -1$
3520 			nNeg = 1;
3521 		break;
3522 		case 6:                                        	// 1-$
3523 			nNeg = 1;
3524 		break;
3525 		case 7:                                        	// 1$-
3526 			nNeg = 1;
3527 		break;
3528 		case 8:                                        	// -1 $
3529 			nNeg = 1;
3530 		break;
3531 		case 9:                                        	// -$ 1
3532 			nNeg = 0;
3533 		break;
3534 		case 10:                                        // 1 $-
3535 			nNeg = 1;
3536 		break;
3537 		case 11:                                        // $ -1
3538 			nNeg = 0;
3539 		break;
3540 		case 12 : 										// $ 1-
3541 			nNeg = 0;
3542 		break;
3543 		case 13 : 										// 1- $
3544 			nNeg = 1;
3545 		break;
3546 		case 14 : 										// ($ 1)
3547 			nNeg = 0;
3548 		break;
3549 		case 15 :										// (1 $)
3550 			nNeg = 1;
3551 		break;
3552 		default:
3553 			LocaleDataWrapper::outputCheckMessage(
3554                     "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3555 		break;
3556 	}
3557 	if ( nPos >= 0 && nNeg >= 0 && nPos != nNeg )
3558 	{
3559 		ByteString aStr( "positions of currency symbols differ\nLanguage: " );
3560 		aStr += ByteString::CreateFromInt32( rCurr.GetLanguage() );
3561 		aStr += " <";
3562 		aStr += ByteString( rCurr.GetSymbol(), RTL_TEXTENCODING_UTF8 );
3563 		aStr += "> positive: ";
3564 		aStr += ByteString::CreateFromInt32( rCurr.GetPositiveFormat() );
3565 		aStr += ( nPos ? " (postfix)" : " (prefix)" );
3566 		aStr += ", negative: ";
3567 		aStr += ByteString::CreateFromInt32( rCurr.GetNegativeFormat() );
3568 		aStr += ( nNeg ? " (postfix)" : " (prefix)" );
3569 #if 0
3570 // seems that there really are some currencies which differ, e.g. YugoDinar
3571 		DBG_ERRORFILE( aStr.GetBuffer() );
3572 #endif
3573 	}
3574 }
3575 
3576 
3577 // static
3578 void SvNumberFormatter::ImpInitCurrencyTable()
3579 {
3580 	// racing condition possible:
3581     // ::osl::MutexGuard aGuard( GetMutex() );
3582 	// while ( !bCurrencyTableInitialized )
3583 	// 		ImpInitCurrencyTable();
3584     static sal_Bool bInitializing = sal_False;
3585     if ( bCurrencyTableInitialized || bInitializing )
3586 		return ;
3587     bInitializing = sal_True;
3588 
3589     RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svl", "er93726", "SvNumberFormatter::ImpInitCurrencyTable" );
3590 
3591     LanguageType eSysLang = SvtSysLocale().GetLanguage();
3592     LocaleDataWrapper* pLocaleData = new LocaleDataWrapper(
3593         ::comphelper::getProcessServiceFactory(),
3594         MsLangId::convertLanguageToLocale( eSysLang ) );
3595     // get user configured currency
3596     String aConfiguredCurrencyAbbrev;
3597     LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3598     SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3599         aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3600     sal_uInt16 nSecondarySystemCurrencyPosition = 0;
3601     sal_uInt16 nMatchingSystemCurrencyPosition = 0;
3602 	NfCurrencyEntryPtr pEntry;
3603 
3604 	// first entry is SYSTEM
3605     pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM );
3606 	theCurrencyTable::get().Insert( pEntry, 0 );
3607     sal_uInt16 nCurrencyPos = 1;
3608 
3609 	::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
3610 		LocaleDataWrapper::getInstalledLocaleNames();
3611 	sal_Int32 nLocaleCount = xLoc.getLength();
3612     RTL_LOGFILE_CONTEXT_TRACE1( aTimeLog, "number of locales: %ld", nLocaleCount );
3613     Locale const * const pLocales = xLoc.getConstArray();
3614     NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3615     NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3616     sal_uInt16 nLegacyOnlyCurrencyPos = 0;
3617 	for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
3618 	{
3619         LanguageType eLang = MsLangId::convertLocaleToLanguage(
3620                 pLocales[nLocale]);
3621 #if OSL_DEBUG_LEVEL > 1
3622 		LanguageType eReal = MsLangId::getRealLanguage( eLang );
3623 		if ( eReal != eLang ) {
3624 			sal_Bool bBreak;
3625             bBreak = sal_True;
3626         }
3627 #endif
3628         pLocaleData->setLocale( pLocales[nLocale] );
3629         Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3630 		sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3631         Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3632 
3633         // one default currency for each locale, insert first so it is found first
3634         sal_Int32 nDefault;
3635         for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3636         {
3637             if ( pCurrencies[nDefault].Default )
3638                 break;
3639         }
3640         if ( nDefault < nCurrencyCount )
3641             pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang );
3642         else
3643             pEntry = new NfCurrencyEntry( *pLocaleData, eLang );    // first or ShellsAndPebbles
3644 
3645         if (LocaleDataWrapper::areChecksEnabled())
3646             lcl_CheckCurrencySymbolPosition( *pEntry );
3647 
3648         rCurrencyTable.Insert( pEntry, nCurrencyPos++ );
3649         if ( !nSystemCurrencyPosition && (aConfiguredCurrencyAbbrev.Len() ?
3650                 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
3651                 pEntry->GetLanguage() == eConfiguredCurrencyLanguage : sal_False) )
3652             nSystemCurrencyPosition = nCurrencyPos-1;
3653         if ( !nMatchingSystemCurrencyPosition &&
3654                 pEntry->GetLanguage() == eSysLang )
3655             nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3656 
3657         // all remaining currencies for each locale
3658 		if ( nCurrencyCount > 1 )
3659 		{
3660 			sal_Int32 nCurrency;
3661 			for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3662 			{
3663                 if (pCurrencies[nCurrency].LegacyOnly)
3664                 {
3665                     pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3666                     rLegacyOnlyCurrencyTable.Insert( pEntry, nLegacyOnlyCurrencyPos++ );
3667                 }
3668                 else if ( nCurrency != nDefault )
3669                 {
3670                     pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3671                     // no dupes
3672                     sal_Bool bInsert = sal_True;
3673                     NfCurrencyEntry const * const * pData = rCurrencyTable.GetData();
3674                     sal_uInt16 n = rCurrencyTable.Count();
3675                     pData++;        // skip first SYSTEM entry
3676                     for ( sal_uInt16 j=1; j<n; j++ )
3677                     {
3678                         if ( *(*pData++) == *pEntry )
3679                         {
3680                             bInsert = sal_False;
3681                             break;  // for
3682                         }
3683                     }
3684                     if ( !bInsert )
3685                         delete pEntry;
3686                     else
3687                     {
3688                         rCurrencyTable.Insert( pEntry, nCurrencyPos++ );
3689                         if ( !nSecondarySystemCurrencyPosition &&
3690                                 (aConfiguredCurrencyAbbrev.Len() ?
3691                                 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
3692                                 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
3693                             nSecondarySystemCurrencyPosition = nCurrencyPos-1;
3694                         if ( !nMatchingSystemCurrencyPosition &&
3695                                 pEntry->GetLanguage() ==  eSysLang )
3696                             nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3697                     }
3698                 }
3699 			}
3700 		}
3701 	}
3702     if ( !nSystemCurrencyPosition )
3703         nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
3704     if ((aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3705             LocaleDataWrapper::areChecksEnabled())
3706         LocaleDataWrapper::outputCheckMessage(
3707                 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3708     // match SYSTEM if no configured currency found
3709     if ( !nSystemCurrencyPosition )
3710         nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
3711     if ((!aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3712             LocaleDataWrapper::areChecksEnabled())
3713         LocaleDataWrapper::outputCheckMessage(
3714                 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3715     delete pLocaleData;
3716     SvtSysLocaleOptions::SetCurrencyChangeLink(
3717         STATIC_LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) );
3718     bInitializing = sal_False;
3719 	bCurrencyTableInitialized = sal_True;
3720 }
3721 
3722 
3723 sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
3724 			const NfCurrencyEntry& rCurr, sal_Bool bBank ) const
3725 {
3726 	sal_uInt16 nDefault = 0;
3727 	if ( bBank )
3728 	{	// nur Bankensymbole
3729 		String aPositiveBank, aNegativeBank;
3730         rCurr.BuildPositiveFormatString( aPositiveBank, sal_True, *xLocaleData, 1 );
3731         rCurr.BuildNegativeFormatString( aNegativeBank, sal_True, *xLocaleData, 1 );
3732 
3733 		WSStringPtr pFormat1 = new String( aPositiveBank );
3734 		*pFormat1 += ';';
3735 		WSStringPtr pFormat2 = new String( *pFormat1 );
3736 
3737 		String aRed( '[' );
3738 		aRed += pFormatScanner->GetRedString();
3739 		aRed += ']';
3740 
3741 		*pFormat2 += aRed;
3742 
3743 		*pFormat1 += aNegativeBank;
3744 		*pFormat2 += aNegativeBank;
3745 
3746 		rStrArr.Insert( pFormat1, rStrArr.Count() );
3747 		rStrArr.Insert( pFormat2, rStrArr.Count() );
3748 		nDefault = rStrArr.Count() - 1;
3749 	}
3750 	else
3751 	{	// gemischte Formate wie in SvNumberFormatter::ImpGenerateFormats
3752 		// aber keine doppelten, wenn keine Nachkommastellen in Waehrung
3753 		String aPositive, aNegative, aPositiveNoDec, aNegativeNoDec,
3754 			aPositiveDashed, aNegativeDashed;
3755 		WSStringPtr pFormat1, pFormat2, pFormat3, pFormat4, pFormat5;
3756 
3757 		String aRed( '[' );
3758 		aRed += pFormatScanner->GetRedString();
3759 		aRed += ']';
3760 
3761         rCurr.BuildPositiveFormatString( aPositive, sal_False, *xLocaleData, 1 );
3762         rCurr.BuildNegativeFormatString( aNegative, sal_False, *xLocaleData, 1 );
3763 		if ( rCurr.GetDigits() )
3764 		{
3765             rCurr.BuildPositiveFormatString( aPositiveNoDec, sal_False, *xLocaleData, 0 );
3766             rCurr.BuildNegativeFormatString( aNegativeNoDec, sal_False, *xLocaleData, 0 );
3767             rCurr.BuildPositiveFormatString( aPositiveDashed, sal_False, *xLocaleData, 2 );
3768             rCurr.BuildNegativeFormatString( aNegativeDashed, sal_False, *xLocaleData, 2 );
3769 
3770 			pFormat1 = new String( aPositiveNoDec );
3771 			*pFormat1 += ';';
3772 			pFormat3 = new String( *pFormat1 );
3773 			pFormat5 = new String( aPositiveDashed );
3774 			*pFormat5 += ';';
3775 
3776 			*pFormat1 += aNegativeNoDec;
3777 
3778 			*pFormat3 += aRed;
3779 			*pFormat5 += aRed;
3780 
3781 			*pFormat3 += aNegativeNoDec;
3782 			*pFormat5 += aNegativeDashed;
3783 		}
3784 		else
3785 		{
3786 			pFormat1 = NULL;
3787 			pFormat3 = NULL;
3788 			pFormat5 = NULL;
3789 		}
3790 
3791 		pFormat2 = new String( aPositive );
3792 		*pFormat2 += ';';
3793 		pFormat4 = new String( *pFormat2 );
3794 
3795 		*pFormat2 += aNegative;
3796 
3797 		*pFormat4 += aRed;
3798 		*pFormat4 += aNegative;
3799 
3800 		if ( pFormat1 )
3801 			rStrArr.Insert( pFormat1, rStrArr.Count() );
3802 		rStrArr.Insert( pFormat2, rStrArr.Count() );
3803 		if ( pFormat3 )
3804 			rStrArr.Insert( pFormat3, rStrArr.Count() );
3805 		rStrArr.Insert( pFormat4, rStrArr.Count() );
3806 		nDefault = rStrArr.Count() - 1;
3807 		if ( pFormat5 )
3808 			rStrArr.Insert( pFormat5, rStrArr.Count() );
3809 	}
3810 	return nDefault;
3811 }
3812 
3813 
3814 //--- NfCurrencyEntry ----------------------------------------------------
3815 
3816 NfCurrencyEntry::NfCurrencyEntry()
3817 	:	eLanguage( LANGUAGE_DONTKNOW ),
3818 		nPositiveFormat(3),
3819 		nNegativeFormat(8),
3820 		nDigits(2),
3821 		cZeroChar('0')
3822 {
3823 }
3824 
3825 
3826 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3827 {
3828 	aSymbol			= rLocaleData.getCurrSymbol();
3829 	aBankSymbol		= rLocaleData.getCurrBankSymbol();
3830 	eLanguage		= eLang;
3831 	nPositiveFormat	= rLocaleData.getCurrPositiveFormat();
3832 	nNegativeFormat	= rLocaleData.getCurrNegativeFormat();
3833 	nDigits			= rLocaleData.getCurrDigits();
3834 	cZeroChar		= rLocaleData.getCurrZeroChar();
3835 }
3836 
3837 
3838 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr,
3839 			const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3840 {
3841 	aSymbol			= rCurr.Symbol;
3842 	aBankSymbol		= rCurr.BankSymbol;
3843 	eLanguage		= eLang;
3844 	nPositiveFormat	= rLocaleData.getCurrPositiveFormat();
3845 	nNegativeFormat	= rLocaleData.getCurrNegativeFormat();
3846     nDigits         = rCurr.DecimalPlaces;
3847 	cZeroChar		= rLocaleData.getCurrZeroChar();
3848 }
3849 
3850 
3851 sal_Bool NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
3852 {
3853 	return aSymbol		== r.aSymbol
3854 		&& aBankSymbol	== r.aBankSymbol
3855 		&& eLanguage	== r.eLanguage
3856 		;
3857 }
3858 
3859 
3860 void NfCurrencyEntry::SetEuro()
3861 {
3862 	aSymbol = NfCurrencyEntry::GetEuroSymbol();
3863 	aBankSymbol.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EUR" ) );
3864 	eLanguage		= LANGUAGE_DONTKNOW;
3865 	nPositiveFormat	= 3;
3866 	nNegativeFormat	= 8;
3867 	nDigits			= 2;
3868 	cZeroChar		= '0';
3869 }
3870 
3871 
3872 sal_Bool NfCurrencyEntry::IsEuro() const
3873 {
3874 	if ( aBankSymbol.EqualsAscii( "EUR" ) )
3875 		return sal_True;
3876 	String aEuro( NfCurrencyEntry::GetEuroSymbol() );
3877 	return aSymbol == aEuro;
3878 }
3879 
3880 
3881 void NfCurrencyEntry::ApplyVariableInformation( const NfCurrencyEntry& r )
3882 {
3883 	nPositiveFormat	= r.nPositiveFormat;
3884 	nNegativeFormat	= r.nNegativeFormat;
3885 	cZeroChar		= r.cZeroChar;
3886 }
3887 
3888 
3889 void NfCurrencyEntry::BuildSymbolString( String& rStr, sal_Bool bBank,
3890 			sal_Bool bWithoutExtension ) const
3891 {
3892 	rStr  = '[';
3893 	rStr += '$';
3894 	if ( bBank )
3895 		rStr += aBankSymbol;
3896 	else
3897 	{
3898 		if ( aSymbol.Search( '-' ) != STRING_NOTFOUND || aSymbol.Search( ']' ) != STRING_NOTFOUND )
3899 		{
3900 			rStr += '"';
3901 			rStr += aSymbol;
3902 			rStr += '"';
3903 		}
3904 		else
3905 			rStr += aSymbol;
3906 		if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
3907 		{
3908 			rStr += '-';
3909 			rStr += String::CreateFromInt32( sal_Int32( eLanguage ), 16 ).ToUpperAscii();
3910 		}
3911 	}
3912 	rStr += ']';
3913 }
3914 
3915 
3916 void NfCurrencyEntry::Impl_BuildFormatStringNumChars( String& rStr,
3917 			const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
3918 {
3919 	rStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###0" ) );
3920 	rStr.Insert( rLoc.getNumThousandSep(), 1 );
3921 	if ( nDecimalFormat && nDigits )
3922 	{
3923 		rStr += rLoc.getNumDecimalSep();
3924 		rStr.Expand( rStr.Len() + nDigits, (nDecimalFormat == 2 ? '-' : cZeroChar) );
3925 	}
3926 }
3927 
3928 
3929 void NfCurrencyEntry::BuildPositiveFormatString( String& rStr, sal_Bool bBank,
3930 			const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
3931 {
3932 	Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat );
3933 	sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3934 		rLoc.getCurrPositiveFormat(), nPositiveFormat, bBank );
3935 	CompletePositiveFormatString( rStr, bBank, nPosiForm );
3936 }
3937 
3938 
3939 void NfCurrencyEntry::BuildNegativeFormatString( String& rStr, sal_Bool bBank,
3940 			const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
3941 {
3942 	Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat );
3943 	sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3944 		rLoc.getCurrNegativeFormat(), nNegativeFormat, bBank );
3945 	CompleteNegativeFormatString( rStr, bBank, nNegaForm );
3946 }
3947 
3948 
3949 void NfCurrencyEntry::CompletePositiveFormatString( String& rStr, sal_Bool bBank,
3950 			sal_uInt16 nPosiForm ) const
3951 {
3952 	String aSymStr;
3953 	BuildSymbolString( aSymStr, bBank );
3954 	NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
3955 }
3956 
3957 
3958 void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr, sal_Bool bBank,
3959 			sal_uInt16 nNegaForm ) const
3960 {
3961 	String aSymStr;
3962 	BuildSymbolString( aSymStr, bBank );
3963 	NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
3964 }
3965 
3966 
3967 // static
3968 void NfCurrencyEntry::CompletePositiveFormatString( String& rStr,
3969 		const String& rSymStr, sal_uInt16 nPositiveFormat )
3970 {
3971 	switch( nPositiveFormat )
3972 	{
3973 		case 0:                                        	// $1
3974 			rStr.Insert( rSymStr , 0 );
3975 		break;
3976 		case 1:											// 1$
3977 			rStr += rSymStr;
3978 		break;
3979 		case 2:											// $ 1
3980 		{
3981 			rStr.Insert( ' ', 0 );
3982 			rStr.Insert( rSymStr, 0 );
3983 		}
3984 		break;
3985 		case 3:                                         // 1 $
3986 		{
3987 			rStr += ' ';
3988 			rStr += rSymStr;
3989 		}
3990 		break;
3991 		default:
3992 			DBG_ERROR("NfCurrencyEntry::CompletePositiveFormatString: unknown option");
3993 		break;
3994 	}
3995 }
3996 
3997 
3998 // static
3999 void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr,
4000 		const String& rSymStr, sal_uInt16 nNegativeFormat )
4001 {
4002 	switch( nNegativeFormat )
4003 	{
4004 		case 0:                                        	// ($1)
4005 		{
4006 			rStr.Insert( rSymStr, 0);
4007 			rStr.Insert('(',0);
4008 			rStr += ')';
4009 		}
4010 		break;
4011 		case 1:                                        	// -$1
4012 		{
4013 			rStr.Insert( rSymStr, 0);
4014 			rStr.Insert('-',0);
4015 		}
4016 		break;
4017 		case 2:                                        	// $-1
4018 		{
4019 			rStr.Insert('-',0);
4020 			rStr.Insert( rSymStr, 0);
4021 		}
4022 		break;
4023 		case 3:                                        	// $1-
4024 		{
4025 			rStr.Insert( rSymStr, 0);
4026 			rStr += '-';
4027 		}
4028 		break;
4029 		case 4:                                        	// (1$)
4030 		{
4031 			rStr.Insert('(',0);
4032 			rStr += rSymStr;
4033 			rStr += ')';
4034 		}
4035 		break;
4036 		case 5:                                        	// -1$
4037 		{
4038 			rStr += rSymStr;
4039 			rStr.Insert('-',0);
4040 		}
4041 		break;
4042 		case 6:                                        	// 1-$
4043 		{
4044 			rStr += '-';
4045 			rStr += rSymStr;
4046 		}
4047 		break;
4048 		case 7:                                        	// 1$-
4049 		{
4050 			rStr += rSymStr;
4051 			rStr += '-';
4052 		}
4053 		break;
4054 		case 8:                                        	// -1 $
4055 		{
4056 			rStr += ' ';
4057 			rStr += rSymStr;
4058 			rStr.Insert('-',0);
4059 		}
4060 		break;
4061 		case 9:                                        	// -$ 1
4062 		{
4063 			rStr.Insert(' ',0);
4064 			rStr.Insert( rSymStr, 0);
4065 			rStr.Insert('-',0);
4066 		}
4067 		break;
4068 		case 10:                                        // 1 $-
4069 		{
4070 			rStr += ' ';
4071 			rStr += rSymStr;
4072 			rStr += '-';
4073 		}
4074 		break;
4075 		case 11:                                        // $ -1
4076 		{
4077 			String aTmp( rSymStr );
4078 			aTmp += ' ';
4079 			aTmp += '-';
4080 			rStr.Insert( aTmp, 0 );
4081 		}
4082 		break;
4083 		case 12 : 										// $ 1-
4084 		{
4085 			rStr.Insert(' ', 0);
4086 			rStr.Insert( rSymStr, 0);
4087 			rStr += '-';
4088 		}
4089 		break;
4090 		case 13 : 										// 1- $
4091 		{
4092 			rStr += '-';
4093 			rStr += ' ';
4094 			rStr += rSymStr;
4095 		}
4096 		break;
4097 		case 14 : 										// ($ 1)
4098 		{
4099 			rStr.Insert(' ',0);
4100 			rStr.Insert( rSymStr, 0);
4101 			rStr.Insert('(',0);
4102 			rStr += ')';
4103 		}
4104 		break;
4105 		case 15 :										// (1 $)
4106 		{
4107 			rStr.Insert('(',0);
4108 			rStr += ' ';
4109 			rStr += rSymStr;
4110 			rStr += ')';
4111 		}
4112 		break;
4113 		default:
4114 			DBG_ERROR("NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4115 		break;
4116 	}
4117 }
4118 
4119 
4120 // static
4121 sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16
4122 #if ! NF_BANKSYMBOL_FIX_POSITION
4123             nIntlFormat
4124 #endif
4125             , sal_uInt16 nCurrFormat, sal_Bool bBank )
4126 {
4127 	if ( bBank )
4128 	{
4129 #if NF_BANKSYMBOL_FIX_POSITION
4130 		return 3;
4131 #else
4132 		switch ( nIntlFormat )
4133 		{
4134 			case 0:                                        	// $1
4135 				nIntlFormat = 2;                            // $ 1
4136 			break;
4137 			case 1:											// 1$
4138 				nIntlFormat = 3;                            // 1 $
4139 			break;
4140 			case 2:											// $ 1
4141 			break;
4142 			case 3:                                         // 1 $
4143 			break;
4144 			default:
4145 				DBG_ERROR("NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4146 			break;
4147 		}
4148 		return nIntlFormat;
4149 #endif
4150 	}
4151 	else
4152 		return nCurrFormat;
4153 }
4154 
4155 
4156 // nur aufrufen, wenn nCurrFormat wirklich mit Klammern ist
4157 sal_uInt16 lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat )
4158 {
4159 	short nSign = 0;		// -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4160 	switch ( nIntlFormat )
4161 	{
4162 		case 0:                                        	// ($1)
4163 		case 4:                                        	// (1$)
4164 		case 14 : 										// ($ 1)
4165 		case 15 :										// (1 $)
4166 			return nCurrFormat;
4167 		case 1:                                        	// -$1
4168 		case 5:                                        	// -1$
4169 		case 8:                                        	// -1 $
4170 		case 9:                                        	// -$ 1
4171 			nSign = 0;
4172 		break;
4173 		case 2:                                        	// $-1
4174 		case 6:                                        	// 1-$
4175 		case 11 : 										// $ -1
4176 		case 13 : 										// 1- $
4177 			nSign = 1;
4178 		break;
4179 		case 3:                                        	// $1-
4180 		case 7:                                        	// 1$-
4181 		case 10:                                        // 1 $-
4182 		case 12 : 										// $ 1-
4183 			nSign = 2;
4184 		break;
4185 		default:
4186 			DBG_ERROR("lcl_MergeNegativeParenthesisFormat: unknown option");
4187 		break;
4188 	}
4189 
4190 	switch ( nCurrFormat )
4191 	{
4192 		case 0:                                        	// ($1)
4193 			switch ( nSign )
4194 			{
4195 				case 0:
4196 					return 1;                           // -$1
4197 				case 1:
4198 					return 2;                           // $-1
4199 				case 2:
4200 					return 3;                           // $1-
4201 			}
4202 		break;
4203 		case 4:                                        	// (1$)
4204 			switch ( nSign )
4205 			{
4206 				case 0:
4207 					return 5;                           // -1$
4208 				case 1:
4209 					return 6;                           // 1-$
4210 				case 2:
4211 					return 7;                           // 1$-
4212 			}
4213 		break;
4214 		case 14 : 										// ($ 1)
4215 			switch ( nSign )
4216 			{
4217 				case 0:
4218 					return 9;                           // -$ 1
4219 				case 1:
4220 					return 11;                          // $ -1
4221 				case 2:
4222 					return 12;                          // $ 1-
4223 			}
4224 		break;
4225 		case 15 :										// (1 $)
4226 			switch ( nSign )
4227 			{
4228 				case 0:
4229 					return 8;                           // -1 $
4230 				case 1:
4231 					return 13;                          // 1- $
4232 				case 2:
4233 					return 10;                          // 1 $-
4234 			}
4235 		break;
4236 	}
4237 	return nCurrFormat;
4238 }
4239 
4240 
4241 // static
4242 sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4243 			sal_uInt16 nCurrFormat, sal_Bool bBank )
4244 {
4245 	if ( bBank )
4246 	{
4247 #if NF_BANKSYMBOL_FIX_POSITION
4248 		return 8;
4249 #else
4250 		switch ( nIntlFormat )
4251 		{
4252 			case 0:                                        	// ($1)
4253 //				nIntlFormat = 14;                           // ($ 1)
4254 				nIntlFormat = 9;                            // -$ 1
4255 			break;
4256 			case 1:                                        	// -$1
4257 				nIntlFormat = 9;                            // -$ 1
4258 			break;
4259 			case 2:                                        	// $-1
4260 				nIntlFormat = 11;                           // $ -1
4261 			break;
4262 			case 3:                                        	// $1-
4263 				nIntlFormat = 12;                           // $ 1-
4264 			break;
4265 			case 4:                                        	// (1$)
4266 //				nIntlFormat = 15;                           // (1 $)
4267 				nIntlFormat = 8;                            // -1 $
4268 			break;
4269 			case 5:                                        	// -1$
4270 				nIntlFormat = 8;                            // -1 $
4271 			break;
4272 			case 6:                                        	// 1-$
4273 				nIntlFormat = 13;                           // 1- $
4274 			break;
4275 			case 7:                                        	// 1$-
4276 				nIntlFormat = 10;                           // 1 $-
4277 			break;
4278 			case 8:                                        	// -1 $
4279 			break;
4280 			case 9:                                        	// -$ 1
4281 			break;
4282 			case 10:                                        // 1 $-
4283 			break;
4284 			case 11:                                        // $ -1
4285 			break;
4286 			case 12 : 										// $ 1-
4287 			break;
4288 			case 13 : 										// 1- $
4289 			break;
4290 			case 14 : 										// ($ 1)
4291 //				nIntlFormat = 14;                           // ($ 1)
4292 				nIntlFormat = 9;                            // -$ 1
4293 			break;
4294 			case 15 :										// (1 $)
4295 //				nIntlFormat = 15;                           // (1 $)
4296 				nIntlFormat = 8;                            // -1 $
4297 			break;
4298 			default:
4299 				DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4300 			break;
4301 		}
4302 #endif
4303 	}
4304 	else if ( nIntlFormat != nCurrFormat )
4305 	{
4306 		switch ( nCurrFormat )
4307 		{
4308 			case 0:                                        	// ($1)
4309 				nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4310 					nIntlFormat, nCurrFormat );
4311 			break;
4312 			case 1:                                        	// -$1
4313 				nIntlFormat = nCurrFormat;
4314 			break;
4315 			case 2:                                        	// $-1
4316 				nIntlFormat = nCurrFormat;
4317 			break;
4318 			case 3:                                        	// $1-
4319 				nIntlFormat = nCurrFormat;
4320 			break;
4321 			case 4:                                        	// (1$)
4322 				nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4323 					nIntlFormat, nCurrFormat );
4324 			break;
4325 			case 5:                                        	// -1$
4326 				nIntlFormat = nCurrFormat;
4327 			break;
4328 			case 6:                                        	// 1-$
4329 				nIntlFormat = nCurrFormat;
4330 			break;
4331 			case 7:                                        	// 1$-
4332 				nIntlFormat = nCurrFormat;
4333 			break;
4334 			case 8:                                        	// -1 $
4335 				nIntlFormat = nCurrFormat;
4336 			break;
4337 			case 9:                                        	// -$ 1
4338 				nIntlFormat = nCurrFormat;
4339 			break;
4340 			case 10:                                        // 1 $-
4341 				nIntlFormat = nCurrFormat;
4342 			break;
4343 			case 11:                                        // $ -1
4344 				nIntlFormat = nCurrFormat;
4345 			break;
4346 			case 12 : 										// $ 1-
4347 				nIntlFormat = nCurrFormat;
4348 			break;
4349 			case 13 : 										// 1- $
4350 				nIntlFormat = nCurrFormat;
4351 			break;
4352 			case 14 : 										// ($ 1)
4353 				nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4354 					nIntlFormat, nCurrFormat );
4355 			break;
4356 			case 15 :										// (1 $)
4357 				nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4358 					nIntlFormat, nCurrFormat );
4359 			break;
4360 			default:
4361 				DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4362 			break;
4363 		}
4364 	}
4365 	return nIntlFormat;
4366 }
4367 
4368 
4369 // we only support default encodings here
4370 // static
4371 sal_Char NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding )
4372 {
4373 	switch ( eTextEncoding )
4374 	{
4375 		case RTL_TEXTENCODING_MS_1252 :			// WNT Ansi
4376 		case RTL_TEXTENCODING_ISO_8859_1 :		// UNX for use with TrueType fonts
4377 			return '\x80';
4378 		case RTL_TEXTENCODING_ISO_8859_15 :		// UNX real
4379 			return '\xA4';
4380 		case RTL_TEXTENCODING_IBM_850 :			// OS2
4381 			return '\xD5';
4382 		case RTL_TEXTENCODING_APPLE_ROMAN :		// MAC
4383 			return '\xDB';
4384 		default:								// default system
4385 #if WNT
4386 			return '\x80';
4387 #elif OS2
4388 			return '\xD5';
4389 #elif UNX
4390 //			return '\xA4';		// #56121# 0xA4 waere korrekt fuer iso-8859-15
4391 			return '\x80';		// aber Windoze-Code fuer die konvertierten TrueType-Fonts
4392 #else
4393 #error EuroSymbol is what?
4394 			return '\x80';
4395 #endif
4396 	}
4397 	return '\x80';
4398 }
4399 
4400 
4401 
4402