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