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