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