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