xref: /AOO41X/main/svl/source/numbers/zforscan.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 #ifndef GCC
31 #endif
32 
33 #include <stdlib.h>
34 #include <tools/debug.hxx>
35 #include <i18npool/mslangid.hxx>
36 #include <unotools/charclass.hxx>
37 #include <unotools/localedatawrapper.hxx>
38 #include <unotools/numberformatcodewrapper.hxx>
39 #include <rtl/instance.hxx>
40 
41 #include <svl/zforlist.hxx>
42 #include <svl/zformat.hxx>
43 #include <unotools/digitgroupingiterator.hxx>
44 
45 #define _ZFORSCAN_CXX
46 #include "zforscan.hxx"
47 #undef _ZFORSCAN_CXX
48 #include <svl/nfsymbol.hxx>
49 using namespace svt;
50 
51 const sal_Unicode cNonBreakingSpace = 0xA0;
52 
53 namespace
54 {
55     struct ImplEnglishColors
56     {
57         const String* operator()()
58         {
59             static const String aEnglishColors[NF_MAX_DEFAULT_COLORS] =
60             {
61                 String( RTL_CONSTASCII_USTRINGPARAM( "BLACK" ) ),
62                 String( RTL_CONSTASCII_USTRINGPARAM( "BLUE" ) ),
63                 String( RTL_CONSTASCII_USTRINGPARAM( "GREEN" ) ),
64                 String( RTL_CONSTASCII_USTRINGPARAM( "CYAN" ) ),
65                 String( RTL_CONSTASCII_USTRINGPARAM( "RED" ) ),
66                 String( RTL_CONSTASCII_USTRINGPARAM( "MAGENTA" ) ),
67                 String( RTL_CONSTASCII_USTRINGPARAM( "BROWN" ) ),
68                 String( RTL_CONSTASCII_USTRINGPARAM( "GREY" ) ),
69                 String( RTL_CONSTASCII_USTRINGPARAM( "YELLOW" ) ),
70                 String( RTL_CONSTASCII_USTRINGPARAM( "WHITE" ) )
71             };
72             return &aEnglishColors[0];
73         }
74     };
75 
76     struct theEnglishColors
77             : public rtl::StaticAggregate< const String, ImplEnglishColors> {};
78 
79 }
80 
81 ImpSvNumberformatScan::ImpSvNumberformatScan( SvNumberFormatter* pFormatterP )
82 {
83 	pFormatter = pFormatterP;
84 	bConvertMode = sal_False;
85 	//! All keywords MUST be UPPERCASE!
86 	sKeyword[NF_KEY_E].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"E" ) );		// Exponent
87 	sKeyword[NF_KEY_AMPM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"AM/PM" ) );	// AM/PM
88 	sKeyword[NF_KEY_AP].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"A/P" ) );		// AM/PM short
89 	sKeyword[NF_KEY_MI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"M" ) );		// Minute
90 	sKeyword[NF_KEY_MMI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"MM" ) );		// Minute 02
91 	sKeyword[NF_KEY_S].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"S" ) );		// Second
92 	sKeyword[NF_KEY_SS].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"SS" ) );		// Second 02
93 	sKeyword[NF_KEY_Q].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"Q" ) );		// Quarter short 'Q'
94 	sKeyword[NF_KEY_QQ].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"QQ" ) );		// Quarter long
95 	sKeyword[NF_KEY_NN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"NN" ) );		// Day of week short
96 	sKeyword[NF_KEY_NNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"NNN" ) );		// Day of week long
97 	sKeyword[NF_KEY_NNNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"NNNN" ) );		// Day of week long incl. separator
98 	sKeyword[NF_KEY_WW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"WW" ) );		// Week of year
99 	sKeyword[NF_KEY_CCC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"CCC" ) );		// Currency abbreviation
100     bKeywordsNeedInit = sal_True;   // locale dependent keywords
101     bCompatCurNeedInit = sal_True;  // locale dependent compatibility currency strings
102 
103 	StandardColor[0]  =  Color(COL_BLACK);
104 	StandardColor[1]  =  Color(COL_LIGHTBLUE);
105 	StandardColor[2]  =  Color(COL_LIGHTGREEN);
106 	StandardColor[3]  =  Color(COL_LIGHTCYAN);
107 	StandardColor[4]  =  Color(COL_LIGHTRED);
108 	StandardColor[5]  =  Color(COL_LIGHTMAGENTA);
109 	StandardColor[6]  =  Color(COL_BROWN);
110 	StandardColor[7]  =  Color(COL_GRAY);
111 	StandardColor[8]  =  Color(COL_YELLOW);
112 	StandardColor[9]  =  Color(COL_WHITE);
113 
114 	pNullDate = new Date(30,12,1899);
115 	nStandardPrec = 2;
116 
117 	sErrStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###" ) );
118 	Reset();
119 }
120 
121 ImpSvNumberformatScan::~ImpSvNumberformatScan()
122 {
123 	delete pNullDate;
124 	Reset();
125 }
126 
127 
128 void ImpSvNumberformatScan::ChangeIntl()
129 {
130     bKeywordsNeedInit = sal_True;
131     bCompatCurNeedInit = sal_True;
132     // may be initialized by InitSpecialKeyword()
133     sKeyword[NF_KEY_TRUE].Erase();
134     sKeyword[NF_KEY_FALSE].Erase();
135 }
136 
137 
138 void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const
139 {
140     switch ( eIdx )
141     {
142         case NF_KEY_TRUE :
143             ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE] =
144                 pFormatter->GetCharClass()->upper(
145                 pFormatter->GetLocaleData()->getTrueWord() );
146             if ( !sKeyword[NF_KEY_TRUE].Len() )
147             {
148                 DBG_ERRORFILE( "InitSpecialKeyword: TRUE_WORD?" );
149                 ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "sal_True" ) );
150             }
151         break;
152         case NF_KEY_FALSE :
153             ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE] =
154                 pFormatter->GetCharClass()->upper(
155                 pFormatter->GetLocaleData()->getFalseWord() );
156             if ( !sKeyword[NF_KEY_FALSE].Len() )
157             {
158                 DBG_ERRORFILE( "InitSpecialKeyword: FALSE_WORD?" );
159                 ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "sal_False" ) );
160             }
161         break;
162         default:
163             DBG_ERRORFILE( "InitSpecialKeyword: unknown request" );
164     }
165 }
166 
167 
168 void ImpSvNumberformatScan::InitCompatCur() const
169 {
170     ImpSvNumberformatScan* pThis = (ImpSvNumberformatScan*)this;
171     // currency symbol for old style ("automatic") compatibility format codes
172     pFormatter->GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev );
173     // currency symbol upper case
174     pThis->sCurString = pFormatter->GetCharClass()->upper( sCurSymbol );
175     bCompatCurNeedInit = sal_False;
176 }
177 
178 
179 void ImpSvNumberformatScan::InitKeywords() const
180 {
181     if ( !bKeywordsNeedInit )
182         return ;
183     ((ImpSvNumberformatScan*)this)->SetDependentKeywords();
184     bKeywordsNeedInit = sal_False;
185 }
186 
187 
188 /** Extract the name of General, Standard, Whatever, ignoring leading modifiers
189     such as [NatNum1]. */
190 static String lcl_extractStandardGeneralName( const ::rtl::OUString & rCode )
191 {
192     String aStr;
193     const sal_Unicode* p = rCode.getStr();
194     const sal_Unicode* const pStop = p + rCode.getLength();
195     const sal_Unicode* pBeg = p;    // name begins here
196     bool bMod = false;
197     bool bDone = false;
198     while (p < pStop && !bDone)
199     {
200         switch (*p)
201         {
202             case '[':
203                 bMod = true;
204                 break;
205             case ']':
206                 if (bMod)
207                 {
208                     bMod = false;
209                     pBeg = p+1;
210                 }
211                 // else: would be a locale data error, easily to be spotted in
212                 // UI dialog
213                 break;
214             case ';':
215                 if (!bMod)
216                 {
217                     bDone = true;
218                     --p;    // put back, increment by one follows
219                 }
220                 break;
221         }
222         ++p;
223         if (bMod)
224             pBeg = p;
225     }
226     if (pBeg < p)
227         aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg);
228     return aStr;
229 }
230 
231 
232 void ImpSvNumberformatScan::SetDependentKeywords()
233 {
234 	using namespace ::com::sun::star;
235 	using namespace ::com::sun::star::uno;
236 
237 	const CharClass* pCharClass = pFormatter->GetCharClass();
238 	const LocaleDataWrapper* pLocaleData = pFormatter->GetLocaleData();
239 	// #80023# be sure to generate keywords for the loaded Locale, not for the
240 	// requested Locale, otherwise number format codes might not match
241 	lang::Locale aLoadedLocale = pLocaleData->getLoadedLocale();
242 	LanguageType eLang = MsLangId::convertLocaleToLanguage( aLoadedLocale );
243 	NumberFormatCodeWrapper aNumberFormatCode( pFormatter->GetServiceManager(), aLoadedLocale );
244 
245     i18n::NumberFormatCode aFormat = aNumberFormatCode.getFormatCode( NF_NUMBER_STANDARD );
246 	sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code);
247 	sKeyword[NF_KEY_GENERAL] = pCharClass->upper( sNameStandardFormat );
248 
249 	// preset new calendar keywords
250 	sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"AAA" ) );
251 	sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"AAAA" ) );
252 	sKeyword[NF_KEY_EC].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"E" ) );
253 	sKeyword[NF_KEY_EEC].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"EE" ) );
254 	sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM(		"G" ) );
255 	sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"GG" ) );
256 	sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"GGG" ) );
257 	sKeyword[NF_KEY_R].AssignAscii( RTL_CONSTASCII_STRINGPARAM(		"R" ) );
258 	sKeyword[NF_KEY_RR].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"RR" ) );
259 
260     // Thai T NatNum special. Other locale's small letter 't' results in upper
261     // case comparison not matching but length does in conversion mode. Ugly.
262     if (eLang == LANGUAGE_THAI)
263         sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T"));
264     else
265         sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "t"));
266 
267 	switch ( eLang )
268 	{
269 		case LANGUAGE_GERMAN:
270 		case LANGUAGE_GERMAN_SWISS:
271 		case LANGUAGE_GERMAN_AUSTRIAN:
272 		case LANGUAGE_GERMAN_LUXEMBOURG:
273 		case LANGUAGE_GERMAN_LIECHTENSTEIN:
274 		{
275 			//! all capital letters
276 			sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"M" ) ); 			// month 1
277 			sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"MM" ) );			// month 01
278 			sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"MMM" ) );		// month Jan
279 			sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"MMMM" ) );	// month Januar
280 			sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"MMMMM" ) );// month J
281 			sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"H" ) ); 			// hour 2
282 			sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"HH" ) );			// hour 02
283 			sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"T" ) );
284 			sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"TT" ) );
285 			sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"TTT" ) );
286 			sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"TTTT" ) );
287 			sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"JJ" ) );
288 			sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"JJJJ" ) );
289 			sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"LOGISCH" ) );
290 			sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"FARBE" ) );
291 			sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"SCHWARZ" ) );
292 			sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"BLAU" ) );
293 			sKeyword[NF_KEY_GREEN] = UniString( "GR" "\xDC" "N", RTL_TEXTENCODING_ISO_8859_1 );
294 			sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"CYAN" ) );
295 			sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"ROT" ) );
296 			sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"MAGENTA" ) );
297 			sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"BRAUN" ) );
298 			sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"GRAU" ) );
299 			sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"GELB" ) );
300 			sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"WEISS" ) );
301 		}
302 		break;
303 		default:
304 		{
305 			// day
306 			switch ( eLang )
307 			{
308 				case LANGUAGE_ITALIAN       :
309 				case LANGUAGE_ITALIAN_SWISS :
310 					sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
311 					sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
312 					sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
313 					sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGGG" ) );
314 					// must exchange the era code, same as Xcl
315 					sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "X" ) );
316 					sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XX" ) );
317 					sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XXX" ) );
318 				break;
319 				case LANGUAGE_FRENCH            :
320 				case LANGUAGE_FRENCH_BELGIAN    :
321 				case LANGUAGE_FRENCH_CANADIAN   :
322 				case LANGUAGE_FRENCH_SWISS      :
323 				case LANGUAGE_FRENCH_LUXEMBOURG :
324 				case LANGUAGE_FRENCH_MONACO		:
325 					sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "J" ) );
326 					sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
327 					sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJ" ) );
328 					sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
329 				break;
330 				case LANGUAGE_FINNISH :
331 					sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "P" ) );
332 					sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PP" ) );
333 					sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPP" ) );
334 					sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPPP" ) );
335 				break;
336 				default:
337 					sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D" ) );
338 					sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DD" ) );
339 					sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDD" ) );
340 					sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDDD" ) );
341 			}
342 			// month
343 			switch ( eLang )
344 			{
345 				case LANGUAGE_FINNISH :
346 					sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "K" ) );
347 					sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KK" ) );
348 					sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKK" ) );
349 					sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKK" ) );
350 					sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKKK" ) );
351 				break;
352 				default:
353 					sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) );
354 					sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) );
355 					sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) );
356 					sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) );
357 					sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );
358 			}
359 			// year
360 			switch ( eLang )
361 			{
362 				case LANGUAGE_ITALIAN       :
363 				case LANGUAGE_ITALIAN_SWISS :
364 				case LANGUAGE_FRENCH            :
365 				case LANGUAGE_FRENCH_BELGIAN    :
366 				case LANGUAGE_FRENCH_CANADIAN   :
367 				case LANGUAGE_FRENCH_SWISS      :
368 				case LANGUAGE_FRENCH_LUXEMBOURG :
369 				case LANGUAGE_FRENCH_MONACO		:
370 				case LANGUAGE_PORTUGUESE           :
371 				case LANGUAGE_PORTUGUESE_BRAZILIAN :
372 				case LANGUAGE_SPANISH_MODERN      :
373 				case LANGUAGE_SPANISH_DATED       :
374 				case LANGUAGE_SPANISH_MEXICAN     :
375 				case LANGUAGE_SPANISH_GUATEMALA   :
376 				case LANGUAGE_SPANISH_COSTARICA   :
377 				case LANGUAGE_SPANISH_PANAMA      :
378 				case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC :
379 				case LANGUAGE_SPANISH_VENEZUELA   :
380 				case LANGUAGE_SPANISH_COLOMBIA    :
381 				case LANGUAGE_SPANISH_PERU        :
382 				case LANGUAGE_SPANISH_ARGENTINA   :
383 				case LANGUAGE_SPANISH_ECUADOR     :
384 				case LANGUAGE_SPANISH_CHILE       :
385 				case LANGUAGE_SPANISH_URUGUAY     :
386 				case LANGUAGE_SPANISH_PARAGUAY    :
387 				case LANGUAGE_SPANISH_BOLIVIA     :
388 				case LANGUAGE_SPANISH_EL_SALVADOR :
389 				case LANGUAGE_SPANISH_HONDURAS    :
390 				case LANGUAGE_SPANISH_NICARAGUA   :
391 				case LANGUAGE_SPANISH_PUERTO_RICO :
392 					sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AA" ) );
393 					sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
394 					// must exchange the day of week name code, same as Xcl
395 					sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"OOO" ) );
396 					sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM(	"OOOO" ) );
397 				break;
398 				case LANGUAGE_DUTCH         :
399 				case LANGUAGE_DUTCH_BELGIAN :
400 					sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
401 					sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
402 				break;
403 				case LANGUAGE_FINNISH :
404 					sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VV" ) );
405 					sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VVVV" ) );
406 				break;
407 				default:
408 					sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YY" ) );
409 					sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YYYY" ) );
410 			}
411 			// hour
412 			switch ( eLang )
413 			{
414 				case LANGUAGE_DUTCH         :
415 				case LANGUAGE_DUTCH_BELGIAN :
416 					sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "U" ) );
417 					sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "UU" ) );
418 				break;
419 				case LANGUAGE_FINNISH :
420 				case LANGUAGE_SWEDISH         :
421 				case LANGUAGE_SWEDISH_FINLAND :
422 				case LANGUAGE_DANISH :
423 				case LANGUAGE_NORWEGIAN         :
424 				case LANGUAGE_NORWEGIAN_BOKMAL  :
425 				case LANGUAGE_NORWEGIAN_NYNORSK :
426 					sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
427 					sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
428 				break;
429 				default:
430 					sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) );
431 					sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) );
432 			}
433 			// boolean
434 			sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BOOLEAN" ) );
435 			// colours
436 			sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"COLOR" ) );
437 			sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"BLACK" ) );
438 			sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"BLUE" ) );
439 			sKeyword[NF_KEY_GREEN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"GREEN" ) );
440 			sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"CYAN" ) );
441 			sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"RED" ) );
442 			sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"MAGENTA" ) );
443 			sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"BROWN" ) );
444 			sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 		"GREY" ) );
445 			sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"YELLOW" ) );
446 			sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( 	"WHITE" ) );
447 		}
448 		break;
449 	}
450 
451 	// boolean keyords
452     InitSpecialKeyword( NF_KEY_TRUE );
453     InitSpecialKeyword( NF_KEY_FALSE );
454 
455     // compatibility currency strings
456     InitCompatCur();
457 }
458 
459 
460 void ImpSvNumberformatScan::ChangeNullDate(sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear)
461 {
462 	if ( pNullDate )
463 		*pNullDate = Date(nDay, nMonth, nYear);
464 	else
465 		pNullDate = new Date(nDay, nMonth, nYear);
466 }
467 
468 void ImpSvNumberformatScan::ChangeStandardPrec(sal_uInt16 nPrec)
469 {
470 	nStandardPrec = nPrec;
471 }
472 
473 Color* ImpSvNumberformatScan::GetColor(String& sStr)
474 {
475 	String sString = pFormatter->GetCharClass()->upper(sStr);
476     const NfKeywordTable & rKeyword = GetKeywords();
477 	size_t i = 0;
478 	while (i < NF_MAX_DEFAULT_COLORS &&
479            sString != rKeyword[NF_KEY_FIRSTCOLOR+i] )
480 		i++;
481     if ( i >= NF_MAX_DEFAULT_COLORS )
482     {
483         const String* pEnglishColors = theEnglishColors::get();
484         size_t j = 0;
485         while ( j < NF_MAX_DEFAULT_COLORS &&
486                 sString != pEnglishColors[j] )
487             ++j;
488         if ( j < NF_MAX_DEFAULT_COLORS )
489             i = j;
490     }
491 
492     Color* pResult = NULL;
493 	if (i >= NF_MAX_DEFAULT_COLORS)
494 	{
495         const String& rColorWord = rKeyword[NF_KEY_COLOR];
496 		xub_StrLen nPos = sString.Match(rColorWord);
497 		if (nPos > 0)
498 		{
499 			sStr.Erase(0, nPos);
500 			sStr.EraseLeadingChars();
501 			sStr.EraseTrailingChars();
502 			if (bConvertMode)
503 			{
504 				pFormatter->ChangeIntl(eNewLnge);
505                 sStr.Insert( GetKeywords()[NF_KEY_COLOR], 0 );  // Color -> FARBE
506 				pFormatter->ChangeIntl(eTmpLnge);
507 			}
508 			else
509 				sStr.Insert(rColorWord,0);
510 			sString.Erase(0, nPos);
511 			sString.EraseLeadingChars();
512 			sString.EraseTrailingChars();
513 
514 			if ( CharClass::isAsciiNumeric( sString ) )
515 			{
516 				long nIndex = sString.ToInt32();
517 				if (nIndex > 0 && nIndex <= 64)
518 					pResult = pFormatter->GetUserDefColor((sal_uInt16)nIndex-1);
519 			}
520 		}
521 	}
522 	else
523 	{
524 		sStr.Erase();
525 		if (bConvertMode)
526 		{
527 			pFormatter->ChangeIntl(eNewLnge);
528             sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i];           // red -> rot
529 			pFormatter->ChangeIntl(eTmpLnge);
530 		}
531 		else
532             sStr = rKeyword[NF_KEY_FIRSTCOLOR+i];
533 
534 		pResult = &(StandardColor[i]);
535 	}
536     return pResult;
537 }
538 
539 
540 short ImpSvNumberformatScan::GetKeyWord( const String& sSymbol, xub_StrLen nPos )
541 {
542 	String sString = pFormatter->GetCharClass()->toUpper( sSymbol, nPos, sSymbol.Len() - nPos );
543     const NfKeywordTable & rKeyword = GetKeywords();
544 	// #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
545     if ( sString.Search( rKeyword[NF_KEY_GENERAL] ) == 0 )
546 		return NF_KEY_GENERAL;
547 	//! MUST be a reverse search to find longer strings first
548 	short i = NF_KEYWORD_ENTRIES_COUNT-1;
549 	sal_Bool bFound = sal_False;
550     for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i )
551     {
552         bFound = sString.Search(rKeyword[i]) == 0;
553         if ( bFound )
554         {
555             break;
556         }
557     }
558 	// new keywords take precedence over old keywords
559 	if ( !bFound )
560 	{	// skip the gap of colors et al between new and old keywords and search on
561 		i = NF_KEY_LASTKEYWORD;
562         while ( i > 0 && sString.Search(rKeyword[i]) != 0 )
563 			i--;
564         if ( i > NF_KEY_LASTOLDKEYWORD && sString != rKeyword[i] )
565 		{	// found something, but maybe it's something else?
566 			// e.g. new NNN is found in NNNN, for NNNN we must search on
567 			short j = i - 1;
568             while ( j > 0 && sString.Search(rKeyword[j]) != 0 )
569 				j--;
570             if ( j && rKeyword[j].Len() > rKeyword[i].Len() )
571 				return j;
572 		}
573 	}
574     // The Thai T NatNum modifier during Xcl import.
575     if (i == 0 && bConvertMode && sString.GetChar(0) == 'T' && eTmpLnge ==
576             LANGUAGE_ENGLISH_US && MsLangId::getRealLanguage( eNewLnge) ==
577             LANGUAGE_THAI)
578         i = NF_KEY_THAI_T;
579 	return i;		// 0 => not found
580 }
581 
582 //---------------------------------------------------------------------------
583 // Next_Symbol
584 //---------------------------------------------------------------------------
585 // Zerlegt die Eingabe in Symbole fuer die weitere
586 // Verarbeitung (Turing-Maschine).
587 //---------------------------------------------------------------------------
588 // Ausgangs Zustand = SsStart
589 //---------------+-------------------+-----------------------+---------------
590 // Alter Zustand | gelesenes Zeichen | Aktion                | Neuer Zustand
591 //---------------+-------------------+-----------------------+---------------
592 // SsStart       | Buchstabe         | Symbol=Zeichen        | SsGetWord
593 //               |    "              | Typ = String          | SsGetString
594 //               |    \              | Typ = String          | SsGetChar
595 //               |    *              | Typ = Star            | SsGetStar
596 //               |    _              | Typ = Blank           | SsGetBlank
597 //               | @ # 0 ? / . , % [ | Symbol = Zeichen;     |
598 //               | ] ' Blank         | Typ = Steuerzeichen   | SsStop
599 //               | $ - + ( ) :       | Typ    = String;      |
600 //               | |                 | Typ    = Comment      | SsStop
601 //               | Sonst             | Symbol = Zeichen      | SsStop
602 //---------------|-------------------+-----------------------+---------------
603 // SsGetChar     | Sonst             | Symbol=Zeichen        | SsStop
604 //---------------+-------------------+-----------------------+---------------
605 // GetString     | "                 |                       | SsStop
606 //               | Sonst             | Symbol+=Zeichen       | GetString
607 //---------------+-------------------+-----------------------+---------------
608 // SsGetWord     | Buchstabe         | Symbol += Zeichen     |
609 //               | + -        (E+ E-)| Symbol += Zeichen     | SsStop
610 //               | /          (AM/PM)| Symbol += Zeichen     |
611 //               | Sonst             | Pos--, if Key Typ=Word| SsStop
612 //---------------+-------------------+-----------------------+---------------
613 // SsGetStar     | Sonst             | Symbol+=Zeichen       | SsStop
614 //               |                   | markiere Sonderfall * |
615 //---------------+-------------------+-----------------------+---------------
616 // SsGetBlank    | Sonst             | Symbol+=Zeichen       | SsStop
617 //               |                   | markiere Sonderfall _ |
618 //---------------+-------------------+-----------------------+---------------
619 // Wurde im State SsGetWord ein Schluesselwort erkannt (auch als
620 // Anfangsteilwort des Symbols)
621 // so werden die restlichen Buchstaben zurueckgeschrieben !!
622 
623 enum ScanState
624 {
625 	SsStop      = 0,
626 	SsStart     = 1,
627 	SsGetChar   = 2,
628 	SsGetString = 3,
629 	SsGetWord   = 4,
630 	SsGetStar   = 5,
631 	SsGetBlank  = 6
632 };
633 
634 short ImpSvNumberformatScan::Next_Symbol( const String& rStr,
635 			xub_StrLen& nPos, String& sSymbol )
636 {
637     if ( bKeywordsNeedInit )
638         InitKeywords();
639 	const CharClass* pChrCls = pFormatter->GetCharClass();
640 	const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
641 	const xub_StrLen nStart = nPos;
642 	short eType = 0;
643 	ScanState eState = SsStart;
644 	sSymbol.Erase();
645 	while ( nPos < rStr.Len() && eState != SsStop )
646 	{
647 		sal_Unicode cToken = rStr.GetChar( nPos++ );
648 		switch (eState)
649 		{
650 			case SsStart:
651 			{
652 				// Fetch any currency longer than one character and don't get
653 				// confused later on by "E/" or other combinations of letters
654                 // and meaningful symbols. Necessary for old automatic currency.
655                 // #96158# But don't do it if we're starting a "[...]" section,
656                 // for example a "[$...]" new currency symbol to not parse away
657                 // "$U" (symbol) of "[$UYU]" (abbreviation).
658                 if ( nCurrPos != STRING_NOTFOUND && sCurString.Len() > 1 &&
659                         nPos-1 + sCurString.Len() <= rStr.Len() &&
660                         !(nPos > 1 && rStr.GetChar( nPos-2 ) == '[') )
661 				{
662                     String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
663 					pChrCls->toUpper( aTest );
664                     if ( aTest == sCurString )
665 					{
666                         sSymbol = rStr.Copy( --nPos, sCurString.Len() );
667 						nPos = nPos + sSymbol.Len();
668 						eState = SsStop;
669 						eType = NF_SYMBOLTYPE_STRING;
670 						return eType;
671 					}
672 				}
673 				switch (cToken)
674 				{
675 					case '#':
676 					case '0':
677 					case '?':
678 					case '%':
679 					case '@':
680 					case '[':
681 					case ']':
682 					case ',':
683 					case '.':
684 					case '/':
685 					case '\'':
686 					case ' ':
687 					case ':':
688 					case '-':
689 					{
690 						eType = NF_SYMBOLTYPE_DEL;
691 						sSymbol += cToken;
692 						eState = SsStop;
693 					}
694 					break;
695 					case '*':
696 					{
697 						eType = NF_SYMBOLTYPE_STAR;
698 						sSymbol += cToken;
699 						eState = SsGetStar;
700 					}
701 					break;
702 					case '_':
703 					{
704 						eType = NF_SYMBOLTYPE_BLANK;
705 						sSymbol += cToken;
706 						eState = SsGetBlank;
707 					}
708 					break;
709 #if NF_COMMENT_IN_FORMATSTRING
710 					case '{':
711 						eType = NF_SYMBOLTYPE_COMMENT;
712 						eState = SsStop;
713 						sSymbol.Append( rStr.GetBuffer() + (nPos-1), rStr.Len() - (nPos-1) );
714 						nPos = rStr.Len();
715 					break;
716 #endif
717 					case '"':
718 						eType = NF_SYMBOLTYPE_STRING;
719 						eState = SsGetString;
720 						sSymbol += cToken;
721 					break;
722 					case '\\':
723 						eType = NF_SYMBOLTYPE_STRING;
724 						eState = SsGetChar;
725 						sSymbol += cToken;
726 					break;
727 					case '$':
728 					case '+':
729 					case '(':
730 					case ')':
731 						eType = NF_SYMBOLTYPE_STRING;
732 						eState = SsStop;
733 						sSymbol += cToken;
734 					break;
735 					default :
736 					{
737                         if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) ||
738                                 StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) ||
739                                 StringEqualsChar( pFormatter->GetDateSep(), cToken) ||
740                                 StringEqualsChar( pLoc->getTimeSep(), cToken) ||
741                                 StringEqualsChar( pLoc->getTime100SecSep(), cToken))
742                         {
743                             // Another separator than pre-known ASCII
744                             eType = NF_SYMBOLTYPE_DEL;
745                             sSymbol += cToken;
746                             eState = SsStop;
747                         }
748                         else if ( pChrCls->isLetter( rStr, nPos-1 ) )
749 						{
750 							short nTmpType = GetKeyWord( rStr, nPos-1 );
751 							if ( nTmpType )
752 							{
753 								sal_Bool bCurrency = sal_False;
754 								// "Automatic" currency may start with keyword,
755 								// like "R" (Rand) and 'R' (era)
756 								if ( nCurrPos != STRING_NOTFOUND &&
757                                     nPos-1 + sCurString.Len() <= rStr.Len() &&
758                                     sCurString.Search( sKeyword[nTmpType] ) == 0 )
759 								{
760                                     String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
761 									pChrCls->toUpper( aTest );
762                                     if ( aTest == sCurString )
763 										bCurrency = sal_True;
764 								}
765 								if ( bCurrency )
766 								{
767 									eState = SsGetWord;
768 									sSymbol += cToken;
769 								}
770 								else
771 								{
772 									eType = nTmpType;
773 									xub_StrLen nLen = sKeyword[eType].Len();
774 									sSymbol = rStr.Copy( nPos-1, nLen );
775 									if ( eType == NF_KEY_E || IsAmbiguousE( eType ) )
776 									{
777 										sal_Unicode cNext = rStr.GetChar(nPos);
778 										switch ( cNext )
779 										{
780 											case '+' :
781 											case '-' :	// E+ E- combine to one symbol
782 												sSymbol += cNext;
783 												eType = NF_KEY_E;
784 												nPos++;
785 											break;
786 											case '0' :
787 											case '#' :	// scientific E without sign
788 												eType = NF_KEY_E;
789 											break;
790 										}
791 									}
792 									nPos--;
793 									nPos = nPos + nLen;
794 									eState = SsStop;
795 								}
796 							}
797 							else
798 							{
799 								eState = SsGetWord;
800 								sSymbol += cToken;
801 							}
802 						}
803 						else
804 						{
805 							eType = NF_SYMBOLTYPE_STRING;
806 							eState = SsStop;
807 							sSymbol += cToken;
808 						}
809 					}
810 					break;
811 				}
812 			}
813 			break;
814 			case SsGetChar:
815 			{
816 				sSymbol += cToken;
817 				eState = SsStop;
818 			}
819 			break;
820 			case SsGetString:
821 			{
822 				if (cToken == '"')
823 					eState = SsStop;
824 				sSymbol += cToken;
825 			}
826 			break;
827 			case SsGetWord:
828 			{
829 				if ( pChrCls->isLetter( rStr, nPos-1 ) )
830 				{
831 					short nTmpType = GetKeyWord( rStr, nPos-1 );
832 					if ( nTmpType )
833 					{	// beginning of keyword, stop scan and put back
834 						eType = NF_SYMBOLTYPE_STRING;
835 						eState = SsStop;
836 						nPos--;
837 					}
838 					else
839 						sSymbol += cToken;
840 				}
841 				else
842 				{
843 					sal_Bool bDontStop = sal_False;
844 					switch (cToken)
845 					{
846 						case '/':						// AM/PM, A/P
847 						{
848 							sal_Unicode cNext = rStr.GetChar(nPos);
849 							if ( cNext == 'P' || cNext == 'p' )
850 							{
851 								xub_StrLen nLen = sSymbol.Len();
852 								if ( 1 <= nLen
853 										&& (sSymbol.GetChar(0) == 'A' || sSymbol.GetChar(0) == 'a')
854 										&& (nLen == 1 || (nLen == 2
855 											&& (sSymbol.GetChar(1) == 'M' || sSymbol.GetChar(1) == 'm')
856 											&& (rStr.GetChar(nPos+1) == 'M' || rStr.GetChar(nPos+1) == 'm'))) )
857 								{
858 									sSymbol += cToken;
859 									bDontStop = sal_True;
860 								}
861 							}
862 						}
863 						break;
864 					}
865 					// anything not recognized will stop the scan
866 					if ( eState != SsStop && !bDontStop )
867 					{
868 						eState = SsStop;
869 						nPos--;
870 						eType = NF_SYMBOLTYPE_STRING;
871 					}
872 				}
873 			}
874 			break;
875 			case SsGetStar:
876 			{
877 				eState = SsStop;
878 				sSymbol += cToken;
879 				nRepPos = (nPos - nStart) - 1;	// everytime > 0!!
880 			}
881 			break;
882 			case SsGetBlank:
883 			{
884 				eState = SsStop;
885 				sSymbol += cToken;
886 			}
887 			break;
888 			default:
889 			break;
890 		}									// of switch
891 	} 										// of while
892 	if (eState == SsGetWord)
893 		eType = NF_SYMBOLTYPE_STRING;
894 	return eType;
895 }
896 
897 xub_StrLen ImpSvNumberformatScan::Symbol_Division(const String& rString)
898 {
899 	nCurrPos = STRING_NOTFOUND;
900 													// Ist Waehrung im Spiel?
901 	String sString = pFormatter->GetCharClass()->upper(rString);
902 	xub_StrLen nCPos = 0;
903 	while (nCPos != STRING_NOTFOUND)
904 	{
905         nCPos = sString.Search(GetCurString(),nCPos);
906 		if (nCPos != STRING_NOTFOUND)
907 		{
908 			// in Quotes?
909 			xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sString, nCPos );
910 			if ( nQ == STRING_NOTFOUND )
911 			{
912 				sal_Unicode c;
913 				if ( nCPos == 0 ||
914 					((c = sString.GetChar(xub_StrLen(nCPos-1))) != '"'
915 							&& c != '\\') )			// dm kann durch "dm
916 				{                   				// \d geschuetzt werden
917 					nCurrPos = nCPos;
918 					nCPos = STRING_NOTFOUND;		// Abbruch
919 				}
920 				else
921 					nCPos++;						// weitersuchen
922 			}
923 			else
924 				nCPos = nQ + 1;						// weitersuchen
925 		}
926 	}
927 	nAnzStrings = 0;
928 	sal_Bool bStar = sal_False;					// wird bei '*'Detektion gesetzt
929 	Reset();
930 
931 	xub_StrLen nPos = 0;
932 	const xub_StrLen nLen = rString.Len();
933 	while (nPos < nLen && nAnzStrings < NF_MAX_FORMAT_SYMBOLS)
934 	{
935 		nTypeArray[nAnzStrings] = Next_Symbol(rString, nPos, sStrArray[nAnzStrings]);
936 		if (nTypeArray[nAnzStrings] == NF_SYMBOLTYPE_STAR)
937 		{								// Ueberwachung des '*'
938 			if (bStar)
939 				return nPos;		// Fehler: doppelter '*'
940 			else
941 				bStar = sal_True;
942 		}
943 		nAnzStrings++;
944 	}
945 
946 	return 0;						// 0 => ok
947 }
948 
949 void ImpSvNumberformatScan::SkipStrings(sal_uInt16& i, xub_StrLen& nPos)
950 {
951 	while (i < nAnzStrings && (   nTypeArray[i] == NF_SYMBOLTYPE_STRING
952 							   || nTypeArray[i] == NF_SYMBOLTYPE_BLANK
953 							   || nTypeArray[i] == NF_SYMBOLTYPE_STAR) )
954 	{
955 		nPos = nPos + sStrArray[i].Len();
956 		i++;
957 	}
958 }
959 
960 
961 sal_uInt16 ImpSvNumberformatScan::PreviousKeyword(sal_uInt16 i)
962 {
963 	short res = 0;
964 	if (i > 0 && i < nAnzStrings)
965 	{
966 		i--;
967 		while (i > 0 && nTypeArray[i] <= 0)
968 			i--;
969 		if (nTypeArray[i] > 0)
970 			res = nTypeArray[i];
971 	}
972 	return res;
973 }
974 
975 sal_uInt16 ImpSvNumberformatScan::NextKeyword(sal_uInt16 i)
976 {
977 	short res = 0;
978 	if (i < nAnzStrings-1)
979 	{
980 		i++;
981 		while (i < nAnzStrings-1 && nTypeArray[i] <= 0)
982 			i++;
983 		if (nTypeArray[i] > 0)
984 			res = nTypeArray[i];
985 	}
986 	return res;
987 }
988 
989 short ImpSvNumberformatScan::PreviousType( sal_uInt16 i )
990 {
991 	if ( i > 0 && i < nAnzStrings )
992 	{
993 		do
994 		{
995 			i--;
996 		} while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY );
997 		return nTypeArray[i];
998 	}
999 	return 0;
1000 }
1001 
1002 sal_Unicode ImpSvNumberformatScan::PreviousChar(sal_uInt16 i)
1003 {
1004 	sal_Unicode res = ' ';
1005 	if (i > 0 && i < nAnzStrings)
1006 	{
1007 		i--;
1008 		while (i > 0 && ( 	nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
1009 						 || nTypeArray[i] == NF_SYMBOLTYPE_STRING
1010 						 || nTypeArray[i] == NF_SYMBOLTYPE_STAR
1011 						 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK ) )
1012 			i--;
1013 		if (sStrArray[i].Len() > 0)
1014 			res = sStrArray[i].GetChar(xub_StrLen(sStrArray[i].Len()-1));
1015 	}
1016 	return res;
1017 }
1018 
1019 sal_Unicode ImpSvNumberformatScan::NextChar(sal_uInt16 i)
1020 {
1021 	sal_Unicode res = ' ';
1022 	if (i < nAnzStrings-1)
1023 	{
1024 		i++;
1025 		while (i < nAnzStrings-1 &&
1026 			   (   nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
1027 				|| nTypeArray[i] == NF_SYMBOLTYPE_STRING
1028 				|| nTypeArray[i] == NF_SYMBOLTYPE_STAR
1029 				|| nTypeArray[i] == NF_SYMBOLTYPE_BLANK))
1030 			i++;
1031 		if (sStrArray[i].Len() > 0)
1032 			res = sStrArray[i].GetChar(0);
1033 	}
1034 	return res;
1035 }
1036 
1037 sal_Bool ImpSvNumberformatScan::IsLastBlankBeforeFrac(sal_uInt16 i)
1038 {
1039 	sal_Bool res = sal_True;
1040 	if (i < nAnzStrings-1)
1041 	{
1042 		sal_Bool bStop = sal_False;
1043 		i++;
1044 		while (i < nAnzStrings-1 && !bStop)
1045 		{
1046 			i++;
1047 			if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1048 					sStrArray[i].GetChar(0) == '/')
1049 				bStop = sal_True;
1050 			else if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1051 					sStrArray[i].GetChar(0) == ' ')
1052 				res = sal_False;
1053 		}
1054 		if (!bStop)									// kein '/'
1055 			res = sal_False;
1056 	}
1057 	else
1058 		res = sal_False;								// kein '/' mehr
1059 
1060 	return res;
1061 }
1062 
1063 void ImpSvNumberformatScan::Reset()
1064 {
1065 	nAnzStrings = 0;
1066 	nAnzResStrings = 0;
1067 #if 0
1068 // ER 20.06.97 14:05   nicht noetig, wenn nAnzStrings beachtet wird
1069 	for (size_t i = 0; i < NF_MAX_FORMAT_SYMBOLS; i++)
1070 	{
1071 		sStrArray[i].Erase();
1072 		nTypeArray[i] = 0;
1073 	}
1074 #endif
1075 	eScannedType = NUMBERFORMAT_UNDEFINED;
1076 	nRepPos = 0;
1077 	bExp = sal_False;
1078 	bThousand = sal_False;
1079 	nThousand = 0;
1080 	bDecSep = sal_False;
1081 	nDecPos =  -1;
1082 	nExpPos = (sal_uInt16) -1;
1083 	nBlankPos = (sal_uInt16) -1;
1084 	nCntPre = 0;
1085 	nCntPost = 0;
1086 	nCntExp = 0;
1087 	bFrac = sal_False;
1088 	bBlank = sal_False;
1089     nNatNumModifier = 0;
1090 }
1091 
1092 
1093 sal_Bool ImpSvNumberformatScan::Is100SecZero( sal_uInt16 i, sal_Bool bHadDecSep )
1094 {
1095     sal_uInt16 nIndexPre = PreviousKeyword( i );
1096     return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS)
1097             && (bHadDecSep                 // S, SS ','
1098             || (i>0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING));
1099                 // SS"any"00  take "any" as a valid decimal separator
1100 }
1101 
1102 
1103 xub_StrLen ImpSvNumberformatScan::ScanType(const String&)
1104 {
1105 	const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1106 
1107 	xub_StrLen nPos = 0;
1108     sal_uInt16 i = 0;
1109     short eNewType;
1110     sal_Bool bMatchBracket = sal_False;
1111     bool bHaveGeneral = false;      // if General/Standard encountered
1112 
1113     SkipStrings(i, nPos);
1114 	while (i < nAnzStrings)
1115 	{
1116         if (nTypeArray[i] > 0)
1117         {                                       // keyword
1118 			switch (nTypeArray[i])
1119 			{
1120 				case NF_KEY_E:			 				// E
1121 					eNewType = NUMBERFORMAT_SCIENTIFIC;
1122 				break;
1123 				case NF_KEY_AMPM:		 				// AM,A,PM,P
1124 				case NF_KEY_AP:
1125 				case NF_KEY_H:							// H
1126 				case NF_KEY_HH:							// HH
1127 				case NF_KEY_S:							// S
1128 				case NF_KEY_SS:							// SS
1129 					eNewType = NUMBERFORMAT_TIME;
1130 				break;
1131 				case NF_KEY_M:			 				// M
1132 				case NF_KEY_MM:			 				// MM
1133                 {                                       // minute or month
1134 					sal_uInt16 nIndexPre = PreviousKeyword(i);
1135 					sal_uInt16 nIndexNex = NextKeyword(i);
1136 					sal_Unicode cChar = PreviousChar(i);
1137 					if (nIndexPre == NF_KEY_H	|| 	// H
1138 						nIndexPre == NF_KEY_HH	|| 	// HH
1139 						nIndexNex == NF_KEY_S	|| 	// S
1140 						nIndexNex == NF_KEY_SS	||  // SS
1141 						cChar == '['  )     // [M
1142 					{
1143 						eNewType = NUMBERFORMAT_TIME;
1144 						nTypeArray[i] -= 2;			// 6 -> 4, 7 -> 5
1145 					}
1146 					else
1147 						eNewType = NUMBERFORMAT_DATE;
1148 				}
1149 				break;
1150 				case NF_KEY_MMM:				// MMM
1151 				case NF_KEY_MMMM:				// MMMM
1152 				case NF_KEY_MMMMM:				// MMMMM
1153 				case NF_KEY_Q:					// Q
1154 				case NF_KEY_QQ:					// QQ
1155 				case NF_KEY_D:					// D
1156 				case NF_KEY_DD:					// DD
1157 				case NF_KEY_DDD:				// DDD
1158 				case NF_KEY_DDDD:				// DDDD
1159 				case NF_KEY_YY:					// YY
1160 				case NF_KEY_YYYY:				// YYYY
1161 				case NF_KEY_NN:					// NN
1162 				case NF_KEY_NNN:				// NNN
1163 				case NF_KEY_NNNN:				// NNNN
1164 				case NF_KEY_WW :				// WW
1165 				case NF_KEY_AAA :				// AAA
1166 				case NF_KEY_AAAA :				// AAAA
1167 				case NF_KEY_EC :				// E
1168 				case NF_KEY_EEC :				// EE
1169 				case NF_KEY_G :					// G
1170 				case NF_KEY_GG :				// GG
1171 				case NF_KEY_GGG :				// GGG
1172 				case NF_KEY_R :					// R
1173 				case NF_KEY_RR :				// RR
1174 					eNewType = NUMBERFORMAT_DATE;
1175 				break;
1176 				case NF_KEY_CCC:				// CCC
1177 					eNewType = NUMBERFORMAT_CURRENCY;
1178 				break;
1179 				case NF_KEY_GENERAL:			// Standard
1180 					eNewType = NUMBERFORMAT_NUMBER;
1181                     bHaveGeneral = true;
1182 				break;
1183 				default:
1184 					eNewType = NUMBERFORMAT_UNDEFINED;
1185 				break;
1186 			}
1187 		}
1188         else
1189         {                                       // control character
1190 			switch ( sStrArray[i].GetChar(0) )
1191 			{
1192 				case '#':
1193 				case '?':
1194 					eNewType = NUMBERFORMAT_NUMBER;
1195 				break;
1196 				case '0':
1197 				{
1198                     if ( (eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME )
1199 					{
1200                         if ( Is100SecZero( i, bDecSep ) )
1201                         {
1202                             bDecSep = sal_True;                 // subsequent 0's
1203 							eNewType = NUMBERFORMAT_TIME;
1204                         }
1205 						else
1206                             return nPos;                    // Error
1207 					}
1208 					else
1209 						eNewType = NUMBERFORMAT_NUMBER;
1210 				}
1211 				break;
1212 				case '%':
1213 					eNewType = NUMBERFORMAT_PERCENT;
1214 				break;
1215 				case '/':
1216 					eNewType = NUMBERFORMAT_FRACTION;
1217 				break;
1218 				case '[':
1219 				{
1220 					if ( i < nAnzStrings-1 &&
1221 							nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1222 							sStrArray[i+1].GetChar(0) == '$' )
1223 					{	// as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1224 						eNewType = NUMBERFORMAT_CURRENCY;
1225                         bMatchBracket = sal_True;
1226 					}
1227 					else if ( i < nAnzStrings-1 &&
1228 							nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1229 							sStrArray[i+1].GetChar(0) == '~' )
1230 					{	// as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1231 						eNewType = NUMBERFORMAT_DATE;
1232                         bMatchBracket = sal_True;
1233 					}
1234 					else
1235 					{
1236 						sal_uInt16 nIndexNex = NextKeyword(i);
1237 						if (nIndexNex == NF_KEY_H	|| 	// H
1238 							nIndexNex == NF_KEY_HH	|| 	// HH
1239 							nIndexNex == NF_KEY_M	|| 	// M
1240 							nIndexNex == NF_KEY_MM	|| 	// MM
1241 							nIndexNex == NF_KEY_S	|| 	// S
1242 							nIndexNex == NF_KEY_SS   )	// SS
1243 							eNewType = NUMBERFORMAT_TIME;
1244 						else
1245                             return nPos;                // Error
1246 					}
1247 				}
1248 				break;
1249 				case '@':
1250 					eNewType = NUMBERFORMAT_TEXT;
1251 				break;
1252 				default:
1253                     if ( sStrArray[i] == pLoc->getTime100SecSep() )
1254                         bDecSep = sal_True;                     // for SS,0
1255                     eNewType = NUMBERFORMAT_UNDEFINED;
1256 				break;
1257 			}
1258 		}
1259 		if (eScannedType == NUMBERFORMAT_UNDEFINED)
1260 			eScannedType = eNewType;
1261 		else if (eScannedType == NUMBERFORMAT_TEXT || eNewType == NUMBERFORMAT_TEXT)
1262 			eScannedType = NUMBERFORMAT_TEXT;				// Text bleibt immer Text
1263 		else if (eNewType == NUMBERFORMAT_UNDEFINED)
1264 		{											// bleibt wie bisher
1265 		}
1266 		else if (eScannedType != eNewType)
1267 		{
1268 			switch (eScannedType)
1269 			{
1270 				case NUMBERFORMAT_DATE:
1271 				{
1272 					switch (eNewType)
1273 					{
1274 						case NUMBERFORMAT_TIME:
1275 							eScannedType = NUMBERFORMAT_DATETIME;
1276 						break;
1277 						case NUMBERFORMAT_FRACTION: 		// DD/MM
1278 						break;
1279 						default:
1280 						{
1281 							if (nCurrPos != STRING_NOTFOUND)
1282 								eScannedType = NUMBERFORMAT_UNDEFINED;
1283                             else if ( sStrArray[i] != pFormatter->GetDateSep() )
1284 								return nPos;
1285 						}
1286 					}
1287 				}
1288 				break;
1289 				case NUMBERFORMAT_TIME:
1290 				{
1291 					switch (eNewType)
1292 					{
1293 						case NUMBERFORMAT_DATE:
1294 							eScannedType = NUMBERFORMAT_DATETIME;
1295 						break;
1296 						case NUMBERFORMAT_FRACTION: 		// MM/SS
1297 						break;
1298 						default:
1299 						{
1300 							if (nCurrPos != STRING_NOTFOUND)
1301 								eScannedType = NUMBERFORMAT_UNDEFINED;
1302 							else if ( sStrArray[i] != pLoc->getTimeSep() )
1303 								return nPos;
1304 						}
1305 					}
1306 				}
1307 				break;
1308 				case NUMBERFORMAT_DATETIME:
1309 				{
1310 					switch (eNewType)
1311 					{
1312 						case NUMBERFORMAT_TIME:
1313 						case NUMBERFORMAT_DATE:
1314 						break;
1315 						case NUMBERFORMAT_FRACTION: 		// DD/MM
1316 						break;
1317 						default:
1318 						{
1319 							if (nCurrPos != STRING_NOTFOUND)
1320 								eScannedType = NUMBERFORMAT_UNDEFINED;
1321                             else if ( sStrArray[i] != pFormatter->GetDateSep()
1322 								   && sStrArray[i] != pLoc->getTimeSep() )
1323 								return nPos;
1324 						}
1325 					}
1326 				}
1327 				break;
1328 				case NUMBERFORMAT_PERCENT:
1329 				{
1330 					switch (eNewType)
1331 					{
1332 						case NUMBERFORMAT_NUMBER:	// nur Zahl nach Prozent
1333 						break;
1334 						default:
1335 							return nPos;
1336 					}
1337 				}
1338 				break;
1339 				case NUMBERFORMAT_SCIENTIFIC:
1340 				{
1341 					switch (eNewType)
1342 					{
1343 						case NUMBERFORMAT_NUMBER:	// nur Zahl nach E
1344 						break;
1345 						default:
1346 							return nPos;
1347 					}
1348 				}
1349 				break;
1350 				case NUMBERFORMAT_NUMBER:
1351 				{
1352 					switch (eNewType)
1353 					{
1354 						case NUMBERFORMAT_SCIENTIFIC:
1355 						case NUMBERFORMAT_PERCENT:
1356 						case NUMBERFORMAT_FRACTION:
1357 						case NUMBERFORMAT_CURRENCY:
1358 							eScannedType = eNewType;
1359 						break;
1360 						default:
1361 							if (nCurrPos != STRING_NOTFOUND)
1362 								eScannedType = NUMBERFORMAT_UNDEFINED;
1363 							else
1364 								return nPos;
1365 					}
1366 				}
1367 				break;
1368 				case NUMBERFORMAT_FRACTION:
1369 				{
1370 					switch (eNewType)
1371 					{
1372 						case NUMBERFORMAT_NUMBER:			// nur Zahl nach Bruch
1373 						break;
1374 						default:
1375 							return nPos;
1376 					}
1377 				}
1378 				break;
1379 				default:
1380 				break;
1381 			}
1382 		}
1383 		nPos = nPos + sStrArray[i].Len();			// Korrekturposition
1384 		i++;
1385         if ( bMatchBracket )
1386         {   // no type detection inside of matching brackets if [$...], [~...]
1387             while ( bMatchBracket && i < nAnzStrings )
1388             {
1389                 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL
1390                         && sStrArray[i].GetChar(0) == ']' )
1391                     bMatchBracket = sal_False;
1392                 else
1393                     nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1394                 nPos = nPos + sStrArray[i].Len();
1395                 i++;
1396             }
1397             if ( bMatchBracket )
1398                 return nPos;    // missing closing bracket at end of code
1399         }
1400 		SkipStrings(i, nPos);
1401 	}
1402 
1403 	if ((eScannedType == NUMBERFORMAT_NUMBER || eScannedType == NUMBERFORMAT_UNDEFINED)
1404 		 && nCurrPos != STRING_NOTFOUND && !bHaveGeneral)
1405 		eScannedType = NUMBERFORMAT_CURRENCY;	// old "automatic" currency
1406 	if (eScannedType == NUMBERFORMAT_UNDEFINED)
1407 		eScannedType = NUMBERFORMAT_DEFINED;
1408 	return 0;								// Alles ok
1409 }
1410 
1411 
1412 bool ImpSvNumberformatScan::InsertSymbol( sal_uInt16 & nPos, svt::NfSymbolType eType, const String& rStr )
1413 {
1414     if (nAnzStrings >= NF_MAX_FORMAT_SYMBOLS || nPos > nAnzStrings)
1415         return false;
1416     ++nAnzResStrings;
1417     if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY)
1418         --nPos;     // reuse position
1419     else
1420     {
1421         ++nAnzStrings;
1422         for (size_t i = nAnzStrings; i > nPos; --i)
1423         {
1424             nTypeArray[i] = nTypeArray[i-1];
1425             sStrArray[i] = sStrArray[i-1];
1426         }
1427     }
1428     nTypeArray[nPos] = static_cast<short>(eType);
1429     sStrArray[nPos] = rStr;
1430     return true;
1431 }
1432 
1433 
1434 int ImpSvNumberformatScan::FinalScanGetCalendar( xub_StrLen& nPos, sal_uInt16& i,
1435 			sal_uInt16& rAnzResStrings )
1436 {
1437 	if ( sStrArray[i].GetChar(0) == '[' &&
1438 			i < nAnzStrings-1 &&
1439 			nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1440 			sStrArray[i+1].GetChar(0) == '~' )
1441 	{	// [~calendarID]
1442 		// as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1443 		nPos = nPos + sStrArray[i].Len();			// [
1444 		nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1445 		nPos = nPos + sStrArray[++i].Len();		// ~
1446 		sStrArray[i-1] += sStrArray[i];		// [~
1447 		nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1448 		rAnzResStrings--;
1449 		if ( ++i >= nAnzStrings )
1450 			return -1;		// error
1451 		nPos = nPos + sStrArray[i].Len();			// calendarID
1452 		String& rStr = sStrArray[i];
1453 		nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR;	// convert
1454 		i++;
1455 		while ( i < nAnzStrings &&
1456 				sStrArray[i].GetChar(0) != ']' )
1457 		{
1458 			nPos = nPos + sStrArray[i].Len();
1459 			rStr += sStrArray[i];
1460 			nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1461 			rAnzResStrings--;
1462 			i++;
1463 		}
1464 		if ( rStr.Len() && i < nAnzStrings &&
1465 				sStrArray[i].GetChar(0) == ']' )
1466 		{
1467 			nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1468 			nPos = nPos + sStrArray[i].Len();
1469 			i++;
1470 		}
1471 		else
1472 			return -1;		// error
1473 		return 1;
1474 	}
1475 	return 0;
1476 }
1477 
1478 xub_StrLen ImpSvNumberformatScan::FinalScan( String& rString, String& rComment )
1479 {
1480 	const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1481 
1482 	// save values for convert mode
1483     String sOldDecSep       = pFormatter->GetNumDecimalSep();
1484     String sOldThousandSep  = pFormatter->GetNumThousandSep();
1485     String sOldDateSep      = pFormatter->GetDateSep();
1486 	String sOldTimeSep		= pLoc->getTimeSep();
1487     String sOldTime100SecSep= pLoc->getTime100SecSep();
1488     String sOldCurSymbol    = GetCurSymbol();
1489     String sOldCurString    = GetCurString();
1490     sal_Unicode cOldKeyH    = sKeyword[NF_KEY_H].GetChar(0);
1491     sal_Unicode cOldKeyMI   = sKeyword[NF_KEY_MI].GetChar(0);
1492     sal_Unicode cOldKeyS    = sKeyword[NF_KEY_S].GetChar(0);
1493 
1494 	// If the group separator is a Non-Breaking Space (French) continue with a
1495 	// normal space instead so queries on space work correctly.
1496 	// The format string is adjusted to allow both.
1497 	// For output of the format code string the LocaleData characters are used.
1498 	if ( sOldThousandSep.GetChar(0) == cNonBreakingSpace && sOldThousandSep.Len() == 1 )
1499 		sOldThousandSep = ' ';
1500 
1501 	// change locale data et al
1502 	if (bConvertMode)
1503     {
1504 		pFormatter->ChangeIntl(eNewLnge);
1505         //! pointer may have changed
1506         pLoc = pFormatter->GetLocaleData();
1507         //! init new keywords
1508         InitKeywords();
1509     }
1510 	const CharClass* pChrCls = pFormatter->GetCharClass();
1511 
1512     xub_StrLen nPos = 0;                    // error correction position
1513     sal_uInt16 i = 0;                           // symbol loop counter
1514     sal_uInt16 nCounter = 0;                    // counts digits
1515     nAnzResStrings = nAnzStrings;           // counts remaining symbols
1516     bDecSep = sal_False;                        // reset in case already used in TypeCheck
1517     bool bThaiT = false;                    // Thai T NatNum modifier present
1518 
1519 	switch (eScannedType)
1520 	{
1521 		case NUMBERFORMAT_TEXT:
1522 		case NUMBERFORMAT_DEFINED:
1523 		{
1524 			while (i < nAnzStrings)
1525 			{
1526 				switch (nTypeArray[i])
1527 				{
1528 					case NF_SYMBOLTYPE_BLANK:
1529 					case NF_SYMBOLTYPE_STAR:
1530 					break;
1531 					case NF_SYMBOLTYPE_COMMENT:
1532 					{
1533 						String& rStr = sStrArray[i];
1534 						nPos = nPos + rStr.Len();
1535 						SvNumberformat::EraseCommentBraces( rStr );
1536 						rComment += rStr;
1537 						nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1538 						nAnzResStrings--;
1539 					}
1540 					break;
1541 					case NF_KEY_GENERAL :	// #77026# "General" is the same as "@"
1542 					break;
1543 					default:
1544 					{
1545 						if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL ||
1546 								sStrArray[i].GetChar(0) != '@' )
1547 							nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1548 					}
1549 					break;
1550 				}
1551 				nPos = nPos + sStrArray[i].Len();
1552 				i++;
1553 			}										// of while
1554 		}
1555 		break;
1556 		case NUMBERFORMAT_NUMBER:
1557 		case NUMBERFORMAT_PERCENT:
1558 		case NUMBERFORMAT_CURRENCY:
1559 		case NUMBERFORMAT_SCIENTIFIC:
1560 		case NUMBERFORMAT_FRACTION:
1561 		{
1562 			sal_Unicode cThousandFill = ' ';
1563 			while (i < nAnzStrings)
1564 			{
1565 				if (eScannedType == NUMBERFORMAT_FRACTION &&  	// special case
1566 					nTypeArray[i] == NF_SYMBOLTYPE_DEL && 			// # ### #/#
1567 					StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden
1568 					StringEqualsChar( sStrArray[i], ' ' ) &&
1569 					!bFrac                          &&
1570 					IsLastBlankBeforeFrac(i) )
1571 				{
1572 					nTypeArray[i] = NF_SYMBOLTYPE_STRING;			// del->string
1573 				}                                               // kein Taus.p.
1574 
1575 
1576 				if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK	||
1577 					nTypeArray[i] == NF_SYMBOLTYPE_STAR	||
1578 					nTypeArray[i] == NF_KEY_CCC			||	// CCC
1579 					nTypeArray[i] == NF_KEY_GENERAL )		// Standard
1580 				{
1581 					if (nTypeArray[i] == NF_KEY_GENERAL)
1582 					{
1583 						nThousand = FLAG_STANDARD_IN_FORMAT;
1584 						if ( bConvertMode )
1585 							sStrArray[i] = sNameStandardFormat;
1586 					}
1587 					nPos = nPos + sStrArray[i].Len();
1588 					i++;
1589 				}
1590 				else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING ||  // Strings oder
1591 						 nTypeArray[i] > 0) 					// Keywords
1592 				{
1593 					if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
1594 							 nTypeArray[i] == NF_KEY_E) 		// E+
1595 					{
1596 						if (bExp) 								// doppelt
1597 							return nPos;
1598 						bExp = sal_True;
1599 						nExpPos = i;
1600 						if (bDecSep)
1601 							nCntPost = nCounter;
1602 						else
1603 							nCntPre = nCounter;
1604 						nCounter = 0;
1605 						nTypeArray[i] = NF_SYMBOLTYPE_EXP;
1606 					}
1607 					else if (eScannedType == NUMBERFORMAT_FRACTION &&
1608 							 sStrArray[i].GetChar(0) == ' ')
1609 					{
1610 						if (!bBlank && !bFrac)	// nicht doppelt oder hinter /
1611 						{
1612 							if (bDecSep && nCounter > 0)	// Nachkommastellen
1613 								return nPos;				// Fehler
1614 							bBlank = sal_True;
1615 							nBlankPos = i;
1616 							nCntPre = nCounter;
1617 							nCounter = 0;
1618 						}
1619 						nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK;
1620 					}
1621                     else if (nTypeArray[i] == NF_KEY_THAI_T)
1622                     {
1623                         bThaiT = true;
1624                         sStrArray[i] = sKeyword[nTypeArray[i]];
1625                     }
1626 					else
1627 						nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1628 					nPos = nPos + sStrArray[i].Len();
1629 					i++;
1630 				}
1631 				else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL)
1632 				{
1633 					sal_Unicode cHere = sStrArray[i].GetChar(0);
1634                     // Handle not pre-known separators in switch.
1635                     sal_Unicode cSimplified;
1636                     if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere))
1637                         cSimplified = ',';
1638                     else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere))
1639                         cSimplified = '.';
1640                     else
1641                         cSimplified = cHere;
1642 					switch ( cSimplified )
1643 					{
1644 						case '#':
1645 						case '0':
1646 						case '?':
1647 						{
1648 							if (nThousand > 0)					// #... #
1649 								return nPos;					// Fehler
1650 							else if (bFrac && cHere == '0')
1651 								return nPos;					// 0 im Nenner
1652 							nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1653 							String& rStr = sStrArray[i];
1654 							nPos = nPos + rStr.Len();
1655 							i++;
1656 							nCounter++;
1657 							while (i < nAnzStrings &&
1658 								(sStrArray[i].GetChar(0) == '#' ||
1659 									sStrArray[i].GetChar(0) == '0' ||
1660 									sStrArray[i].GetChar(0) == '?')
1661 								)
1662 							{
1663 								nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1664 								nPos = nPos + sStrArray[i].Len();
1665 								nCounter++;
1666 								i++;
1667 							}
1668 						}
1669 						break;
1670 						case '-':
1671 						{
1672                             if ( bDecSep && nDecPos+1 == i &&
1673 									nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP )
1674                             {   // "0.--"
1675 								nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1676 								String& rStr = sStrArray[i];
1677 								nPos = nPos + rStr.Len();
1678 								i++;
1679 								nCounter++;
1680 								while (i < nAnzStrings &&
1681 										(sStrArray[i].GetChar(0) == '-') )
1682 								{
1683                                     // If more than two dashes are present in
1684                                     // currency formats the last dash will be
1685                                     // interpreted literally as a minus sign.
1686                                     // Has to be this ugly. Period.
1687                                     if ( eScannedType == NUMBERFORMAT_CURRENCY
1688                                             && rStr.Len() >= 2 &&
1689                                             (i == nAnzStrings-1 ||
1690                                             sStrArray[i+1].GetChar(0) != '-') )
1691                                         break;
1692 									rStr += sStrArray[i];
1693 									nPos = nPos + sStrArray[i].Len();
1694 									nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1695 									nAnzResStrings--;
1696 									nCounter++;
1697 									i++;
1698 								}
1699 							}
1700 							else
1701 							{
1702 								nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1703 								nPos = nPos + sStrArray[i].Len();
1704 								i++;
1705 							}
1706 						}
1707 						break;
1708 						case '.':
1709 						case ',':
1710 						case '\'':
1711 						case ' ':
1712 						{
1713 							sal_Unicode cSep = cHere;	// remember
1714 							if ( StringEqualsChar( sOldThousandSep, cSep ) )
1715 							{
1716 								// previous char with skip empty
1717 								sal_Unicode cPre = PreviousChar(i);
1718 								sal_Unicode cNext;
1719 								if (bExp || bBlank || bFrac)
1720 								{	// after E, / or ' '
1721 									if ( !StringEqualsChar( sOldThousandSep, ' ' ) )
1722 									{
1723 										nPos = nPos + sStrArray[i].Len();
1724 										nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1725 										nAnzResStrings--;
1726 										i++; 				// eat it
1727 									}
1728 									else
1729 										nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1730 								}
1731 								else if (i > 0 && i < nAnzStrings-1   &&
1732 									(cPre == '#' || cPre == '0')      &&
1733 									((cNext = NextChar(i)) == '#' || cNext == '0')
1734 									)					// #,#
1735 								{
1736 									nPos = nPos + sStrArray[i].Len();
1737 									if (!bThousand)					// only once
1738                                     {
1739 										bThousand = sal_True;
1740 										cThousandFill = sStrArray[i+1].GetChar(0);
1741 									}
1742                                     // Eat it, will be reinserted at proper
1743                                     // grouping positions further down.
1744                                     nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1745                                     nAnzResStrings--;
1746 									i++;
1747 								}
1748 								else if (i > 0 && (cPre == '#' || cPre == '0')
1749 									&& PreviousType(i) == NF_SYMBOLTYPE_DIGIT
1750 									&& nThousand < FLAG_STANDARD_IN_FORMAT )
1751 								{									// #,,,,
1752 									if ( StringEqualsChar( sOldThousandSep, ' ' ) )
1753 									{	// strange, those French..
1754 										sal_Bool bFirst = sal_True;
1755 										String& rStr = sStrArray[i];
1756                                         //  set a hard Non-Breaking Space or ConvertMode
1757                                         const String& rSepF = pFormatter->GetNumThousandSep();
1758 										while ( i < nAnzStrings
1759 											&& sStrArray[i] == sOldThousandSep
1760 											&& StringEqualsChar( sOldThousandSep, NextChar(i) ) )
1761 										{	// last was a space or another space
1762 											// is following => separator
1763 											nPos = nPos + sStrArray[i].Len();
1764 											if ( bFirst )
1765 											{
1766 												bFirst = sal_False;
1767 												rStr = rSepF;
1768 												nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1769 											}
1770 											else
1771 											{
1772 												rStr += rSepF;
1773 												nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1774 												nAnzResStrings--;
1775 											}
1776 											nThousand++;
1777 											i++;
1778 										}
1779 										if ( i < nAnzStrings-1
1780 											&& sStrArray[i] == sOldThousandSep )
1781 										{	// something following last space
1782 											// => space if currency contained,
1783 											// else separator
1784 											nPos = nPos + sStrArray[i].Len();
1785 											if ( (nPos <= nCurrPos &&
1786 													nCurrPos < nPos + sStrArray[i+1].Len())
1787 												|| nTypeArray[i+1] == NF_KEY_CCC
1788 												|| (i < nAnzStrings-2 &&
1789 												sStrArray[i+1].GetChar(0) == '[' &&
1790 												sStrArray[i+2].GetChar(0) == '$') )
1791 											{
1792 												nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1793 											}
1794 											else
1795 											{
1796 												if ( bFirst )
1797 												{
1798 													bFirst = sal_False;
1799 													rStr = rSepF;
1800 													nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1801 												}
1802 												else
1803 												{
1804 													rStr += rSepF;
1805 													nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1806 													nAnzResStrings--;
1807 												}
1808 												nThousand++;
1809 											}
1810 											i++;
1811 										}
1812 									}
1813 									else
1814 									{
1815                                         do
1816                                         {
1817                                             nThousand++;
1818                                             nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1819                                             nPos = nPos + sStrArray[i].Len();
1820                                             sStrArray[i] = pFormatter->GetNumThousandSep();
1821                                             i++;
1822                                         } while (i < nAnzStrings &&
1823                                                 sStrArray[i] == sOldThousandSep);
1824 									}
1825 								}
1826 								else 					// any grsep
1827 								{
1828 									nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1829 									String& rStr = sStrArray[i];
1830 									nPos = nPos + rStr.Len();
1831 									i++;
1832 									while ( i < nAnzStrings &&
1833 										sStrArray[i] == sOldThousandSep )
1834 									{
1835 										rStr += sStrArray[i];
1836 										nPos = nPos + sStrArray[i].Len();
1837 										nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1838 										nAnzResStrings--;
1839 										i++;
1840 									}
1841 								}
1842 							}
1843 							else if ( StringEqualsChar( sOldDecSep, cSep ) )
1844 							{
1845 								if (bBlank || bFrac)    // . behind / or ' '
1846 									return nPos;		// error
1847 								else if (bExp)			// behind E
1848 								{
1849 									nPos = nPos + sStrArray[i].Len();
1850 									nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1851 									nAnzResStrings--;
1852 									i++; 				// eat it
1853 								}
1854 								else if (bDecSep)		// any .
1855 								{
1856 									nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1857 									String& rStr = sStrArray[i];
1858 									nPos = nPos + rStr.Len();
1859 									i++;
1860 									while ( i < nAnzStrings &&
1861 										sStrArray[i] == sOldDecSep )
1862 									{
1863 										rStr += sStrArray[i];
1864 										nPos = nPos + sStrArray[i].Len();
1865 										nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1866 										nAnzResStrings--;
1867 										i++;
1868 									}
1869 								}
1870 								else
1871 								{
1872 									nPos = nPos + sStrArray[i].Len();
1873 									nTypeArray[i] = NF_SYMBOLTYPE_DECSEP;
1874                                     sStrArray[i] = pFormatter->GetNumDecimalSep();
1875 									bDecSep = sal_True;
1876 									nDecPos = i;
1877 									nCntPre = nCounter;
1878 									nCounter = 0;
1879 
1880 									i++;
1881 								}
1882 							} 							// of else = DecSep
1883 							else						// . without meaning
1884 							{
1885 								if (cSep == ' ' &&
1886 									eScannedType == NUMBERFORMAT_FRACTION &&
1887 									StringEqualsChar( sStrArray[i], ' ' ) )
1888 								{
1889 									if (!bBlank && !bFrac)	// no dups
1890 									{	                    // or behind /
1891 										if (bDecSep && nCounter > 0)// dec.
1892 											return nPos;			// error
1893 										bBlank = sal_True;
1894 										nBlankPos = i;
1895 										nCntPre = nCounter;
1896 										nCounter = 0;
1897 									}
1898 									nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1899 									nPos = nPos + sStrArray[i].Len();
1900 								}
1901 								else
1902 								{
1903 									nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1904 									String& rStr = sStrArray[i];
1905 									nPos = nPos + rStr.Len();
1906 									i++;
1907 									while (i < nAnzStrings &&
1908 										StringEqualsChar( sStrArray[i], cSep ) )
1909 									{
1910 										rStr += sStrArray[i];
1911 										nPos = nPos + sStrArray[i].Len();
1912 										nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1913 										nAnzResStrings--;
1914 										i++;
1915 									}
1916 								}
1917 							}
1918 						}
1919 						break;
1920 						case '/':
1921 						{
1922 							if (eScannedType == NUMBERFORMAT_FRACTION)
1923 							{
1924 								if ( i == 0 ||
1925 										(nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT &&
1926 									 	nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) )
1927 									return nPos ? nPos : 1;	// /? not allowed
1928 								else if (!bFrac || (bDecSep && nCounter > 0))
1929 								{
1930 									bFrac = sal_True;
1931 									nCntPost = nCounter;
1932 									nCounter = 0;
1933 									nTypeArray[i] = NF_SYMBOLTYPE_FRAC;
1934 									nPos = nPos + sStrArray[i].Len();
1935 									i++;
1936 								}
1937 								else 				// / doppelt od. , imZaehl
1938 									return nPos;	// Fehler
1939 							}
1940 							else
1941 							{
1942 								nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1943 								nPos = nPos + sStrArray[i].Len();
1944 								i++;
1945 							}
1946 						}
1947 						break;
1948 						case '[' :
1949 						{
1950 							if ( eScannedType == NUMBERFORMAT_CURRENCY &&
1951 									i < nAnzStrings-1 &&
1952 									nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1953 									sStrArray[i+1].GetChar(0) == '$' )
1954 							{	// [$DM-xxx]
1955 								// ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
1956 								nPos = nPos + sStrArray[i].Len();			// [
1957 								nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
1958 								nPos = nPos + sStrArray[++i].Len();		// $
1959 								sStrArray[i-1] += sStrArray[i];		// [$
1960 								nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1961 								nAnzResStrings--;
1962 								if ( ++i >= nAnzStrings )
1963 									return nPos;		// Fehler
1964 								nPos = nPos + sStrArray[i].Len();			// DM
1965 								String& rStr = sStrArray[i];
1966 								String* pStr = &sStrArray[i];
1967 								nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY;	// wandeln
1968 								sal_Bool bHadDash = sal_False;
1969 								i++;
1970 								while ( i < nAnzStrings &&
1971 										sStrArray[i].GetChar(0) != ']' )
1972 								{
1973 									nPos = nPos + sStrArray[i].Len();
1974 									if ( bHadDash )
1975 									{
1976 										*pStr += sStrArray[i];
1977 										nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1978 										nAnzResStrings--;
1979 									}
1980 									else
1981 									{
1982 										if ( sStrArray[i].GetChar(0) == '-' )
1983 										{
1984 											bHadDash = sal_True;
1985 											pStr = &sStrArray[i];
1986 											nTypeArray[i] = NF_SYMBOLTYPE_CURREXT;
1987 										}
1988 										else
1989 										{
1990 											*pStr += sStrArray[i];
1991 											nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1992 											nAnzResStrings--;
1993 										}
1994 									}
1995 									i++;
1996 								}
1997 								if ( rStr.Len() && i < nAnzStrings &&
1998 										sStrArray[i].GetChar(0) == ']' )
1999 								{
2000 									nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
2001 									nPos = nPos + sStrArray[i].Len();
2002 									i++;
2003 								}
2004 								else
2005 									return nPos;		// Fehler
2006 							}
2007 							else
2008 							{
2009 								nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2010 								nPos = nPos + sStrArray[i].Len();
2011 								i++;
2012 							}
2013 						}
2014 						break;
2015 						default:					// andere Dels
2016 						{
2017                             if (eScannedType == NUMBERFORMAT_PERCENT &&
2018                                     cHere == '%')
2019                                 nTypeArray[i] = NF_SYMBOLTYPE_PERCENT;
2020                             else
2021                                 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2022 							nPos = nPos + sStrArray[i].Len();
2023 							i++;
2024 						}
2025 						break;
2026 					}								// of switch (Del)
2027 				}									// of else Del
2028 				else if ( nTypeArray[i] == NF_SYMBOLTYPE_COMMENT )
2029 				{
2030 					String& rStr = sStrArray[i];
2031 					nPos = nPos + rStr.Len();
2032 					SvNumberformat::EraseCommentBraces( rStr );
2033 					rComment += rStr;
2034 					nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2035 					nAnzResStrings--;
2036 					i++;
2037 				}
2038 				else
2039 				{
2040 					DBG_ERRORFILE( "unknown NF_SYMBOLTYPE_..." );
2041 					nPos = nPos + sStrArray[i].Len();
2042 					i++;
2043 				}
2044 			}                                  		// of while
2045 			if (eScannedType == NUMBERFORMAT_FRACTION)
2046 			{
2047 				if (bFrac)
2048 					nCntExp = nCounter;
2049 				else if (bBlank)
2050 					nCntPost = nCounter;
2051 				else
2052 					nCntPre = nCounter;
2053 			}
2054 			else
2055 			{
2056 				if (bExp)
2057 					nCntExp = nCounter;
2058 				else if (bDecSep)
2059 					nCntPost = nCounter;
2060 				else
2061 					nCntPre = nCounter;
2062 			}
2063 			if (bThousand)                          // Expansion of grouping separators
2064 			{
2065 				sal_uInt16 nMaxPos;
2066 				if (bFrac)
2067 				{
2068 					if (bBlank)
2069 						nMaxPos = nBlankPos;
2070 					else
2071 						nMaxPos = 0;				// no grouping
2072 				}
2073 				else if (bDecSep)					// decimal separator present
2074 					nMaxPos = nDecPos;
2075 				else if (bExp)						// 'E' exponent present
2076 					nMaxPos = nExpPos;
2077 				else								// up to end
2078 					nMaxPos = i;
2079                 // Insert separators at proper positions.
2080                 xub_StrLen nCount = 0;
2081                 utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping());
2082                 size_t nFirstDigitSymbol = nMaxPos;
2083                 size_t nFirstGroupingSymbol = nMaxPos;
2084                 i = nMaxPos;
2085                 while (i-- > 0)
2086                 {
2087                     if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2088                     {
2089                         nFirstDigitSymbol = i;
2090                         nCount = nCount + sStrArray[i].Len();   // MSC converts += to int and then warns, so ...
2091                         // Insert separator only if not leftmost symbol.
2092                         if (i > 0 && nCount >= aGrouping.getPos())
2093                         {
2094                             DBG_ASSERT( sStrArray[i].Len() == 1,
2095                                     "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion");
2096                             if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP,
2097                                         pFormatter->GetNumThousandSep()))
2098                                 // nPos isn't correct here, but signals error
2099                                 return nPos;
2100                             // i may have been decremented by 1
2101                             nFirstDigitSymbol = i + 1;
2102                             nFirstGroupingSymbol = i;
2103                             aGrouping.advance();
2104                         }
2105                     }
2106                 }
2107                 // Generated something like "string",000; remove separator again.
2108                 if (nFirstGroupingSymbol < nFirstDigitSymbol)
2109                 {
2110                     nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY;
2111                     nAnzResStrings--;
2112                 }
2113             }
2114             // Combine digits into groups to save memory (Info will be copied
2115             // later, taking only non-empty symbols).
2116             for (i = 0; i < nAnzStrings; ++i)
2117             {
2118                 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2119                 {
2120                     String& rStr = sStrArray[i];
2121                     while (++i < nAnzStrings &&
2122                             nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2123                     {
2124                         rStr += sStrArray[i];
2125                         nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2126                         nAnzResStrings--;
2127                     }
2128                 }
2129             }
2130 		}
2131 		break;										// of NUMBERFORMAT_NUMBER
2132 		case NUMBERFORMAT_DATE:
2133 		{
2134 			while (i < nAnzStrings)
2135 			{
2136 				switch (nTypeArray[i])
2137 				{
2138 					case NF_SYMBOLTYPE_BLANK:
2139 					case NF_SYMBOLTYPE_STAR:
2140 					case NF_SYMBOLTYPE_STRING:
2141 						nPos = nPos + sStrArray[i].Len();
2142 						i++;
2143 					break;
2144 					case NF_SYMBOLTYPE_COMMENT:
2145 					{
2146 						String& rStr = sStrArray[i];
2147 						nPos = nPos + rStr.Len();
2148 						SvNumberformat::EraseCommentBraces( rStr );
2149 						rComment += rStr;
2150 						nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2151 						nAnzResStrings--;
2152 						i++;
2153 					}
2154 					break;
2155 					case NF_SYMBOLTYPE_DEL:
2156 					{
2157 						int nCalRet;
2158 						if (sStrArray[i] == sOldDateSep)
2159 						{
2160 							nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2161 							nPos = nPos + sStrArray[i].Len();
2162                             if (bConvertMode)
2163                                 sStrArray[i] = pFormatter->GetDateSep();
2164 							i++;
2165 						}
2166 						else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2167 						{
2168 							if ( nCalRet < 0  )
2169 								return nPos;		// error
2170 						}
2171 						else
2172 						{
2173 							nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2174 							nPos = nPos + sStrArray[i].Len();
2175 							i++;
2176 						}
2177 					}
2178 					break;
2179                     case NF_KEY_THAI_T :
2180                         bThaiT = true;
2181                         // fall thru
2182 					case NF_KEY_M:							// M
2183 					case NF_KEY_MM:							// MM
2184 					case NF_KEY_MMM:						// MMM
2185 					case NF_KEY_MMMM:						// MMMM
2186 					case NF_KEY_MMMMM:						// MMMMM
2187 					case NF_KEY_Q:							// Q
2188 					case NF_KEY_QQ:							// QQ
2189 					case NF_KEY_D:							// D
2190 					case NF_KEY_DD:							// DD
2191 					case NF_KEY_DDD:						// DDD
2192 					case NF_KEY_DDDD:						// DDDD
2193 					case NF_KEY_YY:							// YY
2194 					case NF_KEY_YYYY:						// YYYY
2195 					case NF_KEY_NN:							// NN
2196 					case NF_KEY_NNN:						// NNN
2197 					case NF_KEY_NNNN:						// NNNN
2198 					case NF_KEY_WW :						// WW
2199 					case NF_KEY_AAA :						// AAA
2200 					case NF_KEY_AAAA :						// AAAA
2201 					case NF_KEY_EC :						// E
2202 					case NF_KEY_EEC :						// EE
2203 					case NF_KEY_G :							// G
2204 					case NF_KEY_GG :						// GG
2205 					case NF_KEY_GGG :						// GGG
2206 					case NF_KEY_R :							// R
2207 					case NF_KEY_RR :						// RR
2208 						sStrArray[i] = sKeyword[nTypeArray[i]];	// tTtT -> TTTT
2209 						nPos = nPos + sStrArray[i].Len();
2210 						i++;
2211 					break;
2212 					default:							// andere Keywords
2213 						nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2214 						nPos = nPos + sStrArray[i].Len();
2215 						i++;
2216 					break;
2217 				}
2218 			}										// of while
2219 		}
2220 		break;										// of NUMBERFORMAT_DATE
2221 		case NUMBERFORMAT_TIME:
2222 		{
2223 			while (i < nAnzStrings)
2224 			{
2225 				switch (nTypeArray[i])
2226 				{
2227 					case NF_SYMBOLTYPE_BLANK:
2228 					case NF_SYMBOLTYPE_STAR:
2229 					{
2230 						nPos = nPos + sStrArray[i].Len();
2231 						i++;
2232 					}
2233 					break;
2234 					case NF_SYMBOLTYPE_DEL:
2235 					{
2236 						switch( sStrArray[i].GetChar(0) )
2237 						{
2238 							case '0':
2239 							{
2240                                 if ( Is100SecZero( i, bDecSep ) )
2241 								{
2242                                     bDecSep = sal_True;
2243 									nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2244 									String& rStr = sStrArray[i];
2245 									i++;
2246 									nPos = nPos + sStrArray[i].Len();
2247 									nCounter++;
2248 									while (i < nAnzStrings &&
2249 										   sStrArray[i].GetChar(0) == '0')
2250 									{
2251 										rStr += sStrArray[i];
2252 										nPos = nPos + sStrArray[i].Len();
2253 										nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2254 										nAnzResStrings--;
2255 										nCounter++;
2256 										i++;
2257 									}
2258 								}
2259 								else
2260 									return nPos;
2261 							}
2262 							break;
2263 							case '#':
2264 							case '?':
2265 								return nPos;
2266 							case '[':
2267 							{
2268 								if (bThousand)				// doppelt
2269 									return nPos;
2270 								bThousand = sal_True;			// bei Time frei
2271 								sal_Unicode cChar = pChrCls->upper( NextChar(i) ).GetChar(0);
2272 								if ( cChar == cOldKeyH )
2273 									nThousand = 1;		// H
2274 								else if ( cChar == cOldKeyMI )
2275 									nThousand = 2;		// M
2276 								else if ( cChar == cOldKeyS )
2277 									nThousand = 3;		// S
2278 								else
2279 									return nPos;
2280 								nPos = nPos + sStrArray[i].Len();
2281 								i++;
2282 							}
2283                             break;
2284 							case ']':
2285 							{
2286 								if (!bThousand)				// kein [ vorher
2287 									return nPos;
2288 								nPos = nPos + sStrArray[i].Len();
2289 								i++;
2290 							}
2291 							break;
2292 							default:
2293 							{
2294 								nPos = nPos + sStrArray[i].Len();
2295                                 if ( sStrArray[i] == sOldTimeSep )
2296                                 {
2297                                     nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2298                                     if ( bConvertMode )
2299                                         sStrArray[i] = pLoc->getTimeSep();
2300                                 }
2301                                 else if ( sStrArray[i] == sOldTime100SecSep )
2302                                 {
2303                                     bDecSep = sal_True;
2304                                     nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2305                                     if ( bConvertMode )
2306                                         sStrArray[i] = pLoc->getTime100SecSep();
2307                                 }
2308                                 else
2309                                     nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2310 								i++;
2311 							}
2312 							break;
2313 						}
2314 					}
2315 					break;
2316 					case NF_SYMBOLTYPE_STRING:
2317 					{
2318 						nPos = nPos + sStrArray[i].Len();
2319 						i++;
2320 					}
2321 					break;
2322 					case NF_SYMBOLTYPE_COMMENT:
2323 					{
2324 						String& rStr = sStrArray[i];
2325 						nPos = nPos + rStr.Len();
2326 						SvNumberformat::EraseCommentBraces( rStr );
2327 						rComment += rStr;
2328 						nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2329 						nAnzResStrings--;
2330 						i++;
2331 					}
2332 					break;
2333 					case NF_KEY_AMPM:						// AM/PM
2334 					case NF_KEY_AP:							// A/P
2335 					{
2336 						bExp = sal_True;					// missbraucht fuer A/P
2337 						sStrArray[i] = sKeyword[nTypeArray[i]];	// tTtT -> TTTT
2338 						nPos = nPos + sStrArray[i].Len();
2339 						i++;
2340 					}
2341 					break;
2342                     case NF_KEY_THAI_T :
2343                         bThaiT = true;
2344                         // fall thru
2345 					case NF_KEY_MI:							// M
2346 					case NF_KEY_MMI:						// MM
2347 					case NF_KEY_H:							// H
2348 					case NF_KEY_HH:							// HH
2349 					case NF_KEY_S:							// S
2350 					case NF_KEY_SS:							// SS
2351 					{
2352 						sStrArray[i] = sKeyword[nTypeArray[i]];	// tTtT -> TTTT
2353 						nPos = nPos + sStrArray[i].Len();
2354 						i++;
2355 					}
2356 					break;
2357 					default:							// andere Keywords
2358 					{
2359 						nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2360 						nPos = nPos + sStrArray[i].Len();
2361 						i++;
2362 					}
2363 					break;
2364 				}
2365 			}                   					// of while
2366 			nCntPost = nCounter;					// Zaehler der Nullen
2367 			if (bExp)
2368 				nCntExp = 1;						// merkt AM/PM
2369 		}
2370 		break;										// of NUMBERFORMAT_TIME
2371 		case NUMBERFORMAT_DATETIME:
2372 		{
2373             sal_Bool bTimePart = sal_False;
2374 			while (i < nAnzStrings)
2375 			{
2376 				switch (nTypeArray[i])
2377 				{
2378 					case NF_SYMBOLTYPE_BLANK:
2379 					case NF_SYMBOLTYPE_STAR:
2380 					case NF_SYMBOLTYPE_STRING:
2381 						nPos = nPos + sStrArray[i].Len();
2382 						i++;
2383 					break;
2384 					case NF_SYMBOLTYPE_COMMENT:
2385 					{
2386 						String& rStr = sStrArray[i];
2387 						nPos = nPos + rStr.Len();
2388 						SvNumberformat::EraseCommentBraces( rStr );
2389 						rComment += rStr;
2390 						nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2391 						nAnzResStrings--;
2392 						i++;
2393 					}
2394 					break;
2395 					case NF_SYMBOLTYPE_DEL:
2396 					{
2397 						int nCalRet;
2398                         if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2399 						{
2400 							if ( nCalRet < 0  )
2401 								return nPos;		// error
2402 						}
2403 						else
2404 						{
2405                             switch( sStrArray[i].GetChar(0) )
2406                             {
2407                                 case '0':
2408                                 {
2409                                     if ( bTimePart && Is100SecZero( i, bDecSep ) )
2410                                     {
2411                                         bDecSep = sal_True;
2412                                         nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2413                                         String& rStr = sStrArray[i];
2414                                         i++;
2415                                         nPos = nPos + sStrArray[i].Len();
2416                                         nCounter++;
2417                                         while (i < nAnzStrings &&
2418                                             sStrArray[i].GetChar(0) == '0')
2419                                         {
2420                                             rStr += sStrArray[i];
2421                                             nPos = nPos + sStrArray[i].Len();
2422                                             nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2423                                             nAnzResStrings--;
2424                                             nCounter++;
2425                                             i++;
2426                                         }
2427                                     }
2428                                     else
2429                                         return nPos;
2430                                 }
2431                                 break;
2432                                 case '#':
2433                                 case '?':
2434                                     return nPos;
2435                                 default:
2436                                 {
2437                                     nPos = nPos + sStrArray[i].Len();
2438                                     if (bTimePart)
2439                                     {
2440                                         if ( sStrArray[i] == sOldTimeSep )
2441                                         {
2442                                             nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2443                                             if ( bConvertMode )
2444                                                 sStrArray[i] = pLoc->getTimeSep();
2445                                         }
2446                                         else if ( sStrArray[i] == sOldTime100SecSep )
2447                                         {
2448                                             bDecSep = sal_True;
2449                                             nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2450                                             if ( bConvertMode )
2451                                                 sStrArray[i] = pLoc->getTime100SecSep();
2452                                         }
2453                                         else
2454                                             nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2455                                     }
2456                                     else
2457                                     {
2458                                         if ( sStrArray[i] == sOldDateSep )
2459                                         {
2460                                             nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2461                                             if (bConvertMode)
2462                                                 sStrArray[i] = pFormatter->GetDateSep();
2463                                         }
2464                                         else
2465                                             nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2466                                     }
2467                                     i++;
2468                                 }
2469                             }
2470 						}
2471 					}
2472 					break;
2473 					case NF_KEY_AMPM:						// AM/PM
2474 					case NF_KEY_AP:							// A/P
2475 					{
2476                         bTimePart = sal_True;
2477 						bExp = sal_True;					// missbraucht fuer A/P
2478 						sStrArray[i] = sKeyword[nTypeArray[i]];	// tTtT -> TTTT
2479 						nPos = nPos + sStrArray[i].Len();
2480 						i++;
2481 					}
2482 					break;
2483 					case NF_KEY_MI:							// M
2484 					case NF_KEY_MMI:						// MM
2485 					case NF_KEY_H:							// H
2486 					case NF_KEY_HH:							// HH
2487 					case NF_KEY_S:							// S
2488 					case NF_KEY_SS:							// SS
2489                         bTimePart = sal_True;
2490 						sStrArray[i] = sKeyword[nTypeArray[i]];	// tTtT -> TTTT
2491 						nPos = nPos + sStrArray[i].Len();
2492 						i++;
2493 					break;
2494 					case NF_KEY_M:							// M
2495 					case NF_KEY_MM:							// MM
2496 					case NF_KEY_MMM:						// MMM
2497 					case NF_KEY_MMMM:						// MMMM
2498 					case NF_KEY_MMMMM:						// MMMMM
2499 					case NF_KEY_Q:							// Q
2500 					case NF_KEY_QQ:							// QQ
2501 					case NF_KEY_D:							// D
2502 					case NF_KEY_DD:							// DD
2503 					case NF_KEY_DDD:						// DDD
2504 					case NF_KEY_DDDD:						// DDDD
2505 					case NF_KEY_YY:							// YY
2506 					case NF_KEY_YYYY:						// YYYY
2507 					case NF_KEY_NN:							// NN
2508 					case NF_KEY_NNN:						// NNN
2509 					case NF_KEY_NNNN:						// NNNN
2510 					case NF_KEY_WW :						// WW
2511 					case NF_KEY_AAA :						// AAA
2512 					case NF_KEY_AAAA :						// AAAA
2513 					case NF_KEY_EC :						// E
2514 					case NF_KEY_EEC :						// EE
2515 					case NF_KEY_G :							// G
2516 					case NF_KEY_GG :						// GG
2517 					case NF_KEY_GGG :						// GGG
2518 					case NF_KEY_R :							// R
2519 					case NF_KEY_RR :						// RR
2520                         bTimePart = sal_False;
2521 						sStrArray[i] = sKeyword[nTypeArray[i]];	// tTtT -> TTTT
2522 						nPos = nPos + sStrArray[i].Len();
2523 						i++;
2524 					break;
2525                     case NF_KEY_THAI_T :
2526                         bThaiT = true;
2527 						sStrArray[i] = sKeyword[nTypeArray[i]];
2528 						nPos = nPos + sStrArray[i].Len();
2529 						i++;
2530 					break;
2531 					default:							// andere Keywords
2532 						nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2533 						nPos = nPos + sStrArray[i].Len();
2534 						i++;
2535 					break;
2536 				}
2537 			}										// of while
2538             nCntPost = nCounter;                    // decimals (100th seconds)
2539 			if (bExp)
2540 				nCntExp = 1;						// merkt AM/PM
2541 		}
2542 		break;										// of NUMBERFORMAT_DATETIME
2543 		default:
2544 		break;
2545 	}
2546 	if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
2547 		(nCntPre + nCntPost == 0 || nCntExp == 0))
2548 		return nPos;
2549 	else if (eScannedType == NUMBERFORMAT_FRACTION && (nCntExp > 8 || nCntExp == 0))
2550 		return nPos;
2551 
2552     if (bThaiT && !GetNatNumModifier())
2553         SetNatNumModifier(1);
2554 
2555 	if ( bConvertMode )
2556 	{	// strings containing keywords of the target locale must be quoted, so
2557 		// the user sees the difference and is able to edit the format string
2558 		for ( i=0; i < nAnzStrings; i++ )
2559 		{
2560 			if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING &&
2561 					sStrArray[i].GetChar(0) != '\"' )
2562 			{
2563 				if ( bConvertSystemToSystem && eScannedType == NUMBERFORMAT_CURRENCY )
2564 				{	// don't stringize automatic currency, will be converted
2565                     if ( sStrArray[i] == sOldCurSymbol )
2566 						continue;	// for
2567 					// DM might be splitted into D and M
2568                     if ( sStrArray[i].Len() < sOldCurSymbol.Len() &&
2569 							pChrCls->toUpper( sStrArray[i], 0, 1 ).GetChar(0) ==
2570 							sOldCurString.GetChar(0) )
2571 					{
2572 						String aTmp( sStrArray[i] );
2573 						sal_uInt16 j = i + 1;
2574                         while ( aTmp.Len() < sOldCurSymbol.Len() &&
2575 								j < nAnzStrings &&
2576 								nTypeArray[j] == NF_SYMBOLTYPE_STRING )
2577 						{
2578 							aTmp += sStrArray[j++];
2579 						}
2580 						if ( pChrCls->upper( aTmp ) == sOldCurString )
2581 						{
2582 							sStrArray[i++] = aTmp;
2583 							for ( ; i<j; i++ )
2584 							{
2585 								nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2586 								nAnzResStrings--;
2587 							}
2588 							i = j - 1;
2589 							continue;	// for
2590 						}
2591 					}
2592 				}
2593 				String& rStr = sStrArray[i];
2594 				xub_StrLen nLen = rStr.Len();
2595 				for ( xub_StrLen j=0; j<nLen; j++ )
2596 				{
2597 					if ( (j == 0 || rStr.GetChar(j-1) != '\\') && GetKeyWord( rStr, j ) )
2598 					{
2599 						rStr.Insert( '\"', 0 );
2600 						rStr += '\"';
2601 						break;	// for
2602 					}
2603 				}
2604 			}
2605 		}
2606 	}
2607 	// concatenate strings, remove quotes for output, and rebuild the format string
2608 	rString.Erase();
2609 	i = 0;
2610 	while (i < nAnzStrings)
2611 	{
2612 		switch ( nTypeArray[i] )
2613 		{
2614 			case NF_SYMBOLTYPE_STRING :
2615 			{
2616 				xub_StrLen nStringPos = rString.Len();
2617 				xub_StrLen nArrPos = 0;
2618 				sal_uInt16 iPos = i;
2619 				do
2620 				{
2621                     if (sStrArray[i].Len() == 2 &&
2622                             sStrArray[i].GetChar(0) == '\\')
2623                     {
2624                         // Unescape some simple forms of symbols even in the UI
2625                         // visible string to prevent duplicates that differ
2626                         // only in notation, originating from import.
2627                         // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical,
2628                         // but 0\ 000 0 and 0 000 0 in a French locale are not.
2629                         sal_Unicode c = sStrArray[i].GetChar(1);
2630                         switch (c)
2631                         {
2632                             case '+':
2633                             case '-':
2634                                 rString += c;
2635                                 break;
2636                             case ' ':
2637                             case '.':
2638                             case '/':
2639                                 if (((eScannedType & NUMBERFORMAT_DATE) == 0)
2640                                         && (StringEqualsChar(
2641                                                 pFormatter->GetNumThousandSep(),
2642                                                 c) || StringEqualsChar(
2643                                                     pFormatter->GetNumDecimalSep(),
2644                                                     c) || (c == ' ' &&
2645                                                         StringEqualsChar(
2646                                                             pFormatter->GetNumThousandSep(),
2647                                                             cNonBreakingSpace))))
2648                                     rString += sStrArray[i];
2649                                 else if ((eScannedType & NUMBERFORMAT_DATE) &&
2650                                         StringEqualsChar(
2651                                             pFormatter->GetDateSep(), c))
2652                                     rString += sStrArray[i];
2653                                 else if ((eScannedType & NUMBERFORMAT_TIME) &&
2654                                         (StringEqualsChar( pLoc->getTimeSep(),
2655                                                            c) ||
2656                                          StringEqualsChar(
2657                                              pLoc->getTime100SecSep(), c)))
2658                                     rString += sStrArray[i];
2659                                 else if (eScannedType & NUMBERFORMAT_FRACTION)
2660                                     rString += sStrArray[i];
2661                                 else
2662                                     rString += c;
2663                                 break;
2664                             default:
2665                                 rString += sStrArray[i];
2666                         }
2667                     }
2668                     else
2669                         rString += sStrArray[i];
2670 					if ( RemoveQuotes( sStrArray[i] ) > 0 )
2671 					{	// update currency up to quoted string
2672 						if ( eScannedType == NUMBERFORMAT_CURRENCY )
2673 						{	// dM -> DM  or  DM -> $  in old automatic
2674 							// currency formats, oh my ..., why did we ever
2675 							// introduce them?
2676 							String aTmp( pChrCls->toUpper(
2677 								sStrArray[iPos], nArrPos,
2678 								sStrArray[iPos].Len()-nArrPos ) );
2679 							xub_StrLen nCPos = aTmp.Search( sOldCurString );
2680 							if ( nCPos != STRING_NOTFOUND )
2681 							{
2682 								const String& rCur =
2683 									bConvertMode && bConvertSystemToSystem ?
2684                                     GetCurSymbol() : sOldCurSymbol;
2685 								sStrArray[iPos].Replace( nArrPos+nCPos,
2686 									sOldCurString.Len(), rCur );
2687 								rString.Replace( nStringPos+nCPos,
2688 									sOldCurString.Len(), rCur );
2689 							}
2690 							nStringPos = rString.Len();
2691 							if ( iPos == i )
2692 								nArrPos = sStrArray[iPos].Len();
2693 							else
2694 								nArrPos = sStrArray[iPos].Len() + sStrArray[i].Len();
2695 						}
2696 					}
2697 					if ( iPos != i )
2698 					{
2699 						sStrArray[iPos] += sStrArray[i];
2700 						nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2701 						nAnzResStrings--;
2702 					}
2703 					i++;
2704 				} while ( i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_STRING );
2705 				if ( i < nAnzStrings )
2706 					i--;	// enter switch on next symbol again
2707 				if ( eScannedType == NUMBERFORMAT_CURRENCY && nStringPos < rString.Len() )
2708 				{	// same as above, since last RemoveQuotes
2709 					String aTmp( pChrCls->toUpper(
2710 						sStrArray[iPos], nArrPos,
2711 						sStrArray[iPos].Len()-nArrPos ) );
2712 					xub_StrLen nCPos = aTmp.Search( sOldCurString );
2713 					if ( nCPos != STRING_NOTFOUND )
2714 					{
2715 						const String& rCur =
2716 							bConvertMode && bConvertSystemToSystem ?
2717                             GetCurSymbol() : sOldCurSymbol;
2718 						sStrArray[iPos].Replace( nArrPos+nCPos,
2719 							sOldCurString.Len(), rCur );
2720 						rString.Replace( nStringPos+nCPos,
2721 							sOldCurString.Len(), rCur );
2722 					}
2723 				}
2724 			}
2725 			break;
2726 			case NF_SYMBOLTYPE_CURRENCY :
2727 			{
2728 				rString += sStrArray[i];
2729 				RemoveQuotes( sStrArray[i] );
2730 			}
2731 			break;
2732             case NF_KEY_THAI_T:
2733                 if (bThaiT && GetNatNumModifier() == 1)
2734                 {   // Remove T from format code, will be replaced with a [NatNum1] prefix.
2735                     nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2736                     nAnzResStrings--;
2737                 }
2738                 else
2739                     rString += sStrArray[i];
2740             break;
2741 			case NF_SYMBOLTYPE_EMPTY :
2742 				// nothing
2743 			break;
2744 			default:
2745 				rString += sStrArray[i];
2746 		}
2747 		i++;
2748 	}
2749 	return 0;
2750 }
2751 
2752 
2753 xub_StrLen ImpSvNumberformatScan::RemoveQuotes( String& rStr )
2754 {
2755 	if ( rStr.Len() > 1 )
2756 	{
2757 		sal_Unicode c = rStr.GetChar(0);
2758 		xub_StrLen n;
2759 		if ( c == '"' && rStr.GetChar( (n = xub_StrLen(rStr.Len()-1)) ) == '"' )
2760 		{
2761 			rStr.Erase(n,1);
2762 			rStr.Erase(0,1);
2763 			return 2;
2764 		}
2765 		else if ( c == '\\' )
2766 		{
2767 			rStr.Erase(0,1);
2768 			return 1;
2769 		}
2770 	}
2771 	return 0;
2772 }
2773 
2774 
2775 xub_StrLen ImpSvNumberformatScan::ScanFormat( String& rString, String& rComment )
2776 {
2777 	xub_StrLen res = Symbol_Division(rString);	//lexikalische Analyse
2778 	if (!res)
2779 		res = ScanType(rString);            // Erkennung des Formattyps
2780 	if (!res)
2781 		res = FinalScan( rString, rComment );	// Typabhaengige Endanalyse
2782 	return res;								// res = Kontrollposition
2783 											// res = 0 => Format ok
2784 }
2785 
2786 void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, sal_uInt16 nAnz)
2787 {
2788 	size_t i,j;
2789 	j = 0;
2790 	i = 0;
2791 	while (i < nAnz && j < NF_MAX_FORMAT_SYMBOLS)
2792 	{
2793 		if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY)
2794 		{
2795 			pInfo->sStrArray[i]  = sStrArray[j];
2796 			pInfo->nTypeArray[i] = nTypeArray[j];
2797 			i++;
2798 		}
2799 		j++;
2800 	}
2801 	pInfo->eScannedType = eScannedType;
2802 	pInfo->bThousand    = bThousand;
2803 	pInfo->nThousand    = nThousand;
2804 	pInfo->nCntPre      = nCntPre;
2805 	pInfo->nCntPost     = nCntPost;
2806 	pInfo->nCntExp      = nCntExp;
2807 }
2808 
2809 
2810