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