xref: /aoo42x/main/svl/source/numbers/zformat.cxx (revision 40df464e)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svl.hxx"
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <float.h>
29 // #include <math.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <tools/debug.hxx>
33 #include <i18npool/mslangid.hxx>
34 #include <rtl/math.hxx>
35 #include <rtl/instance.hxx>
36 #include <unotools/charclass.hxx>
37 #include <unotools/calendarwrapper.hxx>
38 #include <unotools/nativenumberwrapper.hxx>
39 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
40 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
41 #include <com/sun/star/i18n/CalendarDisplayCode.hpp>
42 #include <com/sun/star/i18n/AmPmValue.hpp>
43 
44 #define _ZFORMAT_CXX
45 #include <svl/zformat.hxx>
46 #include <zforscan.hxx>
47 
48 #include "zforfind.hxx"
49 #include <svl/zforlist.hxx>
50 #include "numhead.hxx"
51 #include <unotools/digitgroupingiterator.hxx>
52 #include <svl/nfsymbol.hxx>
53 
54 #include <cmath>
55 
56 using namespace svt;
57 
58 namespace {
59 struct Gregorian
60     : public rtl::StaticWithInit<const ::rtl::OUString, Gregorian> {
61     const ::rtl::OUString operator () () {
62         return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian"));
63     }
64 };
65 
66 const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary...
67 const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value.
68 
69 }
70 
71 const double _D_MAX_U_LONG_ = (double) 0xffffffff;      // 4294967295.0
72 const double _D_MAX_LONG_   = (double) 0x7fffffff;      // 2147483647.0
73 const sal_uInt16 _MAX_FRACTION_PREC = 3;
74 const double D_EPS = 1.0E-2;
75 
76 const double _D_MAX_D_BY_100  = 1.7E306;
77 const double _D_MIN_M_BY_1000 = 2.3E-305;
78 
79 static sal_uInt8 cCharWidths[ 128-32 ] = {
80     1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
81     2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
82     3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
83     2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
84     1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
85     2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
86 };
87 
88 // static
89 xub_StrLen SvNumberformat::InsertBlanks( String& r, xub_StrLen nPos, sal_Unicode c )
90 {
91     if( c >= 32 )
92     {
93         sal_uInt16 n = 2;   // Default fuer Zeichen > 128 (HACK!)
94         if( c <= 127 )
95             n = cCharWidths[ c - 32 ];
96         while( n-- )
97             r.Insert( ' ', nPos++ );
98     }
99     return nPos;
100 }
101 
102 static long GetPrecExp( double fAbsVal )
103 {
104     DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" );
105     if ( fAbsVal < 1e-7 || fAbsVal > 1e7 )
106     {   // die Schere, ob's schneller ist oder nicht, liegt zwischen 1e6 und 1e7
107         return (long) floor( log10( fAbsVal ) ) + 1;
108     }
109     else
110     {
111         long nPrecExp = 1;
112         while( fAbsVal < 1 )
113         {
114             fAbsVal *= 10;
115             nPrecExp--;
116         }
117         while( fAbsVal >= 10 )
118         {
119             fAbsVal /= 10;
120             nPrecExp++;
121         }
122         return nPrecExp;
123     }
124 }
125 
126 const sal_uInt16 nNewCurrencyVersionId = 0x434E;    // "NC"
127 const sal_Unicode cNewCurrencyMagic = 0x01;     // Magic for format code in comment
128 const sal_uInt16 nNewStandardFlagVersionId = 0x4653;    // "SF"
129 
130 /***********************Funktion SvNumberformatInfo******************************/
131 
132 void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz )
133 {
134     for (sal_uInt16 i = 0; i < nAnz; i++)
135     {
136         sStrArray[i]  = rNumFor.sStrArray[i];
137         nTypeArray[i] = rNumFor.nTypeArray[i];
138     }
139     eScannedType = rNumFor.eScannedType;
140     bThousand    = rNumFor.bThousand;
141     nThousand    = rNumFor.nThousand;
142     nCntPre      = rNumFor.nCntPre;
143     nCntPost     = rNumFor.nCntPost;
144     nCntExp      = rNumFor.nCntExp;
145 }
146 
147 void ImpSvNumberformatInfo::Save(SvStream& rStream, sal_uInt16 nAnz) const
148 {
149     for (sal_uInt16 i = 0; i < nAnz; i++)
150     {
151         rStream.WriteByteString( sStrArray[i], rStream.GetStreamCharSet() );
152         short nType = nTypeArray[i];
153         switch ( nType )
154         {   // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR
155             case NF_SYMBOLTYPE_CURRENCY :
156                 rStream << short( NF_SYMBOLTYPE_STRING );
157             break;
158             case NF_SYMBOLTYPE_CURRDEL :
159             case NF_SYMBOLTYPE_CURREXT :
160                 rStream << short(0);        // werden ignoriert (hoffentlich..)
161             break;
162             default:
163                 if ( nType > NF_KEY_LASTKEYWORD_SO5 )
164                     rStream << short( NF_SYMBOLTYPE_STRING );  // all new keywords are string
165                 else
166                     rStream << nType;
167         }
168 
169     }
170     rStream << eScannedType << bThousand << nThousand
171             << nCntPre << nCntPost << nCntExp;
172 }
173 
174 void ImpSvNumberformatInfo::Load(SvStream& rStream, sal_uInt16 nAnz)
175 {
176     for (sal_uInt16 i = 0; i < nAnz; i++)
177     {
178         SvNumberformat::LoadString( rStream, sStrArray[i] );
179         rStream >> nTypeArray[i];
180     }
181     rStream >> eScannedType >> bThousand >> nThousand
182             >> nCntPre >> nCntPost >> nCntExp;
183 }
184 
185 
186 //============================================================================
187 
188 // static
189 sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, sal_Bool bDate )
190 {
191     sal_uInt8 nNatNum = 0;
192     eLang = MsLangId::getRealLanguage( eLang );  // resolve SYSTEM etc.
193     eLang &= 0x03FF;    // 10 bit primary language
194     if ( bDate )
195     {
196         if ( nDBNum == 4 && eLang == LANGUAGE_KOREAN )
197             nNatNum = 9;
198         else if ( nDBNum <= 3 )
199             nNatNum = nDBNum;   // known to be good for: zh,ja,ko / 1,2,3
200     }
201     else
202     {
203         switch ( nDBNum )
204         {
205             case 1:
206                 switch ( eLang )
207                 {
208                     case (LANGUAGE_CHINESE  & 0x03FF) : nNatNum = 4; break;
209                     case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 1; break;
210                     case (LANGUAGE_KOREAN   & 0x03FF) : nNatNum = 1; break;
211                 }
212                 break;
213             case 2:
214                 switch ( eLang )
215                 {
216                     case (LANGUAGE_CHINESE  & 0x03FF) : nNatNum = 5; break;
217                     case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 4; break;
218                     case (LANGUAGE_KOREAN   & 0x03FF) : nNatNum = 2; break;
219                 }
220                 break;
221             case 3:
222                 switch ( eLang )
223                 {
224                     case (LANGUAGE_CHINESE  & 0x03FF) : nNatNum = 6; break;
225                     case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 5; break;
226                     case (LANGUAGE_KOREAN   & 0x03FF) : nNatNum = 3; break;
227                 }
228                 break;
229             case 4:
230                 switch ( eLang )
231                 {
232                     case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 7; break;
233                     case (LANGUAGE_KOREAN   & 0x03FF) : nNatNum = 9; break;
234                 }
235                 break;
236         }
237     }
238     return nNatNum;
239 }
240 
241 
242 // static
243 sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, sal_Bool bDate )
244 {
245     sal_uInt8 nDBNum = 0;
246     eLang = MsLangId::getRealLanguage( eLang );  // resolve SYSTEM etc.
247     eLang &= 0x03FF;    // 10 bit primary language
248     if ( bDate )
249     {
250         if ( nNatNum == 9 && eLang == LANGUAGE_KOREAN )
251             nDBNum = 4;
252         else if ( nNatNum <= 3 )
253             nDBNum = nNatNum;   // known to be good for: zh,ja,ko / 1,2,3
254     }
255     else
256     {
257         switch ( nNatNum )
258         {
259             case 1:
260                 switch ( eLang )
261                 {
262                     case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 1; break;
263                     case (LANGUAGE_KOREAN   & 0x03FF) : nDBNum = 1; break;
264                 }
265                 break;
266             case 2:
267                 switch ( eLang )
268                 {
269                     case (LANGUAGE_KOREAN   & 0x03FF) : nDBNum = 2; break;
270                 }
271                 break;
272             case 3:
273                 switch ( eLang )
274                 {
275                     case (LANGUAGE_KOREAN   & 0x03FF) : nDBNum = 3; break;
276                 }
277                 break;
278             case 4:
279                 switch ( eLang )
280                 {
281                     case (LANGUAGE_CHINESE  & 0x03FF) : nDBNum = 1; break;
282                     case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 2; break;
283                 }
284                 break;
285             case 5:
286                 switch ( eLang )
287                 {
288                     case (LANGUAGE_CHINESE  & 0x03FF) : nDBNum = 2; break;
289                     case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 3; break;
290                 }
291                 break;
292             case 6:
293                 switch ( eLang )
294                 {
295                     case (LANGUAGE_CHINESE  & 0x03FF) : nDBNum = 3; break;
296                 }
297                 break;
298             case 7:
299                 switch ( eLang )
300                 {
301                     case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 4; break;
302                 }
303                 break;
304             case 8:
305                 break;
306             case 9:
307                 switch ( eLang )
308                 {
309                     case (LANGUAGE_KOREAN   & 0x03FF) : nDBNum = 4; break;
310                 }
311                 break;
312             case 10:
313                 break;
314             case 11:
315                 break;
316         }
317     }
318     return nDBNum;
319 }
320 
321 /***********************Funktionen SvNumFor******************************/
322 
323 ImpSvNumFor::ImpSvNumFor()
324 {
325     nAnzStrings = 0;
326     aI.nTypeArray = NULL;
327     aI.sStrArray = NULL;
328     aI.eScannedType = NUMBERFORMAT_UNDEFINED;
329     aI.bThousand = sal_False;
330     aI.nThousand = 0;
331     aI.nCntPre = 0;
332     aI.nCntPost = 0;
333     aI.nCntExp = 0;
334     pColor = NULL;
335 }
336 
337 ImpSvNumFor::~ImpSvNumFor()
338 {
339     for (sal_uInt16 i = 0; i < nAnzStrings; i++)
340         aI.sStrArray[i].Erase();
341     delete [] aI.sStrArray;
342     delete [] aI.nTypeArray;
343 }
344 
345 void ImpSvNumFor::Enlarge(sal_uInt16 nAnz)
346 {
347     if ( nAnzStrings != nAnz )
348     {
349         if ( aI.nTypeArray )
350             delete [] aI.nTypeArray;
351         if ( aI.sStrArray )
352             delete [] aI.sStrArray;
353         nAnzStrings = nAnz;
354         if ( nAnz )
355         {
356             aI.nTypeArray = new short[nAnz];
357             aI.sStrArray  = new String[nAnz];
358         }
359         else
360         {
361             aI.nTypeArray = NULL;
362             aI.sStrArray  = NULL;
363         }
364     }
365 }
366 
367 void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc )
368 {
369     Enlarge( rNumFor.nAnzStrings );
370     aI.Copy( rNumFor.aI, nAnzStrings );
371     sColorName = rNumFor.sColorName;
372     if ( pSc )
373         pColor = pSc->GetColor( sColorName );   // #121103# don't copy pointer between documents
374     else
375         pColor = rNumFor.pColor;
376     aNatNum = rNumFor.aNatNum;
377 }
378 
379 void ImpSvNumFor::Save(SvStream& rStream) const
380 {
381     rStream << nAnzStrings;
382     aI.Save(rStream, nAnzStrings);
383     rStream.WriteByteString( sColorName, rStream.GetStreamCharSet() );
384 }
385 
386 void ImpSvNumFor::Load(SvStream& rStream, ImpSvNumberformatScan& rSc,
387         String& rLoadedColorName )
388 {
389     sal_uInt16 nAnz;
390     rStream >> nAnz;        //! noch nicht direkt nAnzStrings wg. Enlarge
391     Enlarge( nAnz );
392     aI.Load( rStream, nAnz );
393     rStream.ReadByteString( sColorName, rStream.GetStreamCharSet() );
394     rLoadedColorName = sColorName;
395     pColor = rSc.GetColor(sColorName);
396 }
397 
398 
399 sal_Bool ImpSvNumFor::HasNewCurrency() const
400 {
401     for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
402     {
403         if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
404             return sal_True;
405     }
406     return sal_False;
407 }
408 
409 
410 sal_Bool ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol,
411             String& rExtension ) const
412 {
413     for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
414     {
415         if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
416         {
417             rSymbol = aI.sStrArray[j];
418             if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT )
419                 rExtension = aI.sStrArray[j+1];
420             else
421                 rExtension.Erase();
422             return sal_True;
423         }
424     }
425     //! kein Erase an rSymbol, rExtension
426     return sal_False;
427 }
428 
429 
430 void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const
431 {
432     sal_uInt16 j;
433     sal_uInt16 nCnt = 0;
434     for ( j=0; j<nAnzStrings; j++ )
435     {
436         switch ( aI.nTypeArray[j] )
437         {
438             case NF_SYMBOLTYPE_CURRENCY :
439             case NF_SYMBOLTYPE_CURRDEL :
440             case NF_SYMBOLTYPE_CURREXT :
441                 nCnt++;
442             break;
443         }
444     }
445     rStream << nCnt;
446     for ( j=0; j<nAnzStrings; j++ )
447     {
448         switch ( aI.nTypeArray[j] )
449         {
450             case NF_SYMBOLTYPE_CURRENCY :
451             case NF_SYMBOLTYPE_CURRDEL :
452             case NF_SYMBOLTYPE_CURREXT :
453                 rStream << j << aI.nTypeArray[j];
454             break;
455         }
456     }
457 }
458 
459 
460 void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream )
461 {
462     sal_uInt16 nCnt;
463     rStream >> nCnt;
464     for ( sal_uInt16 j=0; j<nCnt; j++ )
465     {
466         sal_uInt16 nPos;
467         short nType;
468         rStream >> nPos >> nType;
469         if ( nPos < nAnzStrings )
470             aI.nTypeArray[nPos] = nType;
471     }
472 }
473 
474 
475 /***********************Funktionen SvNumberformat************************/
476 
477 enum BracketFormatSymbolType
478 {
479     BRACKET_SYMBOLTYPE_FORMAT   = -1,   // subformat string
480     BRACKET_SYMBOLTYPE_COLOR    = -2,   // color
481     BRACKET_SYMBOLTYPE_ERROR    = -3,   // error
482     BRACKET_SYMBOLTYPE_DBNUM1   = -4,   // DoubleByteNumber, represent numbers
483     BRACKET_SYMBOLTYPE_DBNUM2   = -5,   // using CJK characters, Excel compatible.
484     BRACKET_SYMBOLTYPE_DBNUM3   = -6,
485     BRACKET_SYMBOLTYPE_DBNUM4   = -7,
486     BRACKET_SYMBOLTYPE_DBNUM5   = -8,
487     BRACKET_SYMBOLTYPE_DBNUM6   = -9,
488     BRACKET_SYMBOLTYPE_DBNUM7   = -10,
489     BRACKET_SYMBOLTYPE_DBNUM8   = -11,
490     BRACKET_SYMBOLTYPE_DBNUM9   = -12,
491     BRACKET_SYMBOLTYPE_LOCALE   = -13,
492     BRACKET_SYMBOLTYPE_NATNUM0  = -14,  // Our NativeNumber support, ASCII
493     BRACKET_SYMBOLTYPE_NATNUM1  = -15,  // Our NativeNumber support, represent
494     BRACKET_SYMBOLTYPE_NATNUM2  = -16,  //  numbers using CJK, CTL, ...
495     BRACKET_SYMBOLTYPE_NATNUM3  = -17,
496     BRACKET_SYMBOLTYPE_NATNUM4  = -18,
497     BRACKET_SYMBOLTYPE_NATNUM5  = -19,
498     BRACKET_SYMBOLTYPE_NATNUM6  = -20,
499     BRACKET_SYMBOLTYPE_NATNUM7  = -21,
500     BRACKET_SYMBOLTYPE_NATNUM8  = -22,
501     BRACKET_SYMBOLTYPE_NATNUM9  = -23,
502     BRACKET_SYMBOLTYPE_NATNUM10 = -24,
503     BRACKET_SYMBOLTYPE_NATNUM11 = -25,
504     BRACKET_SYMBOLTYPE_NATNUM12 = -26,
505     BRACKET_SYMBOLTYPE_NATNUM13 = -27,
506     BRACKET_SYMBOLTYPE_NATNUM14 = -28,
507     BRACKET_SYMBOLTYPE_NATNUM15 = -29,
508     BRACKET_SYMBOLTYPE_NATNUM16 = -30,
509     BRACKET_SYMBOLTYPE_NATNUM17 = -31,
510     BRACKET_SYMBOLTYPE_NATNUM18 = -32,
511     BRACKET_SYMBOLTYPE_NATNUM19 = -33
512 };
513 
514 SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge )
515         :
516         rScan(rSc),
517         eLnge(eLge),
518         nNewStandardDefined(0),
519         bStarFlag( sal_False )
520 {
521 }
522 
523 void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat )
524 {
525     sFormatstring = rFormat.sFormatstring;
526     eType         = rFormat.eType;
527     eLnge         = rFormat.eLnge;
528     fLimit1       = rFormat.fLimit1;
529     fLimit2       = rFormat.fLimit2;
530     eOp1          = rFormat.eOp1;
531     eOp2          = rFormat.eOp2;
532     bStandard     = rFormat.bStandard;
533     bIsUsed       = rFormat.bIsUsed;
534     sComment      = rFormat.sComment;
535     nNewStandardDefined = rFormat.nNewStandardDefined;
536 
537     // #121103# when copying between documents, get color pointers from own scanner
538     ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL;
539 
540     for (sal_uInt16 i = 0; i < 4; i++)
541         NumFor[i].Copy(rFormat.NumFor[i], pColorSc);
542 }
543 
544 SvNumberformat::SvNumberformat( SvNumberformat& rFormat )
545     : rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag )
546 {
547     ImpCopyNumberformat( rFormat );
548 }
549 
550 SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc )
551     : rScan(rSc), bStarFlag( rFormat.bStarFlag )
552 {
553     ImpCopyNumberformat( rFormat );
554 }
555 
556 
557 sal_Bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
558 {
559     if ( nSymbolType > 0  )
560         return sal_True;        // conditions
561     switch ( nSymbolType )
562     {
563         case BRACKET_SYMBOLTYPE_COLOR :
564         case BRACKET_SYMBOLTYPE_DBNUM1 :
565         case BRACKET_SYMBOLTYPE_DBNUM2 :
566         case BRACKET_SYMBOLTYPE_DBNUM3 :
567         case BRACKET_SYMBOLTYPE_DBNUM4 :
568         case BRACKET_SYMBOLTYPE_DBNUM5 :
569         case BRACKET_SYMBOLTYPE_DBNUM6 :
570         case BRACKET_SYMBOLTYPE_DBNUM7 :
571         case BRACKET_SYMBOLTYPE_DBNUM8 :
572         case BRACKET_SYMBOLTYPE_DBNUM9 :
573         case BRACKET_SYMBOLTYPE_LOCALE :
574         case BRACKET_SYMBOLTYPE_NATNUM0 :
575         case BRACKET_SYMBOLTYPE_NATNUM1 :
576         case BRACKET_SYMBOLTYPE_NATNUM2 :
577         case BRACKET_SYMBOLTYPE_NATNUM3 :
578         case BRACKET_SYMBOLTYPE_NATNUM4 :
579         case BRACKET_SYMBOLTYPE_NATNUM5 :
580         case BRACKET_SYMBOLTYPE_NATNUM6 :
581         case BRACKET_SYMBOLTYPE_NATNUM7 :
582         case BRACKET_SYMBOLTYPE_NATNUM8 :
583         case BRACKET_SYMBOLTYPE_NATNUM9 :
584         case BRACKET_SYMBOLTYPE_NATNUM10 :
585         case BRACKET_SYMBOLTYPE_NATNUM11 :
586         case BRACKET_SYMBOLTYPE_NATNUM12 :
587         case BRACKET_SYMBOLTYPE_NATNUM13 :
588         case BRACKET_SYMBOLTYPE_NATNUM14 :
589         case BRACKET_SYMBOLTYPE_NATNUM15 :
590         case BRACKET_SYMBOLTYPE_NATNUM16 :
591         case BRACKET_SYMBOLTYPE_NATNUM17 :
592         case BRACKET_SYMBOLTYPE_NATNUM18 :
593         case BRACKET_SYMBOLTYPE_NATNUM19 :
594             return sal_True;
595     }
596     return sal_False;
597 }
598 
599 
600 SvNumberformat::SvNumberformat(String& rString,
601                                ImpSvNumberformatScan* pSc,
602                                ImpSvNumberInputScan* pISc,
603                                xub_StrLen& nCheckPos,
604                                LanguageType& eLan,
605                                sal_Bool bStan)
606         :
607         rScan(*pSc),
608         nNewStandardDefined(0),
609         bStarFlag( sal_False )
610 {
611     // If the group (AKA thousand) separator is a Non-Breaking Space (French)
612     // replace all occurences by a simple space.
613     // The tokens will be changed to the LocaleData separator again later on.
614     const sal_Unicode cNBSp = 0xA0;
615     const String& rThSep = GetFormatter().GetNumThousandSep();
616     if ( rThSep.GetChar(0) == cNBSp && rThSep.Len() == 1 )
617     {
618         xub_StrLen nIndex = 0;
619         do
620             nIndex = rString.SearchAndReplace( cNBSp, ' ', nIndex );
621         while ( nIndex != STRING_NOTFOUND );
622     }
623 
624     if (rScan.GetConvertMode())
625     {
626         eLnge = rScan.GetNewLnge();
627         eLan = eLnge;                   // Wechsel auch zurueckgeben
628     }
629     else
630         eLnge = eLan;
631     bStandard = bStan;
632     bIsUsed = sal_False;
633     fLimit1 = 0.0;
634     fLimit2 = 0.0;
635     eOp1 = NUMBERFORMAT_OP_NO;
636     eOp2 = NUMBERFORMAT_OP_NO;
637     eType = NUMBERFORMAT_DEFINED;
638 
639     sal_Bool bCancel = sal_False;
640     sal_Bool bCondition = sal_False;
641     short eSymbolType;
642     xub_StrLen nPos = 0;
643     xub_StrLen nPosOld;
644     nCheckPos = 0;
645     String aComment;
646 
647     // Split into 4 sub formats
648     sal_uInt16 nIndex;
649     for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ )
650     {
651         // Original language/country may have to be reestablished
652         if (rScan.GetConvertMode())
653             (rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge());
654 
655         String sStr;
656         nPosOld = nPos;                         // Start position of substring
657         // first get bracketed prefixes; e.g. conditions, color
658         do
659         {
660             eSymbolType = ImpNextSymbol(rString, nPos, sStr);
661             if (eSymbolType > 0)                    // condition
662             {
663                 if ( nIndex == 0 && !bCondition )
664                 {
665                     bCondition = sal_True;
666                     eOp1 = (SvNumberformatLimitOps) eSymbolType;
667                 }
668                 else if ( nIndex == 1 && bCondition )
669                     eOp2 = (SvNumberformatLimitOps) eSymbolType;
670                 else                                // error
671                 {
672                     bCancel = sal_True;                 // break for
673                     nCheckPos = nPosOld;
674                 }
675                 if (!bCancel)
676                 {
677                     double fNumber;
678                     xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr);
679                     if (nAnzChars > 0)
680                     {
681                         short F_Type = NUMBERFORMAT_UNDEFINED;
682                         if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
683                             ( F_Type != NUMBERFORMAT_NUMBER &&
684                             F_Type != NUMBERFORMAT_SCIENTIFIC) )
685                         {
686                             fNumber = 0.0;
687                             nPos = nPos - nAnzChars;
688                             rString.Erase(nPos, nAnzChars);
689                             rString.Insert('0',nPos);
690                             nPos++;
691                         }
692                     }
693                     else
694                     {
695                         fNumber = 0.0;
696                         rString.Insert('0',nPos++);
697                     }
698                     if (nIndex == 0)
699                         fLimit1 = fNumber;
700                     else
701                         fLimit2 = fNumber;
702                     if ( rString.GetChar(nPos) == ']' )
703                         nPos++;
704                     else
705                     {
706                         bCancel = sal_True;             // break for
707                         nCheckPos = nPos;
708                     }
709                 }
710                 nPosOld = nPos;                     // position before string
711             }
712             else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
713             {
714                 switch ( eSymbolType )
715                 {
716                     case BRACKET_SYMBOLTYPE_COLOR :
717                     {
718                         if ( NumFor[nIndex].GetColor() != NULL )
719                         {                           // error, more than one color
720                             bCancel = sal_True;         // break for
721                             nCheckPos = nPosOld;
722                         }
723                         else
724                         {
725                             Color* pColor = pSc->GetColor( sStr);
726                             NumFor[nIndex].SetColor( pColor, sStr);
727                             if (pColor == NULL)
728                             {                       // error
729                                 bCancel = sal_True;     // break for
730                                 nCheckPos = nPosOld;
731                             }
732                         }
733                     }
734                     break;
735                     case BRACKET_SYMBOLTYPE_NATNUM0 :
736                     case BRACKET_SYMBOLTYPE_NATNUM1 :
737                     case BRACKET_SYMBOLTYPE_NATNUM2 :
738                     case BRACKET_SYMBOLTYPE_NATNUM3 :
739                     case BRACKET_SYMBOLTYPE_NATNUM4 :
740                     case BRACKET_SYMBOLTYPE_NATNUM5 :
741                     case BRACKET_SYMBOLTYPE_NATNUM6 :
742                     case BRACKET_SYMBOLTYPE_NATNUM7 :
743                     case BRACKET_SYMBOLTYPE_NATNUM8 :
744                     case BRACKET_SYMBOLTYPE_NATNUM9 :
745                     case BRACKET_SYMBOLTYPE_NATNUM10 :
746                     case BRACKET_SYMBOLTYPE_NATNUM11 :
747                     case BRACKET_SYMBOLTYPE_NATNUM12 :
748                     case BRACKET_SYMBOLTYPE_NATNUM13 :
749                     case BRACKET_SYMBOLTYPE_NATNUM14 :
750                     case BRACKET_SYMBOLTYPE_NATNUM15 :
751                     case BRACKET_SYMBOLTYPE_NATNUM16 :
752                     case BRACKET_SYMBOLTYPE_NATNUM17 :
753                     case BRACKET_SYMBOLTYPE_NATNUM18 :
754                     case BRACKET_SYMBOLTYPE_NATNUM19 :
755                     {
756                         if ( NumFor[nIndex].GetNatNum().IsSet() )
757                         {
758                             bCancel = sal_True;         // break for
759                             nCheckPos = nPosOld;
760                         }
761                         else
762                         {
763                             sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) );
764                             //! eSymbolType is negative
765                             sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0));
766                             sStr += String::CreateFromInt32( nNum );
767                             NumFor[nIndex].SetNatNumNum( nNum, sal_False );
768                         }
769                     }
770                     break;
771                     case BRACKET_SYMBOLTYPE_DBNUM1 :
772                     case BRACKET_SYMBOLTYPE_DBNUM2 :
773                     case BRACKET_SYMBOLTYPE_DBNUM3 :
774                     case BRACKET_SYMBOLTYPE_DBNUM4 :
775                     case BRACKET_SYMBOLTYPE_DBNUM5 :
776                     case BRACKET_SYMBOLTYPE_DBNUM6 :
777                     case BRACKET_SYMBOLTYPE_DBNUM7 :
778                     case BRACKET_SYMBOLTYPE_DBNUM8 :
779                     case BRACKET_SYMBOLTYPE_DBNUM9 :
780                     {
781                         if ( NumFor[nIndex].GetNatNum().IsSet() )
782                         {
783                             bCancel = sal_True;         // break for
784                             nCheckPos = nPosOld;
785                         }
786                         else
787                         {
788                             sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) );
789                             //! eSymbolType is negative
790                             sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1));
791                             sStr += static_cast< sal_Unicode >('0' + nNum);
792                             NumFor[nIndex].SetNatNumNum( nNum, sal_True );
793                         }
794                     }
795                     break;
796                     case BRACKET_SYMBOLTYPE_LOCALE :
797                     {
798                         if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW )
799                         {
800                             bCancel = sal_True;         // break for
801                             nCheckPos = nPosOld;
802                         }
803                         else
804                         {
805                             xub_StrLen nTmp = 2;
806                             LanguageType eLang = ImpGetLanguageType( sStr, nTmp );
807                             if ( eLang == LANGUAGE_DONTKNOW )
808                             {
809                                 bCancel = sal_True;         // break for
810                                 nCheckPos = nPosOld;
811                             }
812                             else
813                             {
814                                 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) );
815                                 sStr += String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii();
816                                 NumFor[nIndex].SetNatNumLang( eLang );
817                             }
818                         }
819                     }
820                     break;
821                 }
822                 if ( !bCancel )
823                 {
824                     rString.Erase(nPosOld,nPos-nPosOld);
825                     rString.Insert(sStr,nPosOld);
826                     nPos = nPosOld + sStr.Len();
827                     rString.Insert(']', nPos);
828                     rString.Insert('[', nPosOld);
829                     nPos += 2;
830                     nPosOld = nPos;     // position before string
831                 }
832             }
833         } while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) );
834 
835         // The remaining format code string
836         if ( !bCancel )
837         {
838             if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT)
839             {
840                 if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO)
841                     eOp1 = NUMBERFORMAT_OP_GT;  // undefined condition, default: > 0
842                 else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO)
843                     eOp2 = NUMBERFORMAT_OP_LT;  // undefined condition, default: < 0
844                 if (sStr.Len() == 0)
845                 {   // empty sub format
846                 }
847                 else
848                 {
849                     xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment );
850                     sal_uInt16 nAnz = pSc->GetAnzResStrings();
851                     if (nAnz == 0)              // error
852                         nStrPos = 1;
853                     if (nStrPos == 0)               // ok
854                     {
855                         // e.g. Thai T speciality
856                         if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet())
857                         {
858                             String aNat( RTL_CONSTASCII_USTRINGPARAM( "[NatNum"));
859                             aNat += String::CreateFromInt32( pSc->GetNatNumModifier());
860                             aNat += ']';
861                             sStr.Insert( aNat, 0);
862                             NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), sal_False );
863                         }
864                         // #i53826# #i42727# For the Thai T speciality we need
865                         // to freeze the locale and immunize it against
866                         // conversions during exports, just in case we want to
867                         // save to Xcl. This disables the feature of being able
868                         // to convert a NatNum to another locale. You can't
869                         // have both.
870                         // FIXME: implement a specialized export conversion
871                         // that works on tokens (have to tokenize all first)
872                         // and doesn't use the format string and
873                         // PutandConvertEntry() to LANGUAGE_ENGLISH_US in
874                         // sc/source/filter/excel/xestyle.cxx
875                         // XclExpNumFmtBuffer::WriteFormatRecord().
876                         LanguageType eLanguage;
877                         if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 &&
878                                 ((eLanguage =
879                                   MsLangId::getRealLanguage( eLan))
880                                  == LANGUAGE_THAI) &&
881                                 NumFor[nIndex].GetNatNum().GetLang() ==
882                                 LANGUAGE_DONTKNOW)
883                         {
884                             String aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-"));
885                             aLID += String::CreateFromInt32( sal_Int32(
886                                         eLanguage), 16 ).ToUpperAscii();
887                             aLID += ']';
888                             sStr.Insert( aLID, 0);
889                             NumFor[nIndex].SetNatNumLang( eLanguage);
890                         }
891                         rString.Erase(nPosOld,nPos-nPosOld);
892                         rString.Insert(sStr,nPosOld);
893                         nPos = nPosOld + sStr.Len();
894                         if (nPos < rString.Len())
895                         {
896                             rString.Insert(';',nPos);
897                             nPos++;
898                         }
899                         NumFor[nIndex].Enlarge(nAnz);
900                         pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz);
901                         // type check
902                         if (nIndex == 0)
903                             eType = (short) NumFor[nIndex].Info().eScannedType;
904                         else if (nIndex == 3)
905                         {   // #77026# Everything recognized IS text
906                             NumFor[nIndex].Info().eScannedType = NUMBERFORMAT_TEXT;
907                         }
908                         else if ( (short) NumFor[nIndex].Info().eScannedType !=
909                             eType)
910                             eType = NUMBERFORMAT_DEFINED;
911                     }
912                     else
913                     {
914                         nCheckPos = nPosOld + nStrPos;  // error in string
915                         bCancel = sal_True;                 // break for
916                     }
917                 }
918             }
919             else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR)   // error
920             {
921                 nCheckPos = nPosOld;
922                 bCancel = sal_True;
923             }
924             else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
925             {
926                 nCheckPos = nPosOld+1;                  // error, prefix in string
927                 bCancel = sal_True;                         // break for
928             }
929         }
930         if ( bCancel && !nCheckPos )
931             nCheckPos = 1;      // nCheckPos is used as an error condition
932         if ( !bCancel )
933         {
934             if ( NumFor[nIndex].GetNatNum().IsSet() &&
935                     NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW )
936                  NumFor[nIndex].SetNatNumLang( eLan );
937         }
938         if (rString.Len() == nPos)
939         {
940             if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT &&
941                     rString.GetChar(nPos-1) == ';' )
942             {   // #83510# A 4th subformat explicitly specified to be empty
943                 // hides any text. Need the type here for HasTextFormat()
944                 NumFor[3].Info().eScannedType = NUMBERFORMAT_TEXT;
945             }
946             bCancel = sal_True;
947         }
948         if ( NumFor[nIndex].GetNatNum().IsSet() )
949             NumFor[nIndex].SetNatNumDate(
950                 (NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 );
951     }
952 
953     if ( bCondition && !nCheckPos )
954     {
955         if ( nIndex == 1 && NumFor[0].GetnAnz() == 0 &&
956                 rString.GetChar(rString.Len()-1) != ';' )
957         {   // No format code => GENERAL   but not if specified empty
958             String aAdd( pSc->GetStandardName() );
959             String aTmp;
960             if ( !pSc->ScanFormat( aAdd, aTmp ) )
961             {
962                 sal_uInt16 nAnz = pSc->GetAnzResStrings();
963                 if ( nAnz )
964                 {
965                     NumFor[0].Enlarge(nAnz);
966                     pSc->CopyInfo( &(NumFor[0].Info()), nAnz );
967                     rString += aAdd;
968                 }
969             }
970         }
971         else if ( nIndex == 1 && NumFor[nIndex].GetnAnz() == 0 &&
972                 rString.GetChar(rString.Len()-1) != ';' &&
973                 (NumFor[0].GetnAnz() > 1 || (NumFor[0].GetnAnz() == 1 &&
974                 NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) )
975         {   // No trailing second subformat => GENERAL   but not if specified empty
976             // and not if first subformat is GENERAL
977             String aAdd( pSc->GetStandardName() );
978             String aTmp;
979             if ( !pSc->ScanFormat( aAdd, aTmp ) )
980             {
981                 sal_uInt16 nAnz = pSc->GetAnzResStrings();
982                 if ( nAnz )
983                 {
984                     NumFor[nIndex].Enlarge(nAnz);
985                     pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
986                     rString += ';';
987                     rString += aAdd;
988                 }
989             }
990         }
991         else if ( nIndex == 2 && NumFor[nIndex].GetnAnz() == 0 &&
992                 rString.GetChar(rString.Len()-1) != ';' &&
993                 eOp2 != NUMBERFORMAT_OP_NO )
994         {   // No trailing third subformat => GENERAL   but not if specified empty
995             String aAdd( pSc->GetStandardName() );
996             String aTmp;
997             if ( !pSc->ScanFormat( aAdd, aTmp ) )
998             {
999                 sal_uInt16 nAnz = pSc->GetAnzResStrings();
1000                 if ( nAnz )
1001                 {
1002                     NumFor[nIndex].Enlarge(nAnz);
1003                     pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
1004                     rString += ';';
1005                     rString += aAdd;
1006                 }
1007             }
1008         }
1009     }
1010     sFormatstring = rString;
1011     if ( aComment.Len() )
1012     {
1013         SetComment( aComment );     // setzt sComment und sFormatstring
1014         rString = sFormatstring;    // geaenderten sFormatstring uebernehmen
1015     }
1016     if (NumFor[2].GetnAnz() == 0 &&                 // kein 3. Teilstring
1017         eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO &&
1018         fLimit1 == 0.0 && fLimit2 == 0.0)
1019         eOp1 = NUMBERFORMAT_OP_GE;                  // 0 zum ersten Format dazu
1020 
1021 }
1022 
1023 SvNumberformat::~SvNumberformat()
1024 {
1025 }
1026 
1027 //---------------------------------------------------------------------------
1028 // Next_Symbol
1029 //---------------------------------------------------------------------------
1030 // Zerlegt die Eingabe in Symbole fuer die weitere
1031 // Verarbeitung (Turing-Maschine).
1032 //---------------------------------------------------------------------------
1033 // Ausgangs Zustand = SsStart
1034 //---------------+-------------------+-----------------------+---------------
1035 // Alter Zustand | gelesenes Zeichen | Aktion                | Neuer Zustand
1036 //---------------+-------------------+-----------------------+---------------
1037 // SsStart       | ;                 | Pos--                 | SsGetString
1038 //               | [                 | Symbol += Zeichen     | SsGetBracketed
1039 //               | ]                 | Fehler                | SsStop
1040 //               | BLANK             |                       |
1041 //               | Sonst             | Symbol += Zeichen     | SsGetString
1042 //---------------+-------------------+-----------------------+---------------
1043 // SsGetString   | ;                 |                       | SsStop
1044 //               | Sonst             | Symbol+=Zeichen       |
1045 //---------------+-------------------+-----------------------+---------------
1046 // SsGetBracketed| <, > =            | del [                 |
1047 //               |                   | Symbol += Zeichen     | SsGetCon
1048 //               | BLANK             |                       |
1049 //               | h, H, m, M, s, S  | Symbol += Zeichen     | SsGetTime
1050 //               | sonst             | del [                 |
1051 //               |                   | Symbol += Zeichen     | SsGetPrefix
1052 //---------------+-------------------+-----------------------+---------------
1053 // SsGetTime     | ]                 | Symbol += Zeichen     | SsGetString
1054 //               | h, H, m, M, s, S  | Symbol += Zeichen, *  | SsGetString
1055 //               | sonst             | del [; Symbol+=Zeichen| SsGetPrefix
1056 //---------------+-------------------+-----------------------+---------------
1057 // SsGetPrefix   | ]                 |                       | SsStop
1058 //               | sonst             | Symbol += Zeichen     |
1059 //---------------+-------------------+-----------------------+---------------
1060 // SsGetCon      | >, =              | Symbol+=Zeichen       |
1061 //               | ]                 |                       | SsStop
1062 //               | sonst             | Fehler                | SsStop
1063 //---------------+-------------------+-----------------------+---------------
1064 // * : Sonderbedingung
1065 
1066 enum ScanState
1067 {
1068     SsStop,
1069     SsStart,
1070     SsGetCon,           // condition
1071     SsGetString,        // format string
1072     SsGetPrefix,        // color or NatNumN
1073     SsGetTime,          // [HH] for time
1074     SsGetBracketed      // any [...] not decided yet
1075 };
1076 
1077 
1078 // read a string until ']' and delete spaces in input
1079 // static
1080 xub_StrLen SvNumberformat::ImpGetNumber(String& rString,
1081                                  xub_StrLen& nPos,
1082                                  String& sSymbol)
1083 {
1084     xub_StrLen nStartPos = nPos;
1085     sal_Unicode cToken;
1086     xub_StrLen nLen = rString.Len();
1087     sSymbol.Erase();
1088     while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
1089     {
1090         if (cToken == ' ')
1091         {                                               // delete spaces
1092             rString.Erase(nPos,1);
1093             nLen--;
1094         }
1095         else
1096         {
1097             nPos++;
1098             sSymbol += cToken;
1099         }
1100     }
1101     return nPos - nStartPos;
1102 }
1103 
1104 
1105 // static
1106 LanguageType SvNumberformat::ImpGetLanguageType( const String& rString,
1107         xub_StrLen& nPos )
1108 {
1109     sal_Int32 nNum = 0;
1110     sal_Unicode cToken = 0;
1111     xub_StrLen nLen = rString.Len();
1112     while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
1113     {
1114         if ( '0' <= cToken && cToken <= '9' )
1115         {
1116             nNum *= 16;
1117             nNum += cToken - '0';
1118         }
1119         else if ( 'a' <= cToken && cToken <= 'f' )
1120         {
1121             nNum *= 16;
1122             nNum += cToken - 'a' + 10;
1123         }
1124         else if ( 'A' <= cToken && cToken <= 'F' )
1125         {
1126             nNum *= 16;
1127             nNum += cToken - 'A' + 10;
1128         }
1129         else
1130             return LANGUAGE_DONTKNOW;
1131         ++nPos;
1132     }
1133     return (nNum && (cToken == ']' || nPos == nLen)) ? (LanguageType)nNum :
1134         LANGUAGE_DONTKNOW;
1135 }
1136 
1137 
1138 short SvNumberformat::ImpNextSymbol(String& rString,
1139                                  xub_StrLen& nPos,
1140                                  String& sSymbol)
1141 {
1142     short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1143     sal_Unicode cToken;
1144     sal_Unicode cLetter = ' ';                               // Zwischenergebnis
1145     xub_StrLen nLen = rString.Len();
1146     ScanState eState = SsStart;
1147     sSymbol.Erase();
1148     const NfKeywordTable & rKeywords = rScan.GetKeywords();
1149     while (nPos < nLen && eState != SsStop)
1150     {
1151         cToken = rString.GetChar(nPos);
1152         nPos++;
1153         switch (eState)
1154         {
1155             case SsStart:
1156             {
1157                 if (cToken == '[')
1158                 {
1159                     eState = SsGetBracketed;
1160                     sSymbol += cToken;
1161                 }
1162                 else if (cToken == ';')
1163                 {
1164                     eState = SsGetString;
1165                     nPos--;
1166                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1167                 }
1168                 else if (cToken == ']')
1169                 {
1170                     eState = SsStop;
1171                     eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1172                 }
1173                 else if (cToken == ' ')             // Skip Blanks
1174                 {
1175                     rString.Erase(nPos-1,1);
1176                     nPos--;
1177                     nLen--;
1178                 }
1179                 else
1180                 {
1181                     sSymbol += cToken;
1182                     eState = SsGetString;
1183                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1184                 }
1185             }
1186             break;
1187             case SsGetBracketed:
1188             {
1189                 switch (cToken)
1190                 {
1191                     case '<':
1192                     case '>':
1193                     case '=':
1194                     {
1195                         sSymbol.EraseAllChars('[');
1196                         sSymbol += cToken;
1197                         cLetter = cToken;
1198                         eState = SsGetCon;
1199                         switch (cToken)
1200                         {
1201                             case '<': eSymbolType = NUMBERFORMAT_OP_LT; break;
1202                             case '>': eSymbolType = NUMBERFORMAT_OP_GT; break;
1203                             case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break;
1204                             default: break;
1205                         }
1206                     }
1207                     break;
1208                     case ' ':
1209                     {
1210                         rString.Erase(nPos-1,1);
1211                         nPos--;
1212                         nLen--;
1213                     }
1214                     break;
1215                     case '$' :
1216                     {
1217                         if ( rString.GetChar(nPos) == '-' )
1218                         {   // [$-xxx] locale
1219                             sSymbol.EraseAllChars('[');
1220                             eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
1221                             eState = SsGetPrefix;
1222                         }
1223                         else
1224                         {   // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1225                             eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1226                             eState = SsGetString;
1227                         }
1228                         sSymbol += cToken;
1229                     }
1230                     break;
1231                     case '~' :
1232                     {   // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1233                         eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1234                         sSymbol += cToken;
1235                         eState = SsGetString;
1236                     }
1237                     break;
1238                     default:
1239                     {
1240                         static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) );
1241                         static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) );
1242                         String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) );
1243                         String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) );
1244                         sal_Unicode cUpper = aUpperNatNum.GetChar(0);
1245                         sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32();
1246                         sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() );
1247                         if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 )
1248                         {
1249                             sSymbol.EraseAllChars('[');
1250                             sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 );
1251                             nPos += aNatNum.Len()+1;
1252                             //! SymbolType is negative
1253                             eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum);
1254                             eState = SsGetPrefix;
1255                         }
1256                         else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' )
1257                         {
1258                             sSymbol.EraseAllChars('[');
1259                             sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 );
1260                             nPos += aDBNum.Len()+1;
1261                             //! SymbolType is negative
1262                             eSymbolType = sal::static_int_cast< short >(
1263                                 BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1'));
1264                             eState = SsGetPrefix;
1265                         }
1266                         else if (cUpper == rKeywords[NF_KEY_H].GetChar(0)   ||  // H
1267                             cUpper == rKeywords[NF_KEY_MI].GetChar(0)   ||  // M
1268                             cUpper == rKeywords[NF_KEY_S].GetChar(0)    )   // S
1269                         {
1270                             sSymbol += cToken;
1271                             eState = SsGetTime;
1272                             cLetter = cToken;
1273                         }
1274                         else
1275                         {
1276                             sSymbol.EraseAllChars('[');
1277                             sSymbol += cToken;
1278                             eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1279                             eState = SsGetPrefix;
1280                         }
1281                     }
1282                     break;
1283                 }
1284             }
1285             break;
1286             case SsGetString:
1287             {
1288                 if (cToken == ';')
1289                     eState = SsStop;
1290                 else
1291                     sSymbol += cToken;
1292             }
1293             break;
1294             case SsGetTime:
1295             {
1296                 if (cToken == ']')
1297                 {
1298                     sSymbol += cToken;
1299                     eState = SsGetString;
1300                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1301                 }
1302                 else
1303                 {
1304                     sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0);
1305                     if (cUpper == rKeywords[NF_KEY_H].GetChar(0)    ||  // H
1306                         cUpper == rKeywords[NF_KEY_MI].GetChar(0)   ||  // M
1307                         cUpper == rKeywords[NF_KEY_S].GetChar(0)    )   // S
1308                     {
1309                         if (cLetter == cToken)
1310                         {
1311                             sSymbol += cToken;
1312                             cLetter = ' ';
1313                         }
1314                         else
1315                         {
1316                             sSymbol.EraseAllChars('[');
1317                             sSymbol += cToken;
1318                             eState = SsGetPrefix;
1319                         }
1320                     }
1321                     else
1322                     {
1323                         sSymbol.EraseAllChars('[');
1324                         sSymbol += cToken;
1325                         eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1326                         eState = SsGetPrefix;
1327                     }
1328                 }
1329             }
1330             break;
1331             case SsGetCon:
1332             {
1333                 switch (cToken)
1334                 {
1335                     case '<':
1336                     {
1337                         eState = SsStop;
1338                         eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1339                     }
1340                     break;
1341                     case '>':
1342                     {
1343                         if (cLetter == '<')
1344                         {
1345                             sSymbol += cToken;
1346                             cLetter = ' ';
1347                             eState = SsStop;
1348                             eSymbolType = NUMBERFORMAT_OP_NE;
1349                         }
1350                         else
1351                         {
1352                             eState = SsStop;
1353                             eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1354                         }
1355                     }
1356                     break;
1357                     case '=':
1358                     {
1359                         if (cLetter == '<')
1360                         {
1361                             sSymbol += cToken;
1362                             cLetter = ' ';
1363                             eSymbolType = NUMBERFORMAT_OP_LE;
1364                         }
1365                         else if (cLetter == '>')
1366                         {
1367                             sSymbol += cToken;
1368                             cLetter = ' ';
1369                             eSymbolType = NUMBERFORMAT_OP_GE;
1370                         }
1371                         else
1372                         {
1373                             eState = SsStop;
1374                             eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1375                         }
1376                     }
1377                     break;
1378                     case ' ':
1379                     {
1380                         rString.Erase(nPos-1,1);
1381                         nPos--;
1382                         nLen--;
1383                     }
1384                     break;
1385                     default:
1386                     {
1387                         eState = SsStop;
1388                         nPos--;
1389                     }
1390                     break;
1391                 }
1392             }
1393             break;
1394             case SsGetPrefix:
1395             {
1396                 if (cToken == ']')
1397                     eState = SsStop;
1398                 else
1399                     sSymbol += cToken;
1400             }
1401             break;
1402             default:
1403             break;
1404         }                                   // of switch
1405     }                                       // of while
1406 
1407     return eSymbolType;
1408 }
1409 
1410 NfHackConversion SvNumberformat::Load( SvStream& rStream,
1411         ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter,
1412         ImpSvNumberInputScan& rISc )
1413 {
1414     rHdr.StartEntry();
1415     sal_uInt16 nOp1, nOp2;
1416     SvNumberformat::LoadString( rStream, sFormatstring );
1417     rStream >> eType >> fLimit1 >> fLimit2
1418             >> nOp1 >> nOp2 >> bStandard >> bIsUsed;
1419     NfHackConversion eHackConversion = NF_CONVERT_NONE;
1420     sal_Bool bOldConvert = sal_False;
1421     LanguageType eOldTmpLang = 0;
1422 	LanguageType eOldNewLang = 0;
1423     if ( pHackConverter )
1424     {   // werden nur hierbei gebraucht
1425         bOldConvert = rScan.GetConvertMode();
1426         eOldTmpLang = rScan.GetTmpLnge();
1427         eOldNewLang = rScan.GetNewLnge();
1428     }
1429     String aLoadedColorName;
1430     for (sal_uInt16 i = 0; i < 4; i++)
1431     {
1432         NumFor[i].Load( rStream, rScan, aLoadedColorName );
1433         if ( pHackConverter && eHackConversion == NF_CONVERT_NONE )
1434         {
1435             //! HACK! ER 29.07.97 13:52
1436             // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/
1437             // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert..
1438             // System-German FARBE nach System-xxx COLOR umsetzen und vice versa,
1439             //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in
1440             //! ImpSvNumberformatScan existierten
1441             if ( aLoadedColorName.Len() && !NumFor[i].GetColor()
1442                     && aLoadedColorName != rScan.GetColorString() )
1443             {
1444                 if ( rScan.GetColorString().EqualsAscii( "FARBE" ) )
1445                 {   // English -> German
1446                     eHackConversion = NF_CONVERT_ENGLISH_GERMAN;
1447                     rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US );
1448                     rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN );
1449                 }
1450                 else
1451                 {   // German -> English
1452                     eHackConversion = NF_CONVERT_GERMAN_ENGLISH;
1453                     rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN );
1454                     rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US );
1455                 }
1456                 String aColorName = NumFor[i].GetColorName();
1457                 const Color* pColor = rScan.GetColor( aColorName );
1458                 if ( !pColor && aLoadedColorName == aColorName )
1459                     eHackConversion = NF_CONVERT_NONE;
1460                 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM );
1461                 rScan.SetConvertMode( eOldTmpLang, eOldNewLang );
1462                 rScan.SetConvertMode( bOldConvert );
1463             }
1464         }
1465     }
1466     eOp1 = (SvNumberformatLimitOps) nOp1;
1467     eOp2 = (SvNumberformatLimitOps) nOp2;
1468     String aComment;        // wird nach dem NewCurrency-Geraffel richtig gesetzt
1469     if ( rHdr.BytesLeft() )
1470     {   // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
1471         SvNumberformat::LoadString( rStream, aComment );
1472         rStream >> nNewStandardDefined;
1473     }
1474 
1475     xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND;
1476     sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic &&
1477         (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND );
1478     sal_Bool bNewCurrencyLoaded = sal_False;
1479     sal_Bool bNewCurrency = sal_False;
1480 
1481     sal_Bool bGoOn = sal_True;
1482     while ( rHdr.BytesLeft() && bGoOn )
1483     {   // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1484         sal_uInt16 nId;
1485         rStream >> nId;
1486         switch ( nId )
1487         {
1488             case nNewCurrencyVersionId :
1489             {
1490                 bNewCurrencyLoaded = sal_True;
1491                 rStream >> bNewCurrency;
1492                 if ( bNewCurrency )
1493                 {
1494                     for ( sal_uInt16 j=0; j<4; j++ )
1495                     {
1496                         NumFor[j].LoadNewCurrencyMap( rStream );
1497                     }
1498                 }
1499             }
1500             break;
1501             case nNewStandardFlagVersionId :
1502                 rStream >> bStandard;   // the real standard flag
1503             break;
1504             default:
1505                 DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" );
1506                 bGoOn = sal_False;  // stop reading unknown stream left over of newer versions
1507                 // Would be nice to have multiple read/write headers instead
1508                 // but old versions wouldn't know it, TLOT.
1509         }
1510     }
1511     rHdr.EndEntry();
1512 
1513     if ( bNewCurrencyLoaded )
1514     {
1515         if ( bNewCurrency && bNewCurrencyComment )
1516         {   // original Formatstring und Kommentar wiederherstellen
1517             sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
1518             aComment.Erase( 0, nNewCurrencyEnd+1 );
1519         }
1520     }
1521     else if ( bNewCurrencyComment )
1522     {   // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert
1523         // original Formatstring und Kommentar wiederherstellen
1524         sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
1525         aComment.Erase( 0, nNewCurrencyEnd+1 );
1526         // Zustaende merken
1527         short nDefined = ( eType & NUMBERFORMAT_DEFINED );
1528         sal_uInt16 nNewStandard = nNewStandardDefined;
1529         // neu parsen etc.
1530         String aStr( sFormatstring );
1531         xub_StrLen nCheckPos = 0;
1532         SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc,
1533             nCheckPos, eLnge, bStandard );
1534         DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" );
1535         ImpCopyNumberformat( *pFormat );
1536         delete pFormat;
1537         // Zustaende wiederherstellen
1538         eType |= nDefined;
1539         if ( nNewStandard )
1540             SetNewStandardDefined( nNewStandard );
1541     }
1542     SetComment( aComment );
1543 
1544     if ( eHackConversion != NF_CONVERT_NONE )
1545     {   //! und weiter mit dem HACK!
1546         switch ( eHackConversion )
1547         {
1548             case NF_CONVERT_ENGLISH_GERMAN :
1549                 ConvertLanguage( *pHackConverter,
1550                     LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, sal_True );
1551             break;
1552             case NF_CONVERT_GERMAN_ENGLISH :
1553                 ConvertLanguage( *pHackConverter,
1554                     LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True );
1555             break;
1556             default:
1557                 DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" );
1558         }
1559     }
1560     return eHackConversion;
1561 }
1562 
1563 void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
1564         LanguageType eConvertFrom, LanguageType eConvertTo, sal_Bool bSystem )
1565 {
1566     xub_StrLen nCheckPos;
1567     sal_uInt32 nKey;
1568     short nType = eType;
1569     String aFormatString( sFormatstring );
1570     if ( bSystem )
1571         rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
1572             nKey, eConvertFrom, eConvertTo );
1573     else
1574         rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType,
1575             nKey, eConvertFrom, eConvertTo );
1576     const SvNumberformat* pFormat = rConverter.GetEntry( nKey );
1577     DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
1578     if ( pFormat )
1579     {
1580         ImpCopyNumberformat( *pFormat );
1581         // aus Formatter/Scanner uebernommene Werte zuruecksetzen
1582         if ( bSystem )
1583             eLnge = LANGUAGE_SYSTEM;
1584         // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner
1585         for ( sal_uInt16 i = 0; i < 4; i++ )
1586         {
1587             String aColorName = NumFor[i].GetColorName();
1588             Color* pColor = rScan.GetColor( aColorName );
1589             NumFor[i].SetColor( pColor, aColorName );
1590         }
1591     }
1592 }
1593 
1594 
1595 // static
1596 void SvNumberformat::LoadString( SvStream& rStream, String& rStr )
1597 {
1598     CharSet eStream = rStream.GetStreamCharSet();
1599     ByteString aStr;
1600     rStream.ReadByteString( aStr );
1601     sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream );
1602     if ( aStr.Search( cStream ) == STRING_NOTFOUND )
1603     {   // simple conversion to unicode
1604         rStr = UniString( aStr, eStream );
1605     }
1606     else
1607     {
1608         sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol();
1609         register const sal_Char* p = aStr.GetBuffer();
1610         register const sal_Char* const pEnd = p + aStr.Len();
1611         register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() );
1612         while ( p < pEnd )
1613         {
1614             if ( *p == cStream )
1615                 *pUni = cTarget;
1616             else
1617                 *pUni = ByteString::ConvertToUnicode( *p, eStream );
1618             p++;
1619             pUni++;
1620         }
1621         *pUni = 0;
1622     }
1623 }
1624 
1625 
1626 void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const
1627 {
1628     String aFormatstring( sFormatstring );
1629     String aComment( sComment );
1630 #if NF_COMMENT_IN_FORMATSTRING
1631     // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen
1632     // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung
1633     // (z.B. im Dialog) zu ermoeglichen
1634     SetComment( "", aFormatstring, aComment );
1635 #endif
1636 
1637     sal_Bool bNewCurrency = HasNewCurrency();
1638     if ( bNewCurrency )
1639     {   // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern
1640         aComment.Insert( cNewCurrencyMagic, 0 );
1641         aComment.Insert( cNewCurrencyMagic, 0 );
1642         aComment.Insert( aFormatstring, 1 );
1643         Build50Formatstring( aFormatstring );       // alten Formatstring generieren
1644     }
1645 
1646     // old SO5 versions do behave strange (no output) if standard flag is set
1647     // on formats not prepared for it (not having the following exact types)
1648     sal_Bool bOldStandard = bStandard;
1649     if ( bOldStandard )
1650     {
1651         switch ( eType )
1652         {
1653             case NUMBERFORMAT_NUMBER :
1654             case NUMBERFORMAT_DATE :
1655             case NUMBERFORMAT_TIME :
1656             case NUMBERFORMAT_DATETIME :
1657             case NUMBERFORMAT_PERCENT :
1658             case NUMBERFORMAT_SCIENTIFIC :
1659                 // ok to save
1660             break;
1661             default:
1662                 bOldStandard = sal_False;
1663         }
1664     }
1665 
1666     rHdr.StartEntry();
1667     rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() );
1668     rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2
1669             << bOldStandard << bIsUsed;
1670     for (sal_uInt16 i = 0; i < 4; i++)
1671         NumFor[i].Save(rStream);
1672     // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
1673     rStream.WriteByteString( aComment, rStream.GetStreamCharSet() );
1674     rStream << nNewStandardDefined;
1675     // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
1676     rStream << nNewCurrencyVersionId;
1677     rStream << bNewCurrency;
1678     if ( bNewCurrency )
1679     {
1680         for ( sal_uInt16 j=0; j<4; j++ )
1681         {
1682             NumFor[j].SaveNewCurrencyMap( rStream );
1683         }
1684     }
1685 
1686     // the real standard flag to load with versions >638 if different
1687     if ( bStandard != bOldStandard )
1688     {
1689         rStream << nNewStandardFlagVersionId;
1690         rStream << bStandard;
1691     }
1692 
1693     rHdr.EndEntry();
1694 }
1695 
1696 
1697 sal_Bool SvNumberformat::HasNewCurrency() const
1698 {
1699     for ( sal_uInt16 j=0; j<4; j++ )
1700     {
1701         if ( NumFor[j].HasNewCurrency() )
1702             return sal_True;
1703     }
1704     return sal_False;
1705 }
1706 
1707 
1708 sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol,
1709             String& rExtension ) const
1710 {
1711     for ( sal_uInt16 j=0; j<4; j++ )
1712     {
1713         if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
1714             return sal_True;
1715     }
1716     rSymbol.Erase();
1717     rExtension.Erase();
1718     return sal_False;
1719 }
1720 
1721 
1722 // static
1723 String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr,
1724             sal_Bool bQuoteSymbol )
1725 {
1726     String aTmp;
1727     xub_StrLen nStartPos, nPos, nLen;
1728     nLen = rStr.Len();
1729     nStartPos = 0;
1730     while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND )
1731     {
1732         xub_StrLen nEnd;
1733         if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen )
1734         {
1735             aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos );
1736             nStartPos = nEnd;
1737         }
1738         else
1739         {
1740             aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1741             nStartPos = nPos + 2;
1742             xub_StrLen nDash;
1743             nEnd = nStartPos - 1;
1744             do
1745             {
1746                 nDash = rStr.Search( '-', ++nEnd );
1747             } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen );
1748             xub_StrLen nClose;
1749             nEnd = nStartPos - 1;
1750             do
1751             {
1752                 nClose = rStr.Search( ']', ++nEnd );
1753             } while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen );
1754             nPos = ( nDash < nClose ? nDash : nClose );
1755             if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' )
1756                 aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1757             else
1758             {
1759                 aTmp += '"';
1760                 aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1761                 aTmp += '"';
1762             }
1763             nStartPos = nClose + 1;
1764         }
1765     }
1766     if ( nLen > nStartPos )
1767         aTmp += rStr.Copy( nStartPos, nLen - nStartPos );
1768     return aTmp;
1769 }
1770 
1771 
1772 void SvNumberformat::Build50Formatstring( String& rStr ) const
1773 {
1774     rStr = StripNewCurrencyDelimiters( sFormatstring, sal_True );
1775 }
1776 
1777 
1778 void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString)
1779 {
1780     sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
1781 
1782     if ( fabs(fNumber) > 1.0E15 )       // #58531# war E16
1783     {
1784         nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
1785         OutString = ::rtl::math::doubleToUString( fNumber,
1786                 rtl_math_StringFormat_E, nStandardPrec /*2*/,
1787                 GetFormatter().GetNumDecimalSep().GetChar(0));
1788     }
1789     else
1790         ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec);
1791 }
1792 
1793 void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const
1794 {
1795     // Make sure the precision doesn't go over the maximum allowable precision.
1796     nPrecision = ::std::min(UPPER_PRECISION, nPrecision);
1797 
1798 #if 0
1799 {
1800     // debugger test case for ANSI standard correctness
1801     ::rtl::OUString aTest;
1802     // expect 0.00123   OK
1803     aTest = ::rtl::math::doubleToUString( 0.001234567,
1804             rtl_math_StringFormat_G, 3, '.', sal_True );
1805     // expect 123       OK
1806     aTest = ::rtl::math::doubleToUString( 123.4567,
1807             rtl_math_StringFormat_G, 3, '.', sal_True );
1808     // expect 123.5     OK
1809     aTest = ::rtl::math::doubleToUString( 123.4567,
1810             rtl_math_StringFormat_G, 4, '.', sal_True );
1811     // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
1812     // 1000 with an exponent equal to significant digits)
1813     // Currently (24-Jan-2003) we do fail in this case and output 1000
1814     // instead, negligible.
1815     aTest = ::rtl::math::doubleToUString( 999.6,
1816             rtl_math_StringFormat_G, 3, '.', sal_True );
1817     // expect what? result is 1.2e+004
1818     aTest = ::rtl::math::doubleToUString( 12345.6789,
1819             rtl_math_StringFormat_G, -3, '.', sal_True );
1820 }
1821 #endif
1822 
1823     // We decided to strip trailing zeros unconditionally, since binary
1824     // double-precision rounding error makes it impossible to determine e.g.
1825     // whether 844.10000000000002273737 is what the user has typed, or the
1826     // user has typed 844.1 but IEEE 754 represents it that way internally.
1827 
1828     rOutString = ::rtl::math::doubleToUString( rNumber,
1829             rtl_math_StringFormat_F, nPrecision /*2*/,
1830             GetFormatter().GetNumDecimalSep().GetChar(0), true );
1831     if (rOutString.GetChar(0) == '-' &&
1832         rOutString.GetTokenCount('0') == rOutString.Len())
1833         rOutString.EraseLeadingChars('-');            // nicht -0
1834 
1835     ImpTransliterate( rOutString, NumFor[0].GetNatNum() );
1836 }
1837 
1838 void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
1839 {
1840     sal_Bool bModified = sal_False;
1841     if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
1842     {
1843         if (fNumber == 0.0)
1844         {
1845             OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) );
1846             return;
1847         }
1848         fNumber *= 100;
1849         bModified = sal_True;
1850     }
1851 
1852     if (fNumber == 0.0)
1853     {
1854         OutString = '0';
1855         return;
1856     }
1857 
1858     OutString = ::rtl::math::doubleToUString( fNumber,
1859             rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
1860             GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
1861 
1862     if ( eType & NUMBERFORMAT_PERCENT && bModified)
1863         OutString += '%';
1864     return;
1865 }
1866 
1867 short SvNumberformat::ImpCheckCondition(double& fNumber,
1868                                      double& fLimit,
1869                                      SvNumberformatLimitOps eOp)
1870 {
1871     switch(eOp)
1872     {
1873         case NUMBERFORMAT_OP_NO: return -1;
1874         case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit);
1875         case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit);
1876         case NUMBERFORMAT_OP_LT: return (short) (fNumber <  fLimit);
1877         case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit);
1878         case NUMBERFORMAT_OP_GT: return (short) (fNumber >  fLimit);
1879         case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit);
1880         default: return -1;
1881     }
1882 }
1883 
1884 sal_Bool SvNumberformat::GetOutputString(String& sString,
1885                                      String& OutString,
1886                                      Color** ppColor)
1887 {
1888     OutString.Erase();
1889     sal_uInt16 nIx;
1890     if (eType & NUMBERFORMAT_TEXT)
1891         nIx = 0;
1892     else if (NumFor[3].GetnAnz() > 0)
1893         nIx = 3;
1894     else
1895     {
1896         *ppColor = NULL;        // no change of color
1897         return sal_False;
1898     }
1899     *ppColor = NumFor[nIx].GetColor();
1900     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
1901     if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
1902     {
1903         sal_Bool bRes = sal_False;
1904         const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
1905         for (sal_uInt16 i = 0; i < nAnz; i++)
1906         {
1907             switch (rInfo.nTypeArray[i])
1908             {
1909                 case NF_SYMBOLTYPE_STAR:
1910                     if( bStarFlag )
1911                     {
1912                         OutString += (sal_Unicode) 0x1B;
1913                         OutString += rInfo.sStrArray[i].GetChar(1);
1914                         bRes = sal_True;
1915                     }
1916                 break;
1917                 case NF_SYMBOLTYPE_BLANK:
1918                     InsertBlanks( OutString, OutString.Len(),
1919                         rInfo.sStrArray[i].GetChar(1) );
1920                 break;
1921                 case NF_KEY_GENERAL :   // #77026# "General" is the same as "@"
1922                 case NF_SYMBOLTYPE_DEL :
1923                     OutString += sString;
1924                 break;
1925                 default:
1926                     OutString += rInfo.sStrArray[i];
1927             }
1928         }
1929         return bRes;
1930     }
1931     return sal_False;
1932 }
1933 /*
1934 void SvNumberformat::GetNextFareyNumber(sal_uLong nPrec, sal_uLong x0, sal_uLong x1,
1935                                         sal_uLong y0, sal_uLong y1,
1936                                         sal_uLong& x2,sal_uLong& y2)
1937 {
1938     x2 = ((y0+nPrec)/y1)*x1 - x0;
1939     y2 = ((y0+nPrec)/y1)*y1 - y0;
1940 }
1941 */
1942 sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y)
1943 {
1944     if (y == 0)
1945         return x;
1946     else
1947     {
1948         sal_uLong z = x%y;
1949         while (z)
1950         {
1951             x = y;
1952             y = z;
1953             z = x%y;
1954         }
1955         return y;
1956     }
1957 }
1958 
1959 sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y)
1960 {
1961     if (y == 0)
1962         return x;
1963     else
1964     {
1965         sal_uLong z = x%y;
1966         while ((double)z/(double)y > D_EPS)
1967         {
1968             x = y;
1969             y = z;
1970             z = x%y;
1971         }
1972         return y;
1973     }
1974 }
1975 
1976 namespace {
1977 
1978 void lcl_GetOutputStringScientific(
1979     double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString)
1980 {
1981     bool bSign = ::rtl::math::isSignBitSet(fNumber);
1982 
1983     // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7).
1984     sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0;
1985     if (nPrec && bSign)
1986         // Make room for the negative sign.
1987         --nPrec;
1988 
1989     nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals.
1990 
1991     rOutString = ::rtl::math::doubleToUString(
1992         fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0));
1993 }
1994 
1995 }
1996 
1997 bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const
1998 {
1999     using namespace std;
2000 
2001     if (eType != NUMBERFORMAT_NUMBER)
2002         return false;
2003 
2004     double fTestNum = fNumber;
2005     bool bSign = ::rtl::math::isSignBitSet(fTestNum);
2006     if (bSign)
2007         fTestNum = -fTestNum;
2008 
2009     if (fTestNum < EXP_LOWER_BOUND)
2010     {
2011         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2012         return true;
2013     }
2014 
2015     double fExp = log10(fTestNum);
2016     // Values < 1.0 always have one digit before the decimal point.
2017     sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1;
2018 
2019     if (nDigitPre > 15)
2020     {
2021         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2022         return true;
2023     }
2024 
2025     sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0;
2026     if (nPrec && bSign)
2027         // Subtract the negative sign.
2028         --nPrec;
2029     if (nPrec)
2030         // Subtract the decimal point.
2031         --nPrec;
2032 
2033     ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec);
2034     if (rOutString.Len() > nCharCount)
2035         // String still wider than desired.  Switch to scientific notation.
2036         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2037 
2038     return true;
2039 }
2040 
2041 sal_Bool SvNumberformat::GetOutputString(double fNumber,
2042                                      String& OutString,
2043                                      Color** ppColor)
2044 {
2045     sal_Bool bRes = sal_False;
2046     OutString.Erase();                          // alles loeschen
2047     *ppColor = NULL;                            // keine Farbaenderung
2048     if (eType & NUMBERFORMAT_LOGICAL)
2049     {
2050         if (fNumber)
2051             OutString = rScan.GetTrueString();
2052         else
2053             OutString = rScan.GetFalseString();
2054         return sal_False;
2055     }
2056     if (eType & NUMBERFORMAT_TEXT)
2057     {
2058         ImpGetOutputStandard(fNumber, OutString);
2059         return sal_False;
2060     }
2061     sal_Bool bHadStandard = sal_False;
2062     if (bStandard)                              // einzelne Standardformate
2063     {
2064         if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION)     // alle Zahlformate InputLine
2065         {
2066             ImpGetOutputInputLine(fNumber, OutString);
2067             return false;
2068         }
2069         switch (eType)
2070         {
2071             case NUMBERFORMAT_NUMBER:                   // Standardzahlformat
2072             {
2073                 if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION)
2074                 {
2075                     bool bSign = ::rtl::math::isSignBitSet(fNumber);
2076                     if (bSign)
2077                         fNumber = -fNumber;
2078                     ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format.
2079                     if (fNumber < EXP_LOWER_BOUND)
2080                     {
2081                         xub_StrLen nLen = OutString.Len();
2082                         if (!nLen)
2083                             return false;
2084 
2085                         // #i112250# With the 10-decimal limit, small numbers are formatted as "0".
2086                         // Switch to scientific in that case, too:
2087                         if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0))
2088                         {
2089                             sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
2090                             nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
2091                             OutString = ::rtl::math::doubleToUString( fNumber,
2092                                     rtl_math_StringFormat_E, nStandardPrec /*2*/,
2093                                     GetFormatter().GetNumDecimalSep().GetChar(0), true);
2094                         }
2095                     }
2096                     if (bSign)
2097                         OutString.Insert('-', 0);
2098                     return false;
2099                 }
2100                 ImpGetOutputStandard(fNumber, OutString);
2101                 bHadStandard = sal_True;
2102             }
2103             break;
2104             case NUMBERFORMAT_DATE:
2105                 bRes |= ImpGetDateOutput(fNumber, 0, OutString);
2106                 bHadStandard = sal_True;
2107             break;
2108             case NUMBERFORMAT_TIME:
2109                 bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
2110                 bHadStandard = sal_True;
2111             break;
2112             case NUMBERFORMAT_DATETIME:
2113                 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
2114                 bHadStandard = sal_True;
2115             break;
2116         }
2117     }
2118     if ( !bHadStandard )
2119     {
2120         sal_uInt16 nIx;                             // Index des Teilformats
2121         short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
2122         if (nCheck == -1 || nCheck == 1)            // nur 1 String oder True
2123             nIx = 0;
2124         else
2125         {
2126             nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
2127             if (nCheck == -1 || nCheck == 1)
2128                 nIx = 1;
2129             else
2130                 nIx = 2;
2131         }
2132         if (nIx == 1 && fNumber < 0.0 &&        // negatives Format
2133                 IsNegativeRealNegative() )      // ohne Vorzeichen
2134             fNumber = -fNumber;                 // Vorzeichen eliminieren
2135         *ppColor = NumFor[nIx].GetColor();
2136         const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2137         const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
2138         if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
2139             return sal_False;                       // leer => nichts
2140         else if (nAnz == 0)                     // sonst Standard-Format
2141         {
2142             ImpGetOutputStandard(fNumber, OutString);
2143             return sal_False;
2144         }
2145         switch (rInfo.eScannedType)
2146         {
2147             case NUMBERFORMAT_TEXT:
2148             case NUMBERFORMAT_DEFINED:
2149             {
2150                 for (sal_uInt16 i = 0; i < nAnz; i++)
2151                 {
2152                     switch (rInfo.nTypeArray[i])
2153                     {
2154                         case NF_SYMBOLTYPE_STAR:
2155                             if( bStarFlag )
2156                             {
2157                                 OutString += (sal_Unicode) 0x1B;
2158                                 OutString += rInfo.sStrArray[i].GetChar(1);
2159                                 bRes = sal_True;
2160                             }
2161                             break;
2162                         case NF_SYMBOLTYPE_BLANK:
2163                             InsertBlanks( OutString, OutString.Len(),
2164                                 rInfo.sStrArray[i].GetChar(1) );
2165                             break;
2166                         case NF_SYMBOLTYPE_STRING:
2167                         case NF_SYMBOLTYPE_CURRENCY:
2168                             OutString += rInfo.sStrArray[i];
2169                             break;
2170                         case NF_SYMBOLTYPE_THSEP:
2171                             if (rInfo.nThousand == 0)
2172                                 OutString += rInfo.sStrArray[i];
2173                         break;
2174                         default:
2175                         break;
2176                     }
2177                 }
2178             }
2179             break;
2180             case NUMBERFORMAT_DATE:
2181                 bRes |= ImpGetDateOutput(fNumber, nIx, OutString);
2182             break;
2183             case NUMBERFORMAT_TIME:
2184                 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString);
2185             break;
2186             case NUMBERFORMAT_DATETIME:
2187                 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString);
2188             break;
2189             case NUMBERFORMAT_NUMBER:
2190             case NUMBERFORMAT_PERCENT:
2191             case NUMBERFORMAT_CURRENCY:
2192                 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString);
2193             break;
2194             case NUMBERFORMAT_FRACTION:
2195             {
2196                 String sStr, sFrac, sDiv;               // Strings, Wert fuer
2197                 sal_uLong nFrac, nDiv;                      // Vorkommaanteil
2198                                                         // Zaehler und Nenner
2199                 sal_Bool bSign = sal_False;
2200                 if (fNumber < 0)
2201                 {
2202                     if (nIx == 0)                       // nicht in hinteren
2203                         bSign = sal_True;                   // Formaten
2204                     fNumber = -fNumber;
2205                 }
2206                 double fNum = floor(fNumber);           // Vorkommateil
2207                 fNumber -= fNum;                        // Nachkommateil
2208                 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9)
2209                                                         // zu gross
2210                 {
2211                     OutString = rScan.GetErrorString();
2212                     return sal_False;
2213                 }
2214                 if (rInfo.nCntExp == 0)
2215                 {
2216                     DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
2217                     return sal_False;
2218                 }
2219                 sal_uLong nBasis = ((sal_uLong)floor(           // 9, 99, 999 ,...
2220                                     pow(10.0,rInfo.nCntExp))) - 1;
2221                 sal_uLong x0, y0, x1, y1;
2222 
2223                 if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
2224                 {
2225                     sal_Bool bUpperHalf;
2226                     if (fNumber > 0.5)
2227                     {
2228                         bUpperHalf = sal_True;
2229                         fNumber -= (fNumber - 0.5) * 2.0;
2230                     }
2231                     else
2232                         bUpperHalf = sal_False;
2233                                                     // Einstieg in Farey-Serie
2234                                                     // finden:
2235                     x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9
2236                     if (x0 == 0)                        //      => x0 = 2
2237                     {
2238                         y0 = 1;
2239                         x1 = 1;
2240                         y1 = nBasis;
2241                     }
2242                     else if (x0 == (nBasis-1)/2)    // (b-1)/2, 1/2
2243                     {                               // geht (nBasis ungerade)
2244                         y0 = nBasis;
2245                         x1 = 1;
2246                         y1 = 2;
2247                     }
2248                     else if (x0 == 1)
2249                     {
2250                         y0 = nBasis;                    //  1/n; 1/(n-1)
2251                         x1 = 1;
2252                         y1 = nBasis - 1;
2253                     }
2254                     else
2255                     {
2256                         y0 = nBasis;                    // z.B. 2/9   2/8
2257                         x1 = x0;
2258                         y1 = nBasis - 1;
2259                         double fUg = (double) x0 / (double) y0;
2260                         double fOg = (double) x1 / (double) y1;
2261                         sal_uLong nGgt = ImpGGT(y0, x0);       // x0/y0 kuerzen
2262                         x0 /= nGgt;
2263                         y0 /= nGgt;                     // Einschachteln:
2264                         sal_uLong x2 = 0;
2265                         sal_uLong y2 = 0;
2266                         sal_Bool bStop = sal_False;
2267                         while (!bStop)
2268                         {
2269 #ifdef GCC
2270                             // #i21648# GCC over-optimizes something resulting
2271                             // in wrong fTest values throughout the loops.
2272                             volatile
2273 #endif
2274                                 double fTest = (double)x1/(double)y1;
2275                             while (!bStop)
2276                             {
2277                                 while (fTest > fOg)
2278                                 {
2279                                     x1--;
2280                                     fTest = (double)x1/(double)y1;
2281                                 }
2282                                 while (fTest < fUg && y1 > 1)
2283                                 {
2284                                     y1--;
2285                                     fTest = (double)x1/(double)y1;
2286                                 }
2287                                 if (fTest <= fOg)
2288                                 {
2289                                     fOg = fTest;
2290                                     bStop = sal_True;
2291                                 }
2292                                 else if (y1 == 1)
2293                                     bStop = sal_True;
2294                             }                               // of while
2295                             nGgt = ImpGGT(y1, x1);             // x1/y1 kuerzen
2296                             x2 = x1 / nGgt;
2297                             y2 = y1 / nGgt;
2298                             if (x2*y0 - x0*y2 == 1 || y1 <= 1)  // Test, ob x2/y2
2299                                 bStop = sal_True;               // naechste Farey-Zahl
2300                             else
2301                             {
2302                                 y1--;
2303                                 bStop = sal_False;
2304                             }
2305                         }                                   // of while
2306                         x1 = x2;
2307                         y1 = y2;
2308                     }                                       // of else
2309                     double fup, flow;
2310                     flow = (double)x0/(double)y0;
2311                     fup  = (double)x1/(double)y1;
2312                     while (fNumber > fup)
2313                     {
2314                         sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
2315                         sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0;
2316 //                      GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
2317                         x0 = x1;
2318                         y0 = y1;
2319                         x1 = x2;
2320                         y1 = y2;
2321                         flow = fup;
2322                         fup  = (double)x1/(double)y1;
2323                     }
2324                     if (fNumber - flow < fup - fNumber)
2325                     {
2326                         nFrac = x0;
2327                         nDiv  = y0;
2328                     }
2329                     else
2330                     {
2331                         nFrac = x1;
2332                         nDiv  = y1;
2333                     }
2334                     if (bUpperHalf)                     // Original restaur.
2335                     {
2336                         if (nFrac == 0 && nDiv == 1)    // 1/1
2337                             fNum += 1.0;
2338                         else
2339                             nFrac = nDiv - nFrac;
2340                     }
2341                 }
2342                 else                                    // grosse Nenner
2343                 {                                       // 0,1234->123/1000
2344                     sal_uLong nGgt;
2345 /*
2346                     nDiv = nBasis+1;
2347                     nFrac = ((sal_uLong)floor(0.5 + fNumber *
2348                                     pow(10.0,rInfo.nCntExp)));
2349 */
2350                     nDiv = 10000000;
2351                     nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0));
2352                     nGgt = ImpGGT(nDiv, nFrac);
2353                     if (nGgt > 1)
2354                     {
2355                         nDiv  /= nGgt;
2356                         nFrac /= nGgt;
2357                     }
2358                     if (nDiv > nBasis)
2359                     {
2360                         nGgt = ImpGGTRound(nDiv, nFrac);
2361                         if (nGgt > 1)
2362                         {
2363                             nDiv  /= nGgt;
2364                             nFrac /= nGgt;
2365                         }
2366                     }
2367                     if (nDiv > nBasis)
2368                     {
2369                         nDiv = nBasis;
2370                         nFrac = ((sal_uLong)floor(0.5 + fNumber *
2371                                     pow(10.0,rInfo.nCntExp)));
2372                         nGgt = ImpGGTRound(nDiv, nFrac);
2373                         if (nGgt > 1)
2374                         {
2375                             nDiv  /= nGgt;
2376                             nFrac /= nGgt;
2377                         }
2378                     }
2379                 }
2380 
2381                 if (rInfo.nCntPre == 0)    // unechter Bruch
2382                 {
2383                     double fNum1 = fNum * (double)nDiv + (double)nFrac;
2384                     if (fNum1 > _D_MAX_U_LONG_)
2385                     {
2386                         OutString = rScan.GetErrorString();
2387                         return sal_False;
2388                     }
2389                     nFrac = (sal_uLong) floor(fNum1);
2390                     sStr.Erase();
2391                 }
2392                 else if (fNum == 0.0 && nFrac != 0)
2393                     sStr.Erase();
2394                 else
2395                 {
2396                     char aBuf[100];
2397                     sprintf( aBuf, "%.f", fNum );   // simple rounded integer (#100211# - checked)
2398                     sStr.AssignAscii( aBuf );
2399                     ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
2400                 }
2401                 if (rInfo.nCntPre > 0 && nFrac == 0)
2402                 {
2403                     sFrac.Erase();
2404                     sDiv.Erase();
2405                 }
2406                 else
2407                 {
2408                     sFrac = ImpIntToString( nIx, nFrac );
2409                     sDiv = ImpIntToString( nIx, nDiv );
2410                 }
2411 
2412                 sal_uInt16 j = nAnz-1;                  // letztes Symbol->rueckw.
2413                 xub_StrLen k;                       // Nenner:
2414                 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
2415                 sal_Bool bCont = sal_True;
2416                 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
2417                 {
2418                     if (rInfo.nCntPre > 0 && nFrac == 0)
2419                         sDiv.Insert(' ',0);
2420                     else
2421                         sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 );
2422                     if ( j )
2423                         j--;
2424                     else
2425                         bCont = sal_False;
2426                 }
2427                                                     // weiter Zaehler:
2428                 if ( !bCont )
2429                     sFrac.Erase();
2430                 else
2431                 {
2432                     bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
2433                     if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
2434                     {
2435                         sFrac.Insert(rInfo.sStrArray[j],0);
2436                         if ( j )
2437                             j--;
2438                         else
2439                             bCont = sal_False;
2440                     }
2441                 }
2442                                                     // weiter Hauptzahl
2443                 if ( !bCont )
2444                     sStr.Erase();
2445                 else
2446                 {
2447                     k = sStr.Len();                 // hinter letzter Ziffer
2448                     bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
2449                                             rInfo.nCntPre);
2450                 }
2451                 if (bSign && !(nFrac == 0 && fNum == 0.0))
2452                     OutString.Insert('-',0);        // nicht -0
2453                 OutString += sStr;
2454                 OutString += sFrac;
2455                 OutString += sDiv;
2456             }
2457             break;
2458             case NUMBERFORMAT_SCIENTIFIC:
2459             {
2460                 sal_Bool bSign = sal_False;
2461                 if (fNumber < 0)
2462                 {
2463                     if (nIx == 0)                       // nicht in hinteren
2464                         bSign = sal_True;                   // Formaten
2465                     fNumber = -fNumber;
2466                 }
2467                 String sStr( ::rtl::math::doubleToUString( fNumber,
2468                             rtl_math_StringFormat_E,
2469                             rInfo.nCntPre + rInfo.nCntPost - 1, '.' ));
2470 
2471                 String ExpStr;
2472                 short nExpSign = 1;
2473                 xub_StrLen nExPos = sStr.Search('E');
2474                 if ( nExPos != STRING_NOTFOUND )
2475                 {
2476                     // split into mantisse and exponent and get rid of "E+" or "E-"
2477                     xub_StrLen nExpStart = nExPos + 1;
2478                     switch ( sStr.GetChar( nExpStart ) )
2479                     {
2480                         case '-' :
2481                             nExpSign = -1;
2482                             // fallthru
2483                         case '+' :
2484                             ++nExpStart;
2485                         break;
2486                     }
2487                     ExpStr = sStr.Copy( nExpStart );    // part following the "E+"
2488                     sStr.Erase( nExPos );
2489                     sStr.EraseAllChars('.');        // cut any decimal delimiter
2490                     if ( rInfo.nCntPre != 1 )       // rescale Exp
2491                     {
2492                         sal_Int32 nExp = ExpStr.ToInt32() * nExpSign;
2493                         nExp -= sal_Int32(rInfo.nCntPre)-1;
2494                         if ( nExp < 0 )
2495                         {
2496                             nExpSign = -1;
2497                             nExp = -nExp;
2498                         }
2499                         else
2500                             nExpSign = 1;
2501                         ExpStr = String::CreateFromInt32( nExp );
2502                     }
2503                 }
2504                 sal_uInt16 j = nAnz-1;                  // last symbol
2505                 xub_StrLen k;                       // position in ExpStr
2506                 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
2507 
2508                 xub_StrLen nZeros = 0;              // erase leading zeros
2509                 while (nZeros < k && ExpStr.GetChar(nZeros) == '0')
2510                     ++nZeros;
2511                 if (nZeros)
2512                     ExpStr.Erase( 0, nZeros);
2513 
2514                 sal_Bool bCont = sal_True;
2515                 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
2516                 {
2517                     const String& rStr = rInfo.sStrArray[j];
2518                     if (nExpSign == -1)
2519                         ExpStr.Insert('-',0);
2520                     else if (rStr.Len() > 1 && rStr.GetChar(1) == '+')
2521                         ExpStr.Insert('+',0);
2522                     ExpStr.Insert(rStr.GetChar(0),0);
2523                     if ( j )
2524                         j--;
2525                     else
2526                         bCont = sal_False;
2527                 }
2528                                                     // weiter Hauptzahl:
2529                 if ( !bCont )
2530                     sStr.Erase();
2531                 else
2532                 {
2533                     k = sStr.Len();                 // hinter letzter Ziffer
2534                     bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx,
2535                                             rInfo.nCntPre +
2536                                             rInfo.nCntPost);
2537                 }
2538                 if (bSign)
2539                     sStr.Insert('-',0);
2540                 OutString = sStr;
2541                 OutString += ExpStr;
2542             }
2543             break;
2544         }
2545     }
2546     return bRes;
2547 }
2548 
2549 sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber,
2550                                    sal_uInt16 nIx,
2551                                    String& OutString)
2552 {
2553     using namespace ::com::sun::star::i18n;
2554     sal_Bool bCalendarSet = sal_False;
2555     double fNumberOrig = fNumber;
2556     sal_Bool bRes = sal_False;
2557     sal_Bool bSign = sal_False;
2558     if (fNumber < 0.0)
2559     {
2560         fNumber = -fNumber;
2561         if (nIx == 0)
2562             bSign = sal_True;
2563     }
2564     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2565     if (rInfo.bThousand)       // []-Format
2566     {
2567         if (fNumber > 1.0E10)               // zu gross
2568         {
2569             OutString = rScan.GetErrorString();
2570             return sal_False;
2571         }
2572     }
2573     else
2574         fNumber -= floor(fNumber);          // sonst Datum abtrennen
2575     sal_Bool bInputLine;
2576     xub_StrLen nCntPost;
2577     if ( rScan.GetStandardPrec() == 300 &&
2578             0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
2579     {   // round at 7 decimals (+5 of 86400 == 12 significant digits)
2580         bInputLine = sal_True;
2581         nCntPost = 7;
2582     }
2583     else
2584     {
2585         bInputLine = sal_False;
2586         nCntPost = xub_StrLen(rInfo.nCntPost);
2587     }
2588     if (bSign && !rInfo.bThousand)     // kein []-Format
2589         fNumber = 1.0 - fNumber;        // "Kehrwert"
2590     double fTime = fNumber * 86400.0;
2591     fTime = ::rtl::math::round( fTime, int(nCntPost) );
2592     if (bSign && fTime == 0.0)
2593         bSign = sal_False;                      // nicht -00:00:00
2594 
2595     if( floor( fTime ) > _D_MAX_U_LONG_ )
2596     {
2597         OutString = rScan.GetErrorString();
2598         return sal_False;
2599     }
2600     sal_uLong nSeconds = (sal_uLong)floor( fTime );
2601 
2602     String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
2603                 rtl_math_StringFormat_F, int(nCntPost), '.'));
2604     sSecStr.EraseLeadingChars('0');
2605     sSecStr.EraseLeadingChars('.');
2606     if ( bInputLine )
2607     {
2608         sSecStr.EraseTrailingChars('0');
2609         if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
2610             sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
2611         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2612         nCntPost = sSecStr.Len();
2613     }
2614     else
2615         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2616 
2617     xub_StrLen nSecPos = 0;                 // Zum Ziffernweisen
2618                                             // abarbeiten
2619     sal_uLong nHour, nMin, nSec;
2620     if (!rInfo.bThousand)      // kein [] Format
2621     {
2622         nHour = (nSeconds/3600) % 24;
2623         nMin = (nSeconds%3600) / 60;
2624         nSec = nSeconds%60;
2625     }
2626     else if (rInfo.nThousand == 3) // [ss]
2627     {
2628         nHour = 0;
2629         nMin = 0;
2630         nSec = nSeconds;
2631     }
2632     else if (rInfo.nThousand == 2) // [mm]:ss
2633     {
2634         nHour = 0;
2635         nMin = nSeconds / 60;
2636         nSec = nSeconds % 60;
2637     }
2638     else if (rInfo.nThousand == 1) // [hh]:mm:ss
2639     {
2640         nHour = nSeconds / 3600;
2641         nMin = (nSeconds%3600) / 60;
2642         nSec = nSeconds%60;
2643     }
2644 	else {
2645 		// TODO  What should these be set to?
2646 		nHour = 0;
2647 		nMin  = 0;
2648 		nSec  = 0;
2649 	}
2650 
2651     sal_Unicode cAmPm = ' ';                   // a oder p
2652     if (rInfo.nCntExp)     // AM/PM
2653     {
2654         if (nHour == 0)
2655         {
2656             nHour = 12;
2657             cAmPm = 'a';
2658         }
2659         else if (nHour < 12)
2660             cAmPm = 'a';
2661         else
2662         {
2663             cAmPm = 'p';
2664             if (nHour > 12)
2665                 nHour -= 12;
2666         }
2667     }
2668     const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
2669     for (sal_uInt16 i = 0; i < nAnz; i++)
2670     {
2671         switch (rInfo.nTypeArray[i])
2672         {
2673             case NF_SYMBOLTYPE_STAR:
2674                 if( bStarFlag )
2675                 {
2676                     OutString += (sal_Unicode) 0x1B;
2677                     OutString += rInfo.sStrArray[i].GetChar(1);
2678                     bRes = sal_True;
2679                 }
2680                 break;
2681             case NF_SYMBOLTYPE_BLANK:
2682                 InsertBlanks( OutString, OutString.Len(),
2683                     rInfo.sStrArray[i].GetChar(1) );
2684                 break;
2685             case NF_SYMBOLTYPE_STRING:
2686             case NF_SYMBOLTYPE_CURRENCY:
2687             case NF_SYMBOLTYPE_DATESEP:
2688             case NF_SYMBOLTYPE_TIMESEP:
2689             case NF_SYMBOLTYPE_TIME100SECSEP:
2690                 OutString += rInfo.sStrArray[i];
2691                 break;
2692             case NF_SYMBOLTYPE_DIGIT:
2693             {
2694                 xub_StrLen nLen = ( bInputLine && i > 0 &&
2695                     (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
2696                      rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
2697                     nCntPost : rInfo.sStrArray[i].Len() );
2698                 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
2699                 {
2700                     OutString += sSecStr.GetChar(nSecPos);
2701                     nSecPos++;
2702                 }
2703             }
2704             break;
2705             case NF_KEY_AMPM:               // AM/PM
2706             {
2707                 if ( !bCalendarSet )
2708                 {
2709                     double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
2710                     fDiff += fNumberOrig;
2711                     GetCal().setLocalDateTime( fDiff );
2712                     bCalendarSet = sal_True;
2713                 }
2714                 if (cAmPm == 'a')
2715                     OutString += GetCal().getDisplayName(
2716                         CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 );
2717                 else
2718                     OutString += GetCal().getDisplayName(
2719                         CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 );
2720             }
2721             break;
2722             case NF_KEY_AP:                 // A/P
2723             {
2724                 if (cAmPm == 'a')
2725                     OutString += 'a';
2726                 else
2727                     OutString += 'p';
2728             }
2729             break;
2730             case NF_KEY_MI:                 // M
2731                 OutString += ImpIntToString( nIx, nMin );
2732             break;
2733             case NF_KEY_MMI:                // MM
2734                 OutString += ImpIntToString( nIx, nMin, 2 );
2735             break;
2736             case NF_KEY_H:                  // H
2737                 OutString += ImpIntToString( nIx, nHour );
2738             break;
2739             case NF_KEY_HH:                 // HH
2740                 OutString += ImpIntToString( nIx, nHour, 2 );
2741             break;
2742             case NF_KEY_S:                  // S
2743                 OutString += ImpIntToString( nIx, nSec );
2744             break;
2745             case NF_KEY_SS:                 // SS
2746                 OutString += ImpIntToString( nIx, nSec, 2 );
2747             break;
2748             default:
2749             break;
2750         }
2751     }
2752     if (bSign && rInfo.bThousand)
2753         OutString.Insert('-',0);
2754     return bRes;
2755 }
2756 
2757 
2758 sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
2759 {
2760     if ( GetCal().getUniqueID() != Gregorian::get() )
2761         return sal_False;
2762     const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2763     const sal_uInt16 nAnz = rNumFor.GetnAnz();
2764     sal_uInt16 i;
2765     for ( i = 0; i < nAnz; i++ )
2766     {
2767         switch ( rInfo.nTypeArray[i] )
2768         {
2769             case NF_SYMBOLTYPE_CALENDAR :
2770                 return sal_False;
2771             case NF_KEY_EC :
2772             case NF_KEY_EEC :
2773             case NF_KEY_R :
2774             case NF_KEY_RR :
2775             case NF_KEY_AAA :
2776             case NF_KEY_AAAA :
2777                 return sal_True;
2778         }
2779     }
2780     return sal_False;
2781 }
2782 
2783 
2784 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar,
2785         double& fOrgDateTime ) const
2786 {
2787     CalendarWrapper& rCal = GetCal();
2788     const rtl::OUString &rGregorian = Gregorian::get();
2789     if ( rCal.getUniqueID() == rGregorian )
2790     {
2791         using namespace ::com::sun::star::i18n;
2792         ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals
2793             = rCal.getAllCalendars( rLoc().getLocale() );
2794         sal_Int32 nCnt = xCals.getLength();
2795         if ( nCnt > 1 )
2796         {
2797             for ( sal_Int32 j=0; j < nCnt; j++ )
2798             {
2799                 if ( xCals[j] != rGregorian )
2800                 {
2801                     if ( !rOrgCalendar.Len() )
2802                     {
2803                         rOrgCalendar = rCal.getUniqueID();
2804                         fOrgDateTime = rCal.getDateTime();
2805                     }
2806                     rCal.loadCalendar( xCals[j], rLoc().getLocale() );
2807                     rCal.setDateTime( fOrgDateTime );
2808                     break;  // for
2809                 }
2810             }
2811         }
2812     }
2813 }
2814 
2815 
2816 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar,
2817         double fOrgDateTime ) const
2818 {
2819     CalendarWrapper& rCal = GetCal();
2820     const rtl::OUString &rGregorian = Gregorian::get();
2821     if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian )
2822     {
2823         rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2824         rCal.setDateTime( fOrgDateTime );
2825     }
2826 }
2827 
2828 
2829 sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime )
2830 {
2831     using namespace ::com::sun::star::i18n;
2832     CalendarWrapper& rCal = GetCal();
2833     const rtl::OUString &rGregorian = Gregorian::get();
2834     if ( rCal.getUniqueID() != rGregorian )
2835     {
2836         sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2837         if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL(
2838                 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
2839         {
2840             if ( !rOrgCalendar.Len() )
2841             {
2842                 rOrgCalendar = rCal.getUniqueID();
2843                 fOrgDateTime = rCal.getDateTime();
2844             }
2845             else if ( rOrgCalendar == String(rGregorian) )
2846                 rOrgCalendar.Erase();
2847             rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2848             rCal.setDateTime( fOrgDateTime );
2849             return sal_True;
2850         }
2851     }
2852     return sal_False;
2853 }
2854 
2855 
2856 sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
2857         double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
2858 {
2859     const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2860     const sal_uInt16 nAnz = rNumFor.GetnAnz();
2861     for ( sal_uInt16 i = 0; i < nAnz; i++ )
2862     {
2863         if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
2864         {
2865             CalendarWrapper& rCal = GetCal();
2866             if ( !rOrgCalendar.Len() )
2867             {
2868                 rOrgCalendar = rCal.getUniqueID();
2869                 fOrgDateTime = rCal.getDateTime();
2870             }
2871             rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2872             rCal.setDateTime( fOrgDateTime );
2873             return sal_True;
2874         }
2875     }
2876     return sal_False;
2877 }
2878 
2879 
2880 // static
2881 void SvNumberformat::ImpAppendEraG( String& OutString,
2882         const CalendarWrapper& rCal, sal_Int16 nNatNum )
2883 {
2884     using namespace ::com::sun::star::i18n;
2885     if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
2886     {
2887         sal_Unicode cEra;
2888         sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2889         switch ( nVal )
2890         {
2891             case 1 :    cEra = 'M'; break;
2892             case 2 :    cEra = 'T'; break;
2893             case 3 :    cEra = 'S'; break;
2894             case 4 :    cEra = 'H'; break;
2895             default:
2896                 cEra = '?';
2897         }
2898         OutString += cEra;
2899     }
2900     else
2901         OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum );
2902 }
2903 
2904 
2905 sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber,
2906                                    sal_uInt16 nIx,
2907                                    String& OutString)
2908 {
2909     using namespace ::com::sun::star::i18n;
2910     sal_Bool bRes = sal_False;
2911     CalendarWrapper& rCal = GetCal();
2912     double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
2913     fNumber += fDiff;
2914     rCal.setLocalDateTime( fNumber );
2915     String aOrgCalendar;        // empty => not changed yet
2916     double fOrgDateTime;
2917     sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
2918     if ( bOtherCalendar )
2919         SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2920     if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
2921         bOtherCalendar = sal_False;
2922     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2923     const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
2924     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
2925     for (sal_uInt16 i = 0; i < nAnz; i++)
2926     {
2927         switch (rInfo.nTypeArray[i])
2928         {
2929             case NF_SYMBOLTYPE_CALENDAR :
2930                 if ( !aOrgCalendar.Len() )
2931                 {
2932                     aOrgCalendar = rCal.getUniqueID();
2933                     fOrgDateTime = rCal.getDateTime();
2934                 }
2935                 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2936                 rCal.setDateTime( fOrgDateTime );
2937                 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2938             break;
2939             case NF_SYMBOLTYPE_STAR:
2940                 if( bStarFlag )
2941                 {
2942                     OutString += (sal_Unicode) 0x1B;
2943                     OutString += rInfo.sStrArray[i].GetChar(1);
2944                     bRes = sal_True;
2945                 }
2946             break;
2947             case NF_SYMBOLTYPE_BLANK:
2948                 InsertBlanks( OutString, OutString.Len(),
2949                     rInfo.sStrArray[i].GetChar(1) );
2950             break;
2951             case NF_SYMBOLTYPE_STRING:
2952             case NF_SYMBOLTYPE_CURRENCY:
2953             case NF_SYMBOLTYPE_DATESEP:
2954             case NF_SYMBOLTYPE_TIMESEP:
2955             case NF_SYMBOLTYPE_TIME100SECSEP:
2956                 OutString += rInfo.sStrArray[i];
2957             break;
2958             case NF_KEY_M:                  // M
2959                 OutString += rCal.getDisplayString(
2960                         CalendarDisplayCode::SHORT_MONTH, nNatNum );
2961             break;
2962             case NF_KEY_MM:                 // MM
2963                 OutString += rCal.getDisplayString(
2964                         CalendarDisplayCode::LONG_MONTH, nNatNum );
2965             break;
2966             case NF_KEY_MMM:                // MMM
2967                 OutString += rCal.getDisplayString(
2968                         CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
2969             break;
2970             case NF_KEY_MMMM:               // MMMM
2971                 OutString += rCal.getDisplayString(
2972                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
2973             break;
2974             case NF_KEY_MMMMM:              // MMMMM
2975                 OutString += rCal.getDisplayString(
2976                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
2977             break;
2978             case NF_KEY_Q:                  // Q
2979                 OutString += rCal.getDisplayString(
2980                         CalendarDisplayCode::SHORT_QUARTER, nNatNum );
2981             break;
2982             case NF_KEY_QQ:                 // QQ
2983                 OutString += rCal.getDisplayString(
2984                         CalendarDisplayCode::LONG_QUARTER, nNatNum );
2985             break;
2986             case NF_KEY_D:                  // D
2987                 OutString += rCal.getDisplayString(
2988                         CalendarDisplayCode::SHORT_DAY, nNatNum );
2989             break;
2990             case NF_KEY_DD:                 // DD
2991                 OutString += rCal.getDisplayString(
2992                         CalendarDisplayCode::LONG_DAY, nNatNum );
2993             break;
2994             case NF_KEY_DDD:                // DDD
2995             {
2996                 if ( bOtherCalendar )
2997                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2998                 OutString += rCal.getDisplayString(
2999                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3000                 if ( bOtherCalendar )
3001                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3002             }
3003             break;
3004             case NF_KEY_DDDD:               // DDDD
3005             {
3006                 if ( bOtherCalendar )
3007                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3008                 OutString += rCal.getDisplayString(
3009                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3010                 if ( bOtherCalendar )
3011                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3012             }
3013             break;
3014             case NF_KEY_YY:                 // YY
3015             {
3016                 if ( bOtherCalendar )
3017                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3018                 OutString += rCal.getDisplayString(
3019                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3020                 if ( bOtherCalendar )
3021                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3022             }
3023             break;
3024             case NF_KEY_YYYY:               // YYYY
3025             {
3026                 if ( bOtherCalendar )
3027                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3028                 OutString += rCal.getDisplayString(
3029                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3030                 if ( bOtherCalendar )
3031                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3032             }
3033             break;
3034             case NF_KEY_EC:                 // E
3035                 OutString += rCal.getDisplayString(
3036                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3037             break;
3038             case NF_KEY_EEC:                // EE
3039             case NF_KEY_R:                  // R
3040                 OutString += rCal.getDisplayString(
3041                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3042             break;
3043             case NF_KEY_NN:                 // NN
3044             case NF_KEY_AAA:                // AAA
3045                 OutString += rCal.getDisplayString(
3046                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3047             break;
3048             case NF_KEY_NNN:                // NNN
3049             case NF_KEY_AAAA:               // AAAA
3050                 OutString += rCal.getDisplayString(
3051                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3052             break;
3053             case NF_KEY_NNNN:               // NNNN
3054             {
3055                 OutString += rCal.getDisplayString(
3056                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3057                 OutString += rLoc().getLongDateDayOfWeekSep();
3058             }
3059             break;
3060             case NF_KEY_WW :                // WW
3061             {
3062                 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
3063                 OutString += ImpIntToString( nIx, nVal );
3064             }
3065             break;
3066             case NF_KEY_G:                  // G
3067                 ImpAppendEraG( OutString, rCal, nNatNum );
3068             break;
3069             case NF_KEY_GG:                 // GG
3070                 OutString += rCal.getDisplayString(
3071                         CalendarDisplayCode::SHORT_ERA, nNatNum );
3072             break;
3073             case NF_KEY_GGG:                // GGG
3074                 OutString += rCal.getDisplayString(
3075                         CalendarDisplayCode::LONG_ERA, nNatNum );
3076             break;
3077             case NF_KEY_RR:                 // RR => GGGEE
3078                 OutString += rCal.getDisplayString(
3079                         CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
3080             break;
3081         }
3082     }
3083     if ( aOrgCalendar.Len() )
3084         rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() );  // restore calendar
3085     return bRes;
3086 }
3087 
3088 sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
3089                                        sal_uInt16 nIx,
3090                                        String& OutString)
3091 {
3092     using namespace ::com::sun::star::i18n;
3093     sal_Bool bRes = sal_False;
3094 
3095     CalendarWrapper& rCal = GetCal();
3096     double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
3097     fNumber += fDiff;
3098 
3099     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3100     sal_Bool bInputLine;
3101     xub_StrLen nCntPost;
3102     if ( rScan.GetStandardPrec() == 300 &&
3103             0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
3104     {   // round at 7 decimals (+5 of 86400 == 12 significant digits)
3105         bInputLine = sal_True;
3106         nCntPost = 7;
3107     }
3108     else
3109     {
3110         bInputLine = sal_False;
3111         nCntPost = xub_StrLen(rInfo.nCntPost);
3112     }
3113     double fTime = (fNumber - floor( fNumber )) * 86400.0;
3114     fTime = ::rtl::math::round( fTime, int(nCntPost) );
3115     if (fTime >= 86400.0)
3116     {
3117         // result of fNumber==x.999999999... rounded up, use correct date/time
3118         fTime -= 86400.0;
3119         fNumber = floor( fNumber + 0.5) + fTime;
3120     }
3121     rCal.setLocalDateTime( fNumber );
3122 
3123     String aOrgCalendar;        // empty => not changed yet
3124     double fOrgDateTime;
3125     sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
3126     if ( bOtherCalendar )
3127         SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3128     if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
3129         bOtherCalendar = sal_False;
3130     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
3131 
3132     sal_uLong nSeconds = (sal_uLong)floor( fTime );
3133     String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
3134                 rtl_math_StringFormat_F, int(nCntPost), '.'));
3135     sSecStr.EraseLeadingChars('0');
3136     sSecStr.EraseLeadingChars('.');
3137     if ( bInputLine )
3138     {
3139         sSecStr.EraseTrailingChars('0');
3140         if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
3141             sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
3142         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3143         nCntPost = sSecStr.Len();
3144     }
3145     else
3146         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3147 
3148     xub_StrLen nSecPos = 0;                     // Zum Ziffernweisen
3149                                             // abarbeiten
3150     sal_uLong nHour, nMin, nSec;
3151     if (!rInfo.bThousand)      // [] Format
3152     {
3153         nHour = (nSeconds/3600) % 24;
3154         nMin = (nSeconds%3600) / 60;
3155         nSec = nSeconds%60;
3156     }
3157     else if (rInfo.nThousand == 3) // [ss]
3158     {
3159         nHour = 0;
3160         nMin = 0;
3161         nSec = nSeconds;
3162     }
3163     else if (rInfo.nThousand == 2) // [mm]:ss
3164     {
3165         nHour = 0;
3166         nMin = nSeconds / 60;
3167         nSec = nSeconds % 60;
3168     }
3169     else if (rInfo.nThousand == 1) // [hh]:mm:ss
3170     {
3171         nHour = nSeconds / 3600;
3172         nMin = (nSeconds%3600) / 60;
3173         nSec = nSeconds%60;
3174     }
3175     else {
3176         nHour = 0;  // TODO What should these values be?
3177         nMin  = 0;
3178         nSec  = 0;
3179     }
3180     sal_Unicode cAmPm = ' ';                   // a oder p
3181     if (rInfo.nCntExp)     // AM/PM
3182     {
3183         if (nHour == 0)
3184         {
3185             nHour = 12;
3186             cAmPm = 'a';
3187         }
3188         else if (nHour < 12)
3189             cAmPm = 'a';
3190         else
3191         {
3192             cAmPm = 'p';
3193             if (nHour > 12)
3194                 nHour -= 12;
3195         }
3196     }
3197     const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
3198     for (sal_uInt16 i = 0; i < nAnz; i++)
3199     {
3200         switch (rInfo.nTypeArray[i])
3201         {
3202             case NF_SYMBOLTYPE_CALENDAR :
3203                 if ( !aOrgCalendar.Len() )
3204                 {
3205                     aOrgCalendar = rCal.getUniqueID();
3206                     fOrgDateTime = rCal.getDateTime();
3207                 }
3208                 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
3209                 rCal.setDateTime( fOrgDateTime );
3210                 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3211                 break;
3212             case NF_SYMBOLTYPE_STAR:
3213                 if( bStarFlag )
3214                 {
3215                     OutString += (sal_Unicode) 0x1B;
3216                     OutString += rInfo.sStrArray[i].GetChar(1);
3217                     bRes = sal_True;
3218                 }
3219                 break;
3220             case NF_SYMBOLTYPE_BLANK:
3221                 InsertBlanks( OutString, OutString.Len(),
3222                     rInfo.sStrArray[i].GetChar(1) );
3223                 break;
3224             case NF_SYMBOLTYPE_STRING:
3225             case NF_SYMBOLTYPE_CURRENCY:
3226             case NF_SYMBOLTYPE_DATESEP:
3227             case NF_SYMBOLTYPE_TIMESEP:
3228             case NF_SYMBOLTYPE_TIME100SECSEP:
3229                 OutString += rInfo.sStrArray[i];
3230                 break;
3231             case NF_SYMBOLTYPE_DIGIT:
3232             {
3233                 xub_StrLen nLen = ( bInputLine && i > 0 &&
3234                     (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
3235                      rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
3236                     nCntPost : rInfo.sStrArray[i].Len() );
3237                 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
3238                 {
3239                     OutString += sSecStr.GetChar(nSecPos);
3240                     nSecPos++;
3241                 }
3242             }
3243             break;
3244             case NF_KEY_AMPM:               // AM/PM
3245             {
3246                 if (cAmPm == 'a')
3247                     OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3248                         AmPmValue::AM, 0 );
3249                 else
3250                     OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3251                         AmPmValue::PM, 0 );
3252             }
3253             break;
3254             case NF_KEY_AP:                 // A/P
3255             {
3256                 if (cAmPm == 'a')
3257                     OutString += 'a';
3258                 else
3259                     OutString += 'p';
3260             }
3261             break;
3262             case NF_KEY_MI:                 // M
3263                 OutString += ImpIntToString( nIx, nMin );
3264             break;
3265             case NF_KEY_MMI:                // MM
3266                 OutString += ImpIntToString( nIx, nMin, 2 );
3267             break;
3268             case NF_KEY_H:                  // H
3269                 OutString += ImpIntToString( nIx, nHour );
3270             break;
3271             case NF_KEY_HH:                 // HH
3272                 OutString += ImpIntToString( nIx, nHour, 2 );
3273             break;
3274             case NF_KEY_S:                  // S
3275                 OutString += ImpIntToString( nIx, nSec );
3276             break;
3277             case NF_KEY_SS:                 // SS
3278                 OutString += ImpIntToString( nIx, nSec, 2 );
3279             break;
3280             case NF_KEY_M:                  // M
3281                 OutString += rCal.getDisplayString(
3282                         CalendarDisplayCode::SHORT_MONTH, nNatNum );
3283             break;
3284             case NF_KEY_MM:                 // MM
3285                 OutString += rCal.getDisplayString(
3286                         CalendarDisplayCode::LONG_MONTH, nNatNum );
3287             break;
3288             case NF_KEY_MMM:                // MMM
3289                 OutString += rCal.getDisplayString(
3290                         CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
3291             break;
3292             case NF_KEY_MMMM:               // MMMM
3293                 OutString += rCal.getDisplayString(
3294                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
3295             break;
3296             case NF_KEY_MMMMM:              // MMMMM
3297                 OutString += rCal.getDisplayString(
3298                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
3299             break;
3300             case NF_KEY_Q:                  // Q
3301                 OutString += rCal.getDisplayString(
3302                         CalendarDisplayCode::SHORT_QUARTER, nNatNum );
3303             break;
3304             case NF_KEY_QQ:                 // QQ
3305                 OutString += rCal.getDisplayString(
3306                         CalendarDisplayCode::LONG_QUARTER, nNatNum );
3307             break;
3308             case NF_KEY_D:                  // D
3309                 OutString += rCal.getDisplayString(
3310                         CalendarDisplayCode::SHORT_DAY, nNatNum );
3311             break;
3312             case NF_KEY_DD:                 // DD
3313                 OutString += rCal.getDisplayString(
3314                         CalendarDisplayCode::LONG_DAY, nNatNum );
3315             break;
3316             case NF_KEY_DDD:                // DDD
3317             {
3318                 if ( bOtherCalendar )
3319                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3320                 OutString += rCal.getDisplayString(
3321                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3322                 if ( bOtherCalendar )
3323                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3324             }
3325             break;
3326             case NF_KEY_DDDD:               // DDDD
3327             {
3328                 if ( bOtherCalendar )
3329                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3330                 OutString += rCal.getDisplayString(
3331                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3332                 if ( bOtherCalendar )
3333                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3334             }
3335             break;
3336             case NF_KEY_YY:                 // YY
3337             {
3338                 if ( bOtherCalendar )
3339                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3340                 OutString += rCal.getDisplayString(
3341                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3342                 if ( bOtherCalendar )
3343                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3344             }
3345             break;
3346             case NF_KEY_YYYY:               // YYYY
3347             {
3348                 if ( bOtherCalendar )
3349                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3350                 OutString += rCal.getDisplayString(
3351                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3352                 if ( bOtherCalendar )
3353                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3354             }
3355             break;
3356             case NF_KEY_EC:                 // E
3357                 OutString += rCal.getDisplayString(
3358                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3359             break;
3360             case NF_KEY_EEC:                // EE
3361             case NF_KEY_R:                  // R
3362                 OutString += rCal.getDisplayString(
3363                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3364             break;
3365             case NF_KEY_NN:                 // NN
3366             case NF_KEY_AAA:                // AAA
3367                 OutString += rCal.getDisplayString(
3368                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3369             break;
3370             case NF_KEY_NNN:                // NNN
3371             case NF_KEY_AAAA:               // AAAA
3372                 OutString += rCal.getDisplayString(
3373                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3374             break;
3375             case NF_KEY_NNNN:               // NNNN
3376             {
3377                 OutString += rCal.getDisplayString(
3378                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3379                 OutString += rLoc().getLongDateDayOfWeekSep();
3380             }
3381             break;
3382             case NF_KEY_WW :                // WW
3383             {
3384                 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
3385                 OutString += ImpIntToString( nIx, nVal );
3386             }
3387             break;
3388             case NF_KEY_G:                  // G
3389                 ImpAppendEraG( OutString, rCal, nNatNum );
3390             break;
3391             case NF_KEY_GG:                 // GG
3392                 OutString += rCal.getDisplayString(
3393                         CalendarDisplayCode::SHORT_ERA, nNatNum );
3394             break;
3395             case NF_KEY_GGG:                // GGG
3396                 OutString += rCal.getDisplayString(
3397                         CalendarDisplayCode::LONG_ERA, nNatNum );
3398             break;
3399             case NF_KEY_RR:                 // RR => GGGEE
3400                 OutString += rCal.getDisplayString(
3401                         CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
3402             break;
3403         }
3404     }
3405     if ( aOrgCalendar.Len() )
3406         rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() );  // restore calendar
3407     return bRes;
3408 }
3409 
3410 sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber,
3411                                      sal_uInt16 nIx,
3412                                      String& OutString)
3413 {
3414     sal_Bool bRes = sal_False;
3415     sal_Bool bSign;
3416     if (fNumber < 0.0)
3417     {
3418         if (nIx == 0)                       // nicht in hinteren
3419             bSign = sal_True;                   // Formaten
3420         else
3421             bSign = sal_False;
3422         fNumber = -fNumber;
3423     }
3424     else
3425     {
3426         bSign = sal_False;
3427         if ( ::rtl::math::isSignBitSet( fNumber ) )
3428             fNumber = -fNumber;     // yes, -0.0 is possible, eliminate '-'
3429     }
3430     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3431     if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
3432     {
3433         if (fNumber < _D_MAX_D_BY_100)
3434             fNumber *= 100.0;
3435         else
3436         {
3437             OutString = rScan.GetErrorString();
3438             return sal_False;
3439         }
3440     }
3441     sal_uInt16 i, j;
3442     xub_StrLen k;
3443     String sStr;
3444     long nPrecExp;
3445     sal_Bool bInteger = sal_False;
3446     if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
3447     {   // special formatting only if no GENERAL keyword in format code
3448         const sal_uInt16 nThousand = rInfo.nThousand;
3449         for (i = 0; i < nThousand; i++)
3450         {
3451            if (fNumber > _D_MIN_M_BY_1000)
3452                fNumber /= 1000.0;
3453            else
3454                fNumber = 0.0;
3455         }
3456         if (fNumber > 0.0)
3457             nPrecExp = GetPrecExp( fNumber );
3458         else
3459             nPrecExp = 0;
3460         if (rInfo.nCntPost)    // NachkommaStellen
3461         {
3462             if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15)
3463             {
3464                 sStr = ::rtl::math::doubleToUString( fNumber,
3465                         rtl_math_StringFormat_F, 15-nPrecExp, '.');
3466                 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
3467                     sStr += '0';
3468             }
3469             else
3470                 sStr = ::rtl::math::doubleToUString( fNumber,
3471                         rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
3472             sStr.EraseLeadingChars('0');        // fuehrende Nullen weg
3473         }
3474         else if (fNumber == 0.0)            // Null
3475         {
3476             // nothing to be done here, keep empty string sStr,
3477             // ImpNumberFillWithThousands does the rest
3478         }
3479         else                                // Integer
3480         {
3481             sStr = ::rtl::math::doubleToUString( fNumber,
3482                     rtl_math_StringFormat_F, 0, '.');
3483             sStr.EraseLeadingChars('0');        // fuehrende Nullen weg
3484         }
3485         xub_StrLen nPoint = sStr.Search( '.' );
3486         if ( nPoint != STRING_NOTFOUND )
3487         {
3488             register const sal_Unicode* p = sStr.GetBuffer() + nPoint;
3489             while ( *++p == '0' )
3490                 ;
3491             if ( !*p )
3492                 bInteger = sal_True;
3493             sStr.Erase( nPoint, 1 );            //  . herausnehmen
3494         }
3495         if (bSign &&
3496             (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1))   // nur 00000
3497             bSign = sal_False;              // nicht -0.00
3498     }                                   // End of != FLAG_STANDARD_IN_FORMAT
3499 
3500                                         // von hinten nach vorn
3501                                         // editieren:
3502     k = sStr.Len();                     // hinter letzter Ziffer
3503     j = NumFor[nIx].GetnAnz()-1;        // letztes Symbol
3504                                         // Nachkommastellen:
3505     if (rInfo.nCntPost > 0)
3506     {
3507         sal_Bool bTrailing = sal_True;          // ob Endnullen?
3508         sal_Bool bFilled = sal_False;           // ob aufgefuellt wurde ?
3509         short nType;
3510         while (j > 0 &&                 // rueckwaerts
3511            (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
3512         {
3513             switch ( nType )
3514             {
3515                 case NF_SYMBOLTYPE_STAR:
3516                     if( bStarFlag )
3517                     {
3518                         sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
3519                         sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3520                         bRes = sal_True;
3521                     }
3522                     break;
3523                 case NF_SYMBOLTYPE_BLANK:
3524                     /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3525                     break;
3526                 case NF_SYMBOLTYPE_STRING:
3527                 case NF_SYMBOLTYPE_CURRENCY:
3528                 case NF_SYMBOLTYPE_PERCENT:
3529                     sStr.Insert(rInfo.sStrArray[j],k);
3530                     break;
3531                 case NF_SYMBOLTYPE_THSEP:
3532                     if (rInfo.nThousand == 0)
3533                         sStr.Insert(rInfo.sStrArray[j],k);
3534                 break;
3535                 case NF_SYMBOLTYPE_DIGIT:
3536                 {
3537                     const String& rStr = rInfo.sStrArray[j];
3538                     const sal_Unicode* p1 = rStr.GetBuffer();
3539                     register const sal_Unicode* p = p1 + rStr.Len();
3540                     while ( p1 < p-- )
3541                     {
3542                         const sal_Unicode c = *p;
3543                         k--;
3544                         if ( sStr.GetChar(k) != '0' )
3545                             bTrailing = sal_False;
3546                         if (bTrailing)
3547                         {
3548                             if ( c == '0' )
3549                                 bFilled = sal_True;
3550                             else if ( c == '-' )
3551                             {
3552                                 if ( bInteger )
3553                                     sStr.SetChar( k, '-' );
3554                                 bFilled = sal_True;
3555                             }
3556                             else if ( c == '?' )
3557                             {
3558                                 sStr.SetChar( k, ' ' );
3559                                 bFilled = sal_True;
3560                             }
3561                             else if ( !bFilled )    // #
3562                                 sStr.Erase(k,1);
3563                         }
3564                     }                           // of for
3565                 }                               // of case digi
3566                 break;
3567                 case NF_KEY_CCC:                // CCC-Waehrung
3568                     sStr.Insert(rScan.GetCurAbbrev(), k);
3569                 break;
3570                 case NF_KEY_GENERAL:            // Standard im String
3571                 {
3572                     String sNum;
3573                     ImpGetOutputStandard(fNumber, sNum);
3574                     sNum.EraseLeadingChars('-');
3575                     sStr.Insert(sNum, k);
3576                 }
3577                 break;
3578                 default:
3579                 break;
3580             }                                   // of switch
3581             j--;
3582         }                                       // of while
3583     }                                           // of Nachkomma
3584 
3585     bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit .
3586                             rInfo.nCntPre);
3587     if ( rInfo.nCntPost > 0 )
3588     {
3589         const String& rDecSep = GetFormatter().GetNumDecimalSep();
3590         xub_StrLen nLen = rDecSep.Len();
3591         if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) )
3592             sStr.Erase( sStr.Len() - nLen );        // no decimals => strip DecSep
3593     }
3594     if (bSign)
3595         sStr.Insert('-',0);
3596     ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
3597     OutString = sStr;
3598     return bRes;
3599 }
3600 
3601 sal_Bool SvNumberformat::ImpNumberFillWithThousands(
3602                                 String& sStr,       // number string
3603                                 double& rNumber,    // number
3604                                 xub_StrLen k,       // position within string
3605                                 sal_uInt16 j,           // symbol index within format code
3606                                 sal_uInt16 nIx,         // subformat index
3607                                 sal_uInt16 nDigCnt)     // count of integer digits in format
3608 {
3609     sal_Bool bRes = sal_False;
3610     xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
3611     xub_StrLen nDigitCount = 0;         // count of integer digits from the right
3612     sal_Bool bStop = sal_False;
3613     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3614     // no normal thousands separators if number divided by thousands
3615     sal_Bool bDoThousands = (rInfo.nThousand == 0);
3616     utl::DigitGroupingIterator aGrouping(
3617             GetFormatter().GetLocaleData()->getDigitGrouping());
3618     while (!bStop)                                      // backwards
3619     {
3620         if (j == 0)
3621             bStop = sal_True;
3622         switch (rInfo.nTypeArray[j])
3623         {
3624             case NF_SYMBOLTYPE_DECSEP:
3625                 aGrouping.reset();
3626                 // fall thru
3627             case NF_SYMBOLTYPE_STRING:
3628             case NF_SYMBOLTYPE_CURRENCY:
3629             case NF_SYMBOLTYPE_PERCENT:
3630                 sStr.Insert(rInfo.sStrArray[j],k);
3631                 if ( k == 0 )
3632                     nLeadingStringChars =
3633                         nLeadingStringChars + rInfo.sStrArray[j].Len();
3634             break;
3635             case NF_SYMBOLTYPE_STAR:
3636                 if( bStarFlag )
3637                 {
3638                     sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
3639                     sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3640                     bRes = sal_True;
3641                 }
3642                 break;
3643             case NF_SYMBOLTYPE_BLANK:
3644                 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3645                 break;
3646             case NF_SYMBOLTYPE_THSEP:
3647             {
3648                 // #i7284# #102685# Insert separator also if number is divided
3649                 // by thousands and the separator is specified somewhere in
3650                 // between and not only at the end.
3651                 // #i12596# But do not insert if it's a parenthesized negative
3652                 // format like (#,)
3653                 // In fact, do not insert if divided and regex [0#,],[^0#] and
3654                 // no other digit symbol follows (which was already detected
3655                 // during scan of format code, otherwise there would be no
3656                 // division), else do insert. Same in ImpNumberFill() below.
3657                 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3658                     bDoThousands = ((j == 0) ||
3659                             (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3660                              rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3661                             (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3662                 if ( bDoThousands )
3663                 {
3664                     if (k > 0)
3665                         sStr.Insert(rInfo.sStrArray[j],k);
3666                     else if (nDigitCount < nDigCnt)
3667                     {
3668                         // Leading '#' displays nothing (e.g. no leading
3669                         // separator for numbers <1000 with #,##0 format).
3670                         // Leading '?' displays blank.
3671                         // Everything else, including nothing, displays the
3672                         // separator.
3673                         sal_Unicode cLeader = 0;
3674                         if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
3675                         {
3676                             const String& rStr = rInfo.sStrArray[j-1];
3677                             xub_StrLen nLen = rStr.Len();
3678                             if (nLen)
3679                                 cLeader = rStr.GetChar(nLen-1);
3680                         }
3681                         switch (cLeader)
3682                         {
3683                             case '#':
3684                                 ;   // nothing
3685                                 break;
3686                             case '?':
3687                                 // erAck: 2008-04-03T16:24+0200
3688                                 // Actually this currently isn't executed
3689                                 // because the format scanner in the context of
3690                                 // "?," doesn't generate a group separator but
3691                                 // a literal ',' character instead that is
3692                                 // inserted unconditionally. Should be changed
3693                                 // on some occasion.
3694                                 sStr.Insert(' ',k);
3695                                 break;
3696                             default:
3697                                 sStr.Insert(rInfo.sStrArray[j],k);
3698                         }
3699                     }
3700                     aGrouping.advance();
3701                 }
3702             }
3703             break;
3704             case NF_SYMBOLTYPE_DIGIT:
3705             {
3706                 const String& rStr = rInfo.sStrArray[j];
3707                 const sal_Unicode* p1 = rStr.GetBuffer();
3708                 register const sal_Unicode* p = p1 + rStr.Len();
3709                 while ( p1 < p-- )
3710                 {
3711                     nDigitCount++;
3712                     if (k > 0)
3713                         k--;
3714                     else
3715                     {
3716                         switch (*p)
3717                         {
3718                             case '0':
3719                                 sStr.Insert('0',0);
3720                                 break;
3721                             case '?':
3722                                 sStr.Insert(' ',0);
3723                                 break;
3724                         }
3725                     }
3726                     if (nDigitCount == nDigCnt && k > 0)
3727                     {   // more digits than specified
3728                         ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping);
3729                     }
3730                 }
3731             }
3732             break;
3733             case NF_KEY_CCC:                        // CCC currency
3734                 sStr.Insert(rScan.GetCurAbbrev(), k);
3735             break;
3736             case NF_KEY_GENERAL:                    // "General" in string
3737             {
3738                 String sNum;
3739                 ImpGetOutputStandard(rNumber, sNum);
3740                 sNum.EraseLeadingChars('-');
3741                 sStr.Insert(sNum, k);
3742             }
3743             break;
3744 
3745             default:
3746             break;
3747         } // switch
3748         j--;        // next format code string
3749     } // while
3750     k = k + nLeadingStringChars;    // MSC converts += to int and then warns, so ...
3751     if (k > nLeadingStringChars)
3752         ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
3753     return bRes;
3754 }
3755 
3756 void SvNumberformat::ImpDigitFill(
3757         String& sStr,                   // number string
3758         xub_StrLen nStart,              // start of digits
3759         xub_StrLen& k,                  // position within string
3760         sal_uInt16 nIx,                     // subformat index
3761         xub_StrLen & nDigitCount,       // count of integer digits from the right so far
3762         utl::DigitGroupingIterator & rGrouping )    // current grouping
3763 {
3764     if (NumFor[nIx].Info().bThousand)               // only if grouping
3765     {                                               // fill in separators
3766         const String& rThousandSep = GetFormatter().GetNumThousandSep();
3767         while (k > nStart)
3768         {
3769             if (nDigitCount == rGrouping.getPos())
3770             {
3771                 sStr.Insert( rThousandSep, k );
3772                 rGrouping.advance();
3773             }
3774             nDigitCount++;
3775             k--;
3776         }
3777     }
3778     else                                            // simply skip
3779         k = nStart;
3780 }
3781 
3782 sal_Bool SvNumberformat::ImpNumberFill( String& sStr,       // number string
3783                                 double& rNumber,        // number for "General" format
3784                                 xub_StrLen& k,          // position within string
3785                                 sal_uInt16& j,              // symbol index within format code
3786                                 sal_uInt16 nIx,             // subformat index
3787                                 short eSymbolType )     // type of stop condition
3788 {
3789     sal_Bool bRes = sal_False;
3790     k = sStr.Len();                         // behind last digit
3791     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3792     // no normal thousands separators if number divided by thousands
3793     sal_Bool bDoThousands = (rInfo.nThousand == 0);
3794     short nType;
3795     while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
3796     {                                       // rueckwaerts:
3797         switch ( nType )
3798         {
3799             case NF_SYMBOLTYPE_STAR:
3800                 if( bStarFlag )
3801                 {
3802                     sStr.Insert( sal_Unicode(0x1B), k++ );
3803                     sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3804                     bRes = sal_True;
3805                 }
3806                 break;
3807             case NF_SYMBOLTYPE_BLANK:
3808                 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3809                 break;
3810             case NF_SYMBOLTYPE_THSEP:
3811             {
3812                 // Same as in ImpNumberFillWithThousands() above, do not insert
3813                 // if divided and regex [0#,],[^0#] and no other digit symbol
3814                 // follows (which was already detected during scan of format
3815                 // code, otherwise there would be no division), else do insert.
3816                 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3817                     bDoThousands = ((j == 0) ||
3818                             (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3819                              rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3820                             (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3821                 if ( bDoThousands && k > 0 )
3822                 {
3823                     sStr.Insert(rInfo.sStrArray[j],k);
3824                 }
3825             }
3826             break;
3827             case NF_SYMBOLTYPE_DIGIT:
3828             {
3829                 const String& rStr = rInfo.sStrArray[j];
3830                 const sal_Unicode* p1 = rStr.GetBuffer();
3831                 register const sal_Unicode* p = p1 + rStr.Len();
3832                 while ( p1 < p-- )
3833                 {
3834                     if (k > 0)
3835                         k--;
3836                     else
3837                     {
3838                         switch (*p)
3839                         {
3840                             case '0':
3841                                 sStr.Insert('0',0);
3842                                 break;
3843                             case '?':
3844                                 sStr.Insert(' ',0);
3845                                 break;
3846                         }
3847                     }
3848                 }
3849             }
3850             break;
3851             case NF_KEY_CCC:                // CCC-Waehrung
3852                 sStr.Insert(rScan.GetCurAbbrev(), k);
3853             break;
3854             case NF_KEY_GENERAL:            // Standard im String
3855             {
3856                 String sNum;
3857                 ImpGetOutputStandard(rNumber, sNum);
3858                 sNum.EraseLeadingChars('-');    // Vorzeichen weg!!
3859                 sStr.Insert(sNum, k);
3860             }
3861             break;
3862 
3863             default:
3864                 sStr.Insert(rInfo.sStrArray[j],k);
3865             break;
3866         }                                       // of switch
3867         j--;                                    // naechster String
3868     }                                           // of while
3869     return bRes;
3870 }
3871 
3872 void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand,
3873                                           sal_Bool& IsRed,
3874                                           sal_uInt16& nPrecision,
3875                                           sal_uInt16& nAnzLeading) const
3876 {
3877     // as before: take info from nNumFor=0 for whole format (for dialog etc.)
3878 
3879     short nDummyType;
3880     GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
3881 
3882     // "negative in red" is only useful for the whole format
3883 
3884     const Color* pColor = NumFor[1].GetColor();
3885     if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
3886                        && (*pColor == rScan.GetRedColor()))
3887         IsRed = sal_True;
3888     else
3889         IsRed = sal_False;
3890 }
3891 
3892 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType,
3893                     sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const
3894 {
3895     // take info from a specified sub-format (for XML export)
3896 
3897     if ( nNumFor > 3 )
3898         return;             // invalid
3899 
3900     const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
3901     rScannedType = rInfo.eScannedType;
3902     bThousand = rInfo.bThousand;
3903     nPrecision = rInfo.nCntPost;
3904     if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
3905                                                         // StandardFormat
3906         nAnzLeading = 1;
3907     else
3908     {
3909         nAnzLeading = 0;
3910         sal_Bool bStop = sal_False;
3911         sal_uInt16 i = 0;
3912         const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
3913         while (!bStop && i < nAnz)
3914         {
3915             short nType = rInfo.nTypeArray[i];
3916             if ( nType == NF_SYMBOLTYPE_DIGIT)
3917             {
3918                 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
3919                 while ( *p == '#' )
3920                     p++;
3921                 while ( *p++ == '0' )
3922                     nAnzLeading++;
3923             }
3924             else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
3925                 bStop = sal_True;
3926             i++;
3927         }
3928     }
3929 }
3930 
3931 const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos,
3932             sal_Bool bString /* = sal_False */ ) const
3933 {
3934     if ( nNumFor > 3 )
3935         return NULL;
3936     sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
3937     if ( !nAnz )
3938         return NULL;
3939     if ( nPos == 0xFFFF )
3940     {
3941         nPos = nAnz - 1;
3942         if ( bString )
3943         {   // rueckwaerts
3944             short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3945             while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3946                     (*pType != NF_SYMBOLTYPE_CURRENCY) )
3947             {
3948                 pType--;
3949                 nPos--;
3950             }
3951             if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3952                 return NULL;
3953         }
3954     }
3955     else if ( nPos > nAnz - 1 )
3956         return NULL;
3957     else if ( bString )
3958     {   // vorwaerts
3959         short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3960         while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
3961                 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3962         {
3963             pType++;
3964             nPos++;
3965         }
3966         if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
3967                     (*pType != NF_SYMBOLTYPE_CURRENCY)) )
3968             return NULL;
3969     }
3970     return &NumFor[nNumFor].Info().sStrArray[nPos];
3971 }
3972 
3973 
3974 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos,
3975             sal_Bool bString /* = sal_False */ ) const
3976 {
3977     if ( nNumFor > 3 )
3978         return 0;
3979     sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
3980     if ( !nAnz )
3981         return 0;
3982     if ( nPos == 0xFFFF )
3983     {
3984         nPos = nAnz - 1;
3985         if ( bString )
3986         {   // rueckwaerts
3987             short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3988             while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3989                     (*pType != NF_SYMBOLTYPE_CURRENCY) )
3990             {
3991                 pType--;
3992                 nPos--;
3993             }
3994             if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3995                 return 0;
3996         }
3997     }
3998     else if ( nPos > nAnz - 1 )
3999         return 0;
4000     else if ( bString )
4001     {   // vorwaerts
4002         short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4003         while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
4004                 (*pType != NF_SYMBOLTYPE_CURRENCY) )
4005         {
4006             pType++;
4007             nPos++;
4008         }
4009         if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
4010             return 0;
4011     }
4012     return NumFor[nNumFor].Info().nTypeArray[nPos];
4013 }
4014 
4015 
4016 sal_Bool SvNumberformat::IsNegativeWithoutSign() const
4017 {
4018     if ( IsNegativeRealNegative() )
4019     {
4020         const String* pStr = GetNumForString( 1, 0, sal_True );
4021         if ( pStr )
4022             return !HasStringNegativeSign( *pStr );
4023     }
4024     return sal_False;
4025 }
4026 
4027 
4028 DateFormat SvNumberformat::GetDateOrder() const
4029 {
4030     if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
4031     {
4032         short const * const pType = NumFor[0].Info().nTypeArray;
4033         sal_uInt16 nAnz = NumFor[0].GetnAnz();
4034         for ( sal_uInt16 j=0; j<nAnz; j++ )
4035         {
4036             switch ( pType[j] )
4037             {
4038                 case NF_KEY_D :
4039                 case NF_KEY_DD :
4040                     return DMY;
4041                 case NF_KEY_M :
4042                 case NF_KEY_MM :
4043                 case NF_KEY_MMM :
4044                 case NF_KEY_MMMM :
4045                 case NF_KEY_MMMMM :
4046                     return MDY;
4047                 case NF_KEY_YY :
4048                 case NF_KEY_YYYY :
4049                 case NF_KEY_EC :
4050                 case NF_KEY_EEC :
4051                 case NF_KEY_R :
4052                 case NF_KEY_RR :
4053                     return YMD;
4054             }
4055         }
4056     }
4057     else
4058     {
4059        DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
4060     }
4061     return rLoc().getDateFormat();
4062 }
4063 
4064 
4065 sal_uInt32 SvNumberformat::GetExactDateOrder() const
4066 {
4067     sal_uInt32 nRet = 0;
4068     if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
4069     {
4070         DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
4071         return nRet;
4072     }
4073     short const * const pType = NumFor[0].Info().nTypeArray;
4074     sal_uInt16 nAnz = NumFor[0].GetnAnz();
4075     int nShift = 0;
4076     for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ )
4077     {
4078         switch ( pType[j] )
4079         {
4080             case NF_KEY_D :
4081             case NF_KEY_DD :
4082                 nRet = (nRet << 8) | 'D';
4083                 ++nShift;
4084             break;
4085             case NF_KEY_M :
4086             case NF_KEY_MM :
4087             case NF_KEY_MMM :
4088             case NF_KEY_MMMM :
4089             case NF_KEY_MMMMM :
4090                 nRet = (nRet << 8) | 'M';
4091                 ++nShift;
4092             break;
4093             case NF_KEY_YY :
4094             case NF_KEY_YYYY :
4095             case NF_KEY_EC :
4096             case NF_KEY_EEC :
4097             case NF_KEY_R :
4098             case NF_KEY_RR :
4099                 nRet = (nRet << 8) | 'Y';
4100                 ++nShift;
4101             break;
4102         }
4103     }
4104     return nRet;
4105 }
4106 
4107 
4108 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
4109                           SvNumberformatLimitOps& rOper2, double& rVal2 ) const
4110 {
4111     rOper1 = eOp1;
4112     rOper2 = eOp2;
4113     rVal1  = fLimit1;
4114     rVal2  = fLimit2;
4115 }
4116 
4117 
4118 Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const
4119 {
4120     if ( nNumFor > 3 )
4121         return NULL;
4122 
4123     return NumFor[nNumFor].GetColor();
4124 }
4125 
4126 
4127 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr,
4128             SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep )
4129 {
4130     if ( eOp != NUMBERFORMAT_OP_NO )
4131     {
4132         switch ( eOp )
4133         {
4134             case NUMBERFORMAT_OP_EQ :
4135                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
4136             break;
4137             case NUMBERFORMAT_OP_NE :
4138                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
4139             break;
4140             case NUMBERFORMAT_OP_LT :
4141                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
4142             break;
4143             case NUMBERFORMAT_OP_LE :
4144                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
4145             break;
4146             case NUMBERFORMAT_OP_GT :
4147                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
4148             break;
4149             case NUMBERFORMAT_OP_GE :
4150                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
4151             break;
4152             default:
4153                 OSL_ASSERT( "unsupported number format" );
4154                 break;
4155         }
4156         rStr += String( ::rtl::math::doubleToUString( fLimit,
4157                 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
4158                 rDecSep.GetChar(0), sal_True));
4159         rStr += ']';
4160     }
4161 }
4162 
4163 
4164 String SvNumberformat::GetMappedFormatstring(
4165         const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp,
4166         sal_Bool bDontQuote ) const
4167 {
4168     String aStr;
4169     sal_Bool bDefault[4];
4170     // 1 subformat matches all if no condition specified,
4171     bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
4172     // with 2 subformats [>=0];[<0] is implied if no condition specified
4173     bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 &&
4174         eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
4175         eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
4176     // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4177     // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4178     bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
4179         eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
4180         eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
4181     sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
4182     // from now on bDefault[] values are used to append empty subformats at the end
4183     bDefault[3] = sal_False;
4184     if ( !bDefaults )
4185     {   // conditions specified
4186         if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
4187             bDefault[0] = bDefault[1] = sal_True;                               // [];x
4188         else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
4189                 NumFor[2].GetnAnz() == 0 )
4190             bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True;   // [];[];;
4191         // nothing to do if conditions specified for every subformat
4192     }
4193     else if ( bDefault[0] )
4194         bDefault[0] = sal_False;    // a single unconditional subformat is never delimited
4195     else
4196     {
4197         if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
4198             bDefault[3] = sal_True;     // special cases x;x;; and ;x;;
4199         for ( int i=0; i<3 && !bDefault[i]; ++i )
4200             bDefault[i] = sal_True;
4201     }
4202     int nSem = 0;       // needed ';' delimiters
4203     int nSub = 0;       // subformats delimited so far
4204     for ( int n=0; n<4; n++ )
4205     {
4206         if ( n > 0 )
4207             nSem++;
4208 
4209         String aPrefix;
4210 
4211         if ( !bDefaults )
4212         {
4213             switch ( n )
4214             {
4215                 case 0 :
4216                     lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
4217                         fLimit1, rLocWrp.getNumDecimalSep() );
4218                 break;
4219                 case 1 :
4220                     lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
4221                         fLimit2, rLocWrp.getNumDecimalSep() );
4222                 break;
4223             }
4224         }
4225 
4226         const String& rColorName = NumFor[n].GetColorName();
4227         if ( rColorName.Len() )
4228         {
4229             const NfKeywordTable & rKey = rScan.GetKeywords();
4230             for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ )
4231             {
4232                 if ( rKey[j] == rColorName )
4233                 {
4234                     aPrefix += '[';
4235                     aPrefix += rKeywords[j];
4236                     aPrefix += ']';
4237                     break;  // for
4238                 }
4239             }
4240         }
4241 
4242         const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
4243         // The Thai T NatNum modifier during Xcl export.
4244         if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
4245                 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") &&
4246                 MsLangId::getRealLanguage( rNum.GetLang()) ==
4247                 LANGUAGE_THAI)
4248         {
4249             aPrefix += 't';     // must be lowercase, otherwise taken as literal
4250         }
4251 
4252         sal_uInt16 nAnz = NumFor[n].GetnAnz();
4253         if ( nSem && (nAnz || aPrefix.Len()) )
4254         {
4255             for ( ; nSem; --nSem )
4256                 aStr += ';';
4257             for ( ; nSub <= n; ++nSub )
4258                 bDefault[nSub] = sal_False;
4259         }
4260 
4261         if ( aPrefix.Len() )
4262             aStr += aPrefix;
4263 
4264         if ( nAnz )
4265         {
4266             const short* pType = NumFor[n].Info().nTypeArray;
4267             const String* pStr = NumFor[n].Info().sStrArray;
4268             for ( sal_uInt16 j=0; j<nAnz; j++ )
4269             {
4270                 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
4271                 {
4272                     aStr += rKeywords[pType[j]];
4273                     if( NF_KEY_NNNN == pType[j] )
4274                         aStr += rLocWrp.getLongDateDayOfWeekSep();
4275                 }
4276                 else
4277                 {
4278                     switch ( pType[j] )
4279                     {
4280                         case NF_SYMBOLTYPE_DECSEP :
4281                             aStr += rLocWrp.getNumDecimalSep();
4282                         break;
4283                         case NF_SYMBOLTYPE_THSEP :
4284                             aStr += rLocWrp.getNumThousandSep();
4285                         break;
4286                         case NF_SYMBOLTYPE_DATESEP :
4287                             aStr += rLocWrp.getDateSep();
4288                         break;
4289                         case NF_SYMBOLTYPE_TIMESEP :
4290                             aStr += rLocWrp.getTimeSep();
4291                         break;
4292                         case NF_SYMBOLTYPE_TIME100SECSEP :
4293                             aStr += rLocWrp.getTime100SecSep();
4294                         break;
4295                         case NF_SYMBOLTYPE_STRING :
4296                             if( bDontQuote )
4297                                 aStr += pStr[j];
4298                             else if ( pStr[j].Len() == 1 )
4299                             {
4300                                 aStr += '\\';
4301                                 aStr += pStr[j];
4302                             }
4303                             else
4304                             {
4305                                 aStr += '"';
4306                                 aStr += pStr[j];
4307                                 aStr += '"';
4308                             }
4309                             break;
4310                         default:
4311                             aStr += pStr[j];
4312                     }
4313 
4314                 }
4315             }
4316         }
4317     }
4318     for ( ; nSub<4 && bDefault[nSub]; ++nSub )
4319     {   // append empty subformats
4320         aStr += ';';
4321     }
4322     return aStr;
4323 }
4324 
4325 
4326 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
4327         sal_Int32 nVal, sal_uInt16 nMinDigits ) const
4328 {
4329     String aStr;
4330     if ( nMinDigits )
4331     {
4332         if ( nMinDigits == 2 )
4333         {   // speed up the most common case
4334             if ( 0 <= nVal && nVal < 10 )
4335             {
4336                 sal_Unicode* p = aStr.AllocBuffer( 2 );
4337                 *p++ = '0';
4338                 *p = sal_Unicode( '0' + nVal );
4339             }
4340             else
4341                 aStr = String::CreateFromInt32( nVal );
4342         }
4343         else
4344         {
4345             String aValStr( String::CreateFromInt32( nVal ) );
4346             if ( aValStr.Len() >= nMinDigits )
4347                 aStr = aValStr;
4348             else
4349             {
4350                 aStr.Fill( nMinDigits - aValStr.Len(), '0' );
4351                 aStr += aValStr;
4352             }
4353         }
4354     }
4355     else
4356         aStr = String::CreateFromInt32( nVal );
4357     ImpTransliterate( aStr, rNum );
4358     return aStr;
4359 }
4360 
4361 
4362 void SvNumberformat::ImpTransliterateImpl( String& rStr,
4363         const SvNumberNatNum& rNum ) const
4364 {
4365     com::sun::star::lang::Locale aLocale(
4366             MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4367     rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
4368             aLocale, rNum.GetNatNum() );
4369 }
4370 
4371 
4372 void SvNumberformat::GetNatNumXml(
4373         com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
4374         sal_uInt16 nNumFor ) const
4375 {
4376     if ( nNumFor <= 3 )
4377     {
4378         const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
4379         if ( rNum.IsSet() )
4380         {
4381             com::sun::star::lang::Locale aLocale(
4382                     MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4383             rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
4384                     aLocale, rNum.GetNatNum() );
4385         }
4386         else
4387             rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4388     }
4389     else
4390         rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4391 }
4392 
4393 // static
4394 sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr )
4395 {
4396     // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
4397     xub_StrLen nLen = rStr.Len();
4398     if ( !nLen )
4399         return sal_False;
4400     const sal_Unicode* const pBeg = rStr.GetBuffer();
4401     const sal_Unicode* const pEnd = pBeg + nLen;
4402     register const sal_Unicode* p = pBeg;
4403     do
4404     {   // Anfang
4405         if ( *p == '-' )
4406             return sal_True;
4407     } while ( *p == ' ' && ++p < pEnd );
4408     p = pEnd - 1;
4409     do
4410     {   // Ende
4411         if ( *p == '-' )
4412             return sal_True;
4413     } while ( *p == ' ' && pBeg < --p );
4414     return sal_False;
4415 }
4416 
4417 
4418 // static
4419 void SvNumberformat::SetComment( const String& rStr, String& rFormat,
4420         String& rComment )
4421 {
4422     if ( rComment.Len() )
4423     {   // alten Kommentar aus Formatstring loeschen
4424         //! nicht per EraseComment, der Kommentar muss matchen
4425         String aTmp( '{' );
4426         aTmp += ' ';
4427         aTmp += rComment;
4428         aTmp += ' ';
4429         aTmp += '}';
4430         xub_StrLen nCom = 0;
4431         do
4432         {
4433             nCom = rFormat.Search( aTmp, nCom );
4434         } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) );
4435         if ( nCom != STRING_NOTFOUND )
4436             rFormat.Erase( nCom );
4437     }
4438     if ( rStr.Len() )
4439     {   // neuen Kommentar setzen
4440         rFormat += '{';
4441         rFormat += ' ';
4442         rFormat += rStr;
4443         rFormat += ' ';
4444         rFormat += '}';
4445         rComment = rStr;
4446     }
4447 }
4448 
4449 
4450 // static
4451 void SvNumberformat::EraseCommentBraces( String& rStr )
4452 {
4453     xub_StrLen nLen = rStr.Len();
4454     if ( nLen && rStr.GetChar(0) == '{' )
4455     {
4456         rStr.Erase( 0, 1 );
4457         --nLen;
4458     }
4459     if ( nLen && rStr.GetChar(0) == ' ' )
4460     {
4461         rStr.Erase( 0, 1 );
4462         --nLen;
4463     }
4464     if ( nLen && rStr.GetChar( nLen-1 ) == '}' )
4465         rStr.Erase( --nLen, 1 );
4466     if ( nLen && rStr.GetChar( nLen-1 ) == ' ' )
4467         rStr.Erase( --nLen, 1 );
4468 }
4469 
4470 
4471 // static
4472 void SvNumberformat::EraseComment( String& rStr )
4473 {
4474     register const sal_Unicode* p = rStr.GetBuffer();
4475     sal_Bool bInString = sal_False;
4476     sal_Bool bEscaped = sal_False;
4477     sal_Bool bFound = sal_False;
4478     xub_StrLen nPos = 0;
4479     while ( !bFound && *p )
4480     {
4481         switch ( *p )
4482         {
4483             case '\\' :
4484                 bEscaped = !bEscaped;
4485             break;
4486             case '\"' :
4487                 if ( !bEscaped )
4488                     bInString = !bInString;
4489             break;
4490             case '{' :
4491                 if ( !bEscaped && !bInString )
4492                 {
4493                     bFound = sal_True;
4494                     nPos = sal::static_int_cast< xub_StrLen >(
4495                         p - rStr.GetBuffer());
4496                 }
4497             break;
4498         }
4499         if ( bEscaped && *p != '\\' )
4500             bEscaped = sal_False;
4501         ++p;
4502     }
4503     if ( bFound )
4504         rStr.Erase( nPos );
4505 }
4506 
4507 
4508 // static
4509 sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos,
4510             sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4511 {
4512     xub_StrLen nLen = rStr.Len();
4513     if ( nPos >= nLen )
4514         return sal_False;
4515     register const sal_Unicode* p0 = rStr.GetBuffer();
4516     register const sal_Unicode* p = p0;
4517     register const sal_Unicode* p1 = p0 + nPos;
4518     sal_Bool bQuoted = sal_False;
4519     while ( p <= p1 )
4520     {
4521         if ( *p == cQuote )
4522         {
4523             if ( p == p0 )
4524                 bQuoted = sal_True;
4525             else if ( bQuoted )
4526             {
4527                 if ( *(p-1) != cEscIn )
4528                     bQuoted = sal_False;
4529             }
4530             else
4531             {
4532                 if ( *(p-1) != cEscOut )
4533                     bQuoted = sal_True;
4534             }
4535         }
4536         p++;
4537     }
4538     return bQuoted;
4539 }
4540 
4541 
4542 // static
4543 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos,
4544             sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4545 {
4546     xub_StrLen nLen = rStr.Len();
4547     if ( nPos >= nLen )
4548         return STRING_NOTFOUND;
4549     if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
4550     {
4551         if ( rStr.GetChar( nPos ) == cQuote )
4552             return nPos;        // schliessendes cQuote
4553         return STRING_NOTFOUND;
4554     }
4555     register const sal_Unicode* p0 = rStr.GetBuffer();
4556     register const sal_Unicode* p = p0 + nPos;
4557     register const sal_Unicode* p1 = p0 + nLen;
4558     while ( p < p1 )
4559     {
4560         if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
4561             return sal::static_int_cast< xub_StrLen >(p - p0);
4562         p++;
4563     }
4564     return nLen;        // String Ende
4565 }
4566 
4567 
4568 sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const
4569 {
4570     sal_uInt16 nCnt = 0;
4571     sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
4572     short const * const pType = NumFor[nNumFor].Info().nTypeArray;
4573     for ( sal_uInt16 j=0; j<nAnz; ++j )
4574     {
4575         switch ( pType[j] )
4576         {
4577             case NF_SYMBOLTYPE_STRING:
4578             case NF_SYMBOLTYPE_CURRENCY:
4579             case NF_SYMBOLTYPE_DATESEP:
4580             case NF_SYMBOLTYPE_TIMESEP:
4581             case NF_SYMBOLTYPE_TIME100SECSEP:
4582             case NF_SYMBOLTYPE_PERCENT:
4583                 ++nCnt;
4584             break;
4585         }
4586     }
4587     return nCnt;
4588 }
4589 
4590