xref: /aoo42x/main/svl/source/numbers/zformat.cxx (revision c916a786)
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 sal_Bool IsSingleSymbol(String& rString, xub_StrLen nPos){
1138 	sal_Bool ret = sal_False;
1139 	while(nPos > 0){
1140 		if(rString.GetChar(nPos) == '*' || rString.GetChar(nPos) == '\\' || rString.GetChar(nPos) == '_'){
1141 			ret = !ret;
1142 			nPos--;
1143 		}
1144 		else
1145 			return ret;
1146 	}
1147 	return ret;
1148 }
1149 
1150 short SvNumberformat::ImpNextSymbol(String& rString,
1151                                  xub_StrLen& nPos,
1152                                  String& sSymbol)
1153 {
1154     short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1155     sal_Unicode cToken;
1156     sal_Unicode cLetter = ' ';                               // Zwischenergebnis
1157     xub_StrLen nLen = rString.Len();
1158     ScanState eState = SsStart;
1159     sSymbol.Erase();
1160     const NfKeywordTable & rKeywords = rScan.GetKeywords();
1161     while (nPos < nLen && eState != SsStop)
1162     {
1163         cToken = rString.GetChar(nPos);
1164         nPos++;
1165         switch (eState)
1166         {
1167             case SsStart:
1168             {
1169                 if (cToken == '[')
1170                 {
1171                     eState = SsGetBracketed;
1172                     sSymbol += cToken;
1173                 }
1174                 else if (cToken == ';')
1175                 {
1176                     eState = SsGetString;
1177                     nPos--;
1178                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1179                 }
1180                 else if (cToken == ']')
1181                 {
1182                     eState = SsStop;
1183                     eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1184                 }
1185                 else if (cToken == ' ')             // Skip Blanks
1186                 {
1187                     rString.Erase(nPos-1,1);
1188                     nPos--;
1189                     nLen--;
1190                 }
1191                 else
1192                 {
1193                     sSymbol += cToken;
1194                     eState = SsGetString;
1195                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1196                 }
1197             }
1198             break;
1199             case SsGetBracketed:
1200             {
1201                 switch (cToken)
1202                 {
1203                     case '<':
1204                     case '>':
1205                     case '=':
1206                     {
1207                         sSymbol.EraseAllChars('[');
1208                         sSymbol += cToken;
1209                         cLetter = cToken;
1210                         eState = SsGetCon;
1211                         switch (cToken)
1212                         {
1213                             case '<': eSymbolType = NUMBERFORMAT_OP_LT; break;
1214                             case '>': eSymbolType = NUMBERFORMAT_OP_GT; break;
1215                             case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break;
1216                             default: break;
1217                         }
1218                     }
1219                     break;
1220                     case ' ':
1221                     {
1222                         rString.Erase(nPos-1,1);
1223                         nPos--;
1224                         nLen--;
1225                     }
1226                     break;
1227                     case '$' :
1228                     {
1229                         if ( rString.GetChar(nPos) == '-' )
1230                         {   // [$-xxx] locale
1231                             sSymbol.EraseAllChars('[');
1232                             eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
1233                             eState = SsGetPrefix;
1234                         }
1235                         else
1236                         {   // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1237                             eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1238                             eState = SsGetString;
1239                         }
1240                         sSymbol += cToken;
1241                     }
1242                     break;
1243                     case '~' :
1244                     {   // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1245                         eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1246                         sSymbol += cToken;
1247                         eState = SsGetString;
1248                     }
1249                     break;
1250                     default:
1251                     {
1252                         static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) );
1253                         static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) );
1254                         String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) );
1255                         String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) );
1256                         sal_Unicode cUpper = aUpperNatNum.GetChar(0);
1257                         sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32();
1258                         sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() );
1259                         if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 )
1260                         {
1261                             sSymbol.EraseAllChars('[');
1262                             sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 );
1263                             nPos += aNatNum.Len()+1;
1264                             //! SymbolType is negative
1265                             eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum);
1266                             eState = SsGetPrefix;
1267                         }
1268                         else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' )
1269                         {
1270                             sSymbol.EraseAllChars('[');
1271                             sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 );
1272                             nPos += aDBNum.Len()+1;
1273                             //! SymbolType is negative
1274                             eSymbolType = sal::static_int_cast< short >(
1275                                 BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1'));
1276                             eState = SsGetPrefix;
1277                         }
1278                         else if (cUpper == rKeywords[NF_KEY_H].GetChar(0)   ||  // H
1279                             cUpper == rKeywords[NF_KEY_MI].GetChar(0)   ||  // M
1280                             cUpper == rKeywords[NF_KEY_S].GetChar(0)    )   // S
1281                         {
1282                             sSymbol += cToken;
1283                             eState = SsGetTime;
1284                             cLetter = cToken;
1285                         }
1286                         else
1287                         {
1288                             sSymbol.EraseAllChars('[');
1289                             sSymbol += cToken;
1290                             eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1291                             eState = SsGetPrefix;
1292                         }
1293                     }
1294                     break;
1295                 }
1296             }
1297             break;
1298             case SsGetString:
1299             {
1300                 if (cToken == ';' && (nPos>=2) &&!IsSingleSymbol(rString, nPos-2))
1301 				{
1302                     eState = SsStop;
1303 				}
1304                 else
1305                     sSymbol += cToken;
1306             }
1307             break;
1308             case SsGetTime:
1309             {
1310                 if (cToken == ']')
1311                 {
1312                     sSymbol += cToken;
1313                     eState = SsGetString;
1314                     eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1315                 }
1316                 else
1317                 {
1318                     sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0);
1319                     if (cUpper == rKeywords[NF_KEY_H].GetChar(0)    ||  // H
1320                         cUpper == rKeywords[NF_KEY_MI].GetChar(0)   ||  // M
1321                         cUpper == rKeywords[NF_KEY_S].GetChar(0)    )   // S
1322                     {
1323                         if (cLetter == cToken)
1324                         {
1325                             sSymbol += cToken;
1326                             cLetter = ' ';
1327                         }
1328                         else
1329                         {
1330                             sSymbol.EraseAllChars('[');
1331                             sSymbol += cToken;
1332                             eState = SsGetPrefix;
1333                         }
1334                     }
1335                     else
1336                     {
1337                         sSymbol.EraseAllChars('[');
1338                         sSymbol += cToken;
1339                         eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1340                         eState = SsGetPrefix;
1341                     }
1342                 }
1343             }
1344             break;
1345             case SsGetCon:
1346             {
1347                 switch (cToken)
1348                 {
1349                     case '<':
1350                     {
1351                         eState = SsStop;
1352                         eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1353                     }
1354                     break;
1355                     case '>':
1356                     {
1357                         if (cLetter == '<')
1358                         {
1359                             sSymbol += cToken;
1360                             cLetter = ' ';
1361                             eState = SsStop;
1362                             eSymbolType = NUMBERFORMAT_OP_NE;
1363                         }
1364                         else
1365                         {
1366                             eState = SsStop;
1367                             eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1368                         }
1369                     }
1370                     break;
1371                     case '=':
1372                     {
1373                         if (cLetter == '<')
1374                         {
1375                             sSymbol += cToken;
1376                             cLetter = ' ';
1377                             eSymbolType = NUMBERFORMAT_OP_LE;
1378                         }
1379                         else if (cLetter == '>')
1380                         {
1381                             sSymbol += cToken;
1382                             cLetter = ' ';
1383                             eSymbolType = NUMBERFORMAT_OP_GE;
1384                         }
1385                         else
1386                         {
1387                             eState = SsStop;
1388                             eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1389                         }
1390                     }
1391                     break;
1392                     case ' ':
1393                     {
1394                         rString.Erase(nPos-1,1);
1395                         nPos--;
1396                         nLen--;
1397                     }
1398                     break;
1399                     default:
1400                     {
1401                         eState = SsStop;
1402                         nPos--;
1403                     }
1404                     break;
1405                 }
1406             }
1407             break;
1408             case SsGetPrefix:
1409             {
1410                 if (cToken == ']')
1411                     eState = SsStop;
1412                 else
1413                     sSymbol += cToken;
1414             }
1415             break;
1416             default:
1417             break;
1418         }                                   // of switch
1419     }                                       // of while
1420 
1421     return eSymbolType;
1422 }
1423 
1424 NfHackConversion SvNumberformat::Load( SvStream& rStream,
1425         ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter,
1426         ImpSvNumberInputScan& rISc )
1427 {
1428     rHdr.StartEntry();
1429     sal_uInt16 nOp1, nOp2;
1430     SvNumberformat::LoadString( rStream, sFormatstring );
1431     rStream >> eType >> fLimit1 >> fLimit2
1432             >> nOp1 >> nOp2 >> bStandard >> bIsUsed;
1433     NfHackConversion eHackConversion = NF_CONVERT_NONE;
1434     sal_Bool bOldConvert = sal_False;
1435     LanguageType eOldTmpLang = 0;
1436 	LanguageType eOldNewLang = 0;
1437     if ( pHackConverter )
1438     {   // werden nur hierbei gebraucht
1439         bOldConvert = rScan.GetConvertMode();
1440         eOldTmpLang = rScan.GetTmpLnge();
1441         eOldNewLang = rScan.GetNewLnge();
1442     }
1443     String aLoadedColorName;
1444     for (sal_uInt16 i = 0; i < 4; i++)
1445     {
1446         NumFor[i].Load( rStream, rScan, aLoadedColorName );
1447         if ( pHackConverter && eHackConversion == NF_CONVERT_NONE )
1448         {
1449             //! HACK! ER 29.07.97 13:52
1450             // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/
1451             // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert..
1452             // System-German FARBE nach System-xxx COLOR umsetzen und vice versa,
1453             //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in
1454             //! ImpSvNumberformatScan existierten
1455             if ( aLoadedColorName.Len() && !NumFor[i].GetColor()
1456                     && aLoadedColorName != rScan.GetColorString() )
1457             {
1458                 if ( rScan.GetColorString().EqualsAscii( "FARBE" ) )
1459                 {   // English -> German
1460                     eHackConversion = NF_CONVERT_ENGLISH_GERMAN;
1461                     rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US );
1462                     rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN );
1463                 }
1464                 else
1465                 {   // German -> English
1466                     eHackConversion = NF_CONVERT_GERMAN_ENGLISH;
1467                     rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN );
1468                     rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US );
1469                 }
1470                 String aColorName = NumFor[i].GetColorName();
1471                 const Color* pColor = rScan.GetColor( aColorName );
1472                 if ( !pColor && aLoadedColorName == aColorName )
1473                     eHackConversion = NF_CONVERT_NONE;
1474                 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM );
1475                 rScan.SetConvertMode( eOldTmpLang, eOldNewLang );
1476                 rScan.SetConvertMode( bOldConvert );
1477             }
1478         }
1479     }
1480     eOp1 = (SvNumberformatLimitOps) nOp1;
1481     eOp2 = (SvNumberformatLimitOps) nOp2;
1482     String aComment;        // wird nach dem NewCurrency-Geraffel richtig gesetzt
1483     if ( rHdr.BytesLeft() )
1484     {   // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
1485         SvNumberformat::LoadString( rStream, aComment );
1486         rStream >> nNewStandardDefined;
1487     }
1488 
1489     xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND;
1490     sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic &&
1491         (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND );
1492     sal_Bool bNewCurrencyLoaded = sal_False;
1493     sal_Bool bNewCurrency = sal_False;
1494 
1495     sal_Bool bGoOn = sal_True;
1496     while ( rHdr.BytesLeft() && bGoOn )
1497     {   // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1498         sal_uInt16 nId;
1499         rStream >> nId;
1500         switch ( nId )
1501         {
1502             case nNewCurrencyVersionId :
1503             {
1504                 bNewCurrencyLoaded = sal_True;
1505                 rStream >> bNewCurrency;
1506                 if ( bNewCurrency )
1507                 {
1508                     for ( sal_uInt16 j=0; j<4; j++ )
1509                     {
1510                         NumFor[j].LoadNewCurrencyMap( rStream );
1511                     }
1512                 }
1513             }
1514             break;
1515             case nNewStandardFlagVersionId :
1516                 rStream >> bStandard;   // the real standard flag
1517             break;
1518             default:
1519                 DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" );
1520                 bGoOn = sal_False;  // stop reading unknown stream left over of newer versions
1521                 // Would be nice to have multiple read/write headers instead
1522                 // but old versions wouldn't know it, TLOT.
1523         }
1524     }
1525     rHdr.EndEntry();
1526 
1527     if ( bNewCurrencyLoaded )
1528     {
1529         if ( bNewCurrency && bNewCurrencyComment )
1530         {   // original Formatstring und Kommentar wiederherstellen
1531             sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
1532             aComment.Erase( 0, nNewCurrencyEnd+1 );
1533         }
1534     }
1535     else if ( bNewCurrencyComment )
1536     {   // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert
1537         // original Formatstring und Kommentar wiederherstellen
1538         sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
1539         aComment.Erase( 0, nNewCurrencyEnd+1 );
1540         // Zustaende merken
1541         short nDefined = ( eType & NUMBERFORMAT_DEFINED );
1542         sal_uInt16 nNewStandard = nNewStandardDefined;
1543         // neu parsen etc.
1544         String aStr( sFormatstring );
1545         xub_StrLen nCheckPos = 0;
1546         SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc,
1547             nCheckPos, eLnge, bStandard );
1548         DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" );
1549         ImpCopyNumberformat( *pFormat );
1550         delete pFormat;
1551         // Zustaende wiederherstellen
1552         eType |= nDefined;
1553         if ( nNewStandard )
1554             SetNewStandardDefined( nNewStandard );
1555     }
1556     SetComment( aComment );
1557 
1558     if ( eHackConversion != NF_CONVERT_NONE )
1559     {   //! und weiter mit dem HACK!
1560         switch ( eHackConversion )
1561         {
1562             case NF_CONVERT_ENGLISH_GERMAN :
1563                 ConvertLanguage( *pHackConverter,
1564                     LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, sal_True );
1565             break;
1566             case NF_CONVERT_GERMAN_ENGLISH :
1567                 ConvertLanguage( *pHackConverter,
1568                     LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True );
1569             break;
1570             default:
1571                 DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" );
1572         }
1573     }
1574     return eHackConversion;
1575 }
1576 
1577 void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
1578         LanguageType eConvertFrom, LanguageType eConvertTo, sal_Bool bSystem )
1579 {
1580     xub_StrLen nCheckPos;
1581     sal_uInt32 nKey;
1582     short nType = eType;
1583     String aFormatString( sFormatstring );
1584     if ( bSystem )
1585         rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
1586             nKey, eConvertFrom, eConvertTo );
1587     else
1588         rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType,
1589             nKey, eConvertFrom, eConvertTo );
1590     const SvNumberformat* pFormat = rConverter.GetEntry( nKey );
1591     DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
1592     if ( pFormat )
1593     {
1594         ImpCopyNumberformat( *pFormat );
1595         // aus Formatter/Scanner uebernommene Werte zuruecksetzen
1596         if ( bSystem )
1597             eLnge = LANGUAGE_SYSTEM;
1598         // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner
1599         for ( sal_uInt16 i = 0; i < 4; i++ )
1600         {
1601             String aColorName = NumFor[i].GetColorName();
1602             Color* pColor = rScan.GetColor( aColorName );
1603             NumFor[i].SetColor( pColor, aColorName );
1604         }
1605     }
1606 }
1607 
1608 
1609 // static
1610 void SvNumberformat::LoadString( SvStream& rStream, String& rStr )
1611 {
1612     CharSet eStream = rStream.GetStreamCharSet();
1613     ByteString aStr;
1614     rStream.ReadByteString( aStr );
1615     sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream );
1616     if ( aStr.Search( cStream ) == STRING_NOTFOUND )
1617     {   // simple conversion to unicode
1618         rStr = UniString( aStr, eStream );
1619     }
1620     else
1621     {
1622         sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol();
1623         register const sal_Char* p = aStr.GetBuffer();
1624         register const sal_Char* const pEnd = p + aStr.Len();
1625         register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() );
1626         while ( p < pEnd )
1627         {
1628             if ( *p == cStream )
1629                 *pUni = cTarget;
1630             else
1631                 *pUni = ByteString::ConvertToUnicode( *p, eStream );
1632             p++;
1633             pUni++;
1634         }
1635         *pUni = 0;
1636     }
1637 }
1638 
1639 
1640 void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const
1641 {
1642     String aFormatstring( sFormatstring );
1643     String aComment( sComment );
1644 #if NF_COMMENT_IN_FORMATSTRING
1645     // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen
1646     // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung
1647     // (z.B. im Dialog) zu ermoeglichen
1648     SetComment( "", aFormatstring, aComment );
1649 #endif
1650 
1651     sal_Bool bNewCurrency = HasNewCurrency();
1652     if ( bNewCurrency )
1653     {   // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern
1654         aComment.Insert( cNewCurrencyMagic, 0 );
1655         aComment.Insert( cNewCurrencyMagic, 0 );
1656         aComment.Insert( aFormatstring, 1 );
1657         Build50Formatstring( aFormatstring );       // alten Formatstring generieren
1658     }
1659 
1660     // old SO5 versions do behave strange (no output) if standard flag is set
1661     // on formats not prepared for it (not having the following exact types)
1662     sal_Bool bOldStandard = bStandard;
1663     if ( bOldStandard )
1664     {
1665         switch ( eType )
1666         {
1667             case NUMBERFORMAT_NUMBER :
1668             case NUMBERFORMAT_DATE :
1669             case NUMBERFORMAT_TIME :
1670             case NUMBERFORMAT_DATETIME :
1671             case NUMBERFORMAT_PERCENT :
1672             case NUMBERFORMAT_SCIENTIFIC :
1673                 // ok to save
1674             break;
1675             default:
1676                 bOldStandard = sal_False;
1677         }
1678     }
1679 
1680     rHdr.StartEntry();
1681     rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() );
1682     rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2
1683             << bOldStandard << bIsUsed;
1684     for (sal_uInt16 i = 0; i < 4; i++)
1685         NumFor[i].Save(rStream);
1686     // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
1687     rStream.WriteByteString( aComment, rStream.GetStreamCharSet() );
1688     rStream << nNewStandardDefined;
1689     // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
1690     rStream << nNewCurrencyVersionId;
1691     rStream << bNewCurrency;
1692     if ( bNewCurrency )
1693     {
1694         for ( sal_uInt16 j=0; j<4; j++ )
1695         {
1696             NumFor[j].SaveNewCurrencyMap( rStream );
1697         }
1698     }
1699 
1700     // the real standard flag to load with versions >638 if different
1701     if ( bStandard != bOldStandard )
1702     {
1703         rStream << nNewStandardFlagVersionId;
1704         rStream << bStandard;
1705     }
1706 
1707     rHdr.EndEntry();
1708 }
1709 
1710 
1711 sal_Bool SvNumberformat::HasNewCurrency() const
1712 {
1713     for ( sal_uInt16 j=0; j<4; j++ )
1714     {
1715         if ( NumFor[j].HasNewCurrency() )
1716             return sal_True;
1717     }
1718     return sal_False;
1719 }
1720 
1721 
1722 sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol,
1723             String& rExtension ) const
1724 {
1725     for ( sal_uInt16 j=0; j<4; j++ )
1726     {
1727         if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
1728             return sal_True;
1729     }
1730     rSymbol.Erase();
1731     rExtension.Erase();
1732     return sal_False;
1733 }
1734 
1735 
1736 // static
1737 String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr,
1738             sal_Bool bQuoteSymbol )
1739 {
1740     String aTmp;
1741     xub_StrLen nStartPos, nPos, nLen;
1742     nLen = rStr.Len();
1743     nStartPos = 0;
1744     while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND )
1745     {
1746         xub_StrLen nEnd;
1747         if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen )
1748         {
1749             aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos );
1750             nStartPos = nEnd;
1751         }
1752         else
1753         {
1754             aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1755             nStartPos = nPos + 2;
1756             xub_StrLen nDash;
1757             nEnd = nStartPos - 1;
1758             do
1759             {
1760                 nDash = rStr.Search( '-', ++nEnd );
1761             } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen );
1762             xub_StrLen nClose;
1763             nEnd = nStartPos - 1;
1764             do
1765             {
1766                 nClose = rStr.Search( ']', ++nEnd );
1767             } while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen );
1768             nPos = ( nDash < nClose ? nDash : nClose );
1769             if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' )
1770                 aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1771             else
1772             {
1773                 aTmp += '"';
1774                 aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
1775                 aTmp += '"';
1776             }
1777             nStartPos = nClose + 1;
1778         }
1779     }
1780     if ( nLen > nStartPos )
1781         aTmp += rStr.Copy( nStartPos, nLen - nStartPos );
1782     return aTmp;
1783 }
1784 
1785 
1786 void SvNumberformat::Build50Formatstring( String& rStr ) const
1787 {
1788     rStr = StripNewCurrencyDelimiters( sFormatstring, sal_True );
1789 }
1790 
1791 
1792 void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString)
1793 {
1794     sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
1795 
1796     if ( fabs(fNumber) > 1.0E15 )       // #58531# war E16
1797     {
1798         nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
1799         OutString = ::rtl::math::doubleToUString( fNumber,
1800                 rtl_math_StringFormat_E, nStandardPrec /*2*/,
1801                 GetFormatter().GetNumDecimalSep().GetChar(0));
1802     }
1803     else
1804         ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec);
1805 }
1806 
1807 void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const
1808 {
1809     // Make sure the precision doesn't go over the maximum allowable precision.
1810     nPrecision = ::std::min(UPPER_PRECISION, nPrecision);
1811 
1812 #if 0
1813 {
1814     // debugger test case for ANSI standard correctness
1815     ::rtl::OUString aTest;
1816     // expect 0.00123   OK
1817     aTest = ::rtl::math::doubleToUString( 0.001234567,
1818             rtl_math_StringFormat_G, 3, '.', sal_True );
1819     // expect 123       OK
1820     aTest = ::rtl::math::doubleToUString( 123.4567,
1821             rtl_math_StringFormat_G, 3, '.', sal_True );
1822     // expect 123.5     OK
1823     aTest = ::rtl::math::doubleToUString( 123.4567,
1824             rtl_math_StringFormat_G, 4, '.', sal_True );
1825     // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
1826     // 1000 with an exponent equal to significant digits)
1827     // Currently (24-Jan-2003) we do fail in this case and output 1000
1828     // instead, negligible.
1829     aTest = ::rtl::math::doubleToUString( 999.6,
1830             rtl_math_StringFormat_G, 3, '.', sal_True );
1831     // expect what? result is 1.2e+004
1832     aTest = ::rtl::math::doubleToUString( 12345.6789,
1833             rtl_math_StringFormat_G, -3, '.', sal_True );
1834 }
1835 #endif
1836 
1837     // We decided to strip trailing zeros unconditionally, since binary
1838     // double-precision rounding error makes it impossible to determine e.g.
1839     // whether 844.10000000000002273737 is what the user has typed, or the
1840     // user has typed 844.1 but IEEE 754 represents it that way internally.
1841 
1842     rOutString = ::rtl::math::doubleToUString( rNumber,
1843             rtl_math_StringFormat_F, nPrecision /*2*/,
1844             GetFormatter().GetNumDecimalSep().GetChar(0), true );
1845     if (rOutString.GetChar(0) == '-' &&
1846         rOutString.GetTokenCount('0') == rOutString.Len())
1847         rOutString.EraseLeadingChars('-');            // nicht -0
1848 
1849     ImpTransliterate( rOutString, NumFor[0].GetNatNum() );
1850 }
1851 
1852 void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
1853 {
1854     sal_Bool bModified = sal_False;
1855     if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
1856     {
1857         if (fNumber == 0.0)
1858         {
1859             OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) );
1860             return;
1861         }
1862         fNumber *= 100;
1863         bModified = sal_True;
1864     }
1865 
1866     if (fNumber == 0.0)
1867     {
1868         OutString = '0';
1869         return;
1870     }
1871 
1872     OutString = ::rtl::math::doubleToUString( fNumber,
1873             rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
1874             GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
1875 
1876     if ( eType & NUMBERFORMAT_PERCENT && bModified)
1877         OutString += '%';
1878     return;
1879 }
1880 
1881 short SvNumberformat::ImpCheckCondition(double& fNumber,
1882                                      double& fLimit,
1883                                      SvNumberformatLimitOps eOp)
1884 {
1885     switch(eOp)
1886     {
1887         case NUMBERFORMAT_OP_NO: return -1;
1888         case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit);
1889         case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit);
1890         case NUMBERFORMAT_OP_LT: return (short) (fNumber <  fLimit);
1891         case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit);
1892         case NUMBERFORMAT_OP_GT: return (short) (fNumber >  fLimit);
1893         case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit);
1894         default: return -1;
1895     }
1896 }
1897 
1898 sal_Bool SvNumberformat::GetOutputString(String& sString,
1899                                      String& OutString,
1900                                      Color** ppColor)
1901 {
1902     OutString.Erase();
1903     sal_uInt16 nIx;
1904     if (eType & NUMBERFORMAT_TEXT)
1905         nIx = 0;
1906     else if (NumFor[3].GetnAnz() > 0)
1907         nIx = 3;
1908     else
1909     {
1910         *ppColor = NULL;        // no change of color
1911         return sal_False;
1912     }
1913     *ppColor = NumFor[nIx].GetColor();
1914     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
1915     if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
1916     {
1917         sal_Bool bRes = sal_False;
1918         const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
1919         for (sal_uInt16 i = 0; i < nAnz; i++)
1920         {
1921             switch (rInfo.nTypeArray[i])
1922             {
1923                 case NF_SYMBOLTYPE_STAR:
1924                     if( bStarFlag )
1925                     {
1926                         OutString += (sal_Unicode) 0x1B;
1927                         OutString += rInfo.sStrArray[i].GetChar(1);
1928                         bRes = sal_True;
1929                     }
1930                 break;
1931                 case NF_SYMBOLTYPE_BLANK:
1932                     InsertBlanks( OutString, OutString.Len(),
1933                         rInfo.sStrArray[i].GetChar(1) );
1934                 break;
1935                 case NF_KEY_GENERAL :   // #77026# "General" is the same as "@"
1936                 case NF_SYMBOLTYPE_DEL :
1937                     OutString += sString;
1938                 break;
1939                 default:
1940                     OutString += rInfo.sStrArray[i];
1941             }
1942         }
1943         return bRes;
1944     }
1945     return sal_False;
1946 }
1947 /*
1948 void SvNumberformat::GetNextFareyNumber(sal_uLong nPrec, sal_uLong x0, sal_uLong x1,
1949                                         sal_uLong y0, sal_uLong y1,
1950                                         sal_uLong& x2,sal_uLong& y2)
1951 {
1952     x2 = ((y0+nPrec)/y1)*x1 - x0;
1953     y2 = ((y0+nPrec)/y1)*y1 - y0;
1954 }
1955 */
1956 sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y)
1957 {
1958     if (y == 0)
1959         return x;
1960     else
1961     {
1962         sal_uLong z = x%y;
1963         while (z)
1964         {
1965             x = y;
1966             y = z;
1967             z = x%y;
1968         }
1969         return y;
1970     }
1971 }
1972 
1973 sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y)
1974 {
1975     if (y == 0)
1976         return x;
1977     else
1978     {
1979         sal_uLong z = x%y;
1980         while ((double)z/(double)y > D_EPS)
1981         {
1982             x = y;
1983             y = z;
1984             z = x%y;
1985         }
1986         return y;
1987     }
1988 }
1989 
1990 namespace {
1991 
1992 void lcl_GetOutputStringScientific(
1993     double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString)
1994 {
1995     bool bSign = ::rtl::math::isSignBitSet(fNumber);
1996 
1997     // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7).
1998     sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0;
1999     if (nPrec && bSign)
2000         // Make room for the negative sign.
2001         --nPrec;
2002 
2003     nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals.
2004 
2005     rOutString = ::rtl::math::doubleToUString(
2006         fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0));
2007 }
2008 
2009 }
2010 
2011 bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const
2012 {
2013     using namespace std;
2014 
2015     if (eType != NUMBERFORMAT_NUMBER)
2016         return false;
2017 
2018     double fTestNum = fNumber;
2019     bool bSign = ::rtl::math::isSignBitSet(fTestNum);
2020     if (bSign)
2021         fTestNum = -fTestNum;
2022 
2023     if (fTestNum < EXP_LOWER_BOUND)
2024     {
2025         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2026         return true;
2027     }
2028 
2029     double fExp = log10(fTestNum);
2030     // Values < 1.0 always have one digit before the decimal point.
2031     sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1;
2032 
2033     if (nDigitPre > 15)
2034     {
2035         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2036         return true;
2037     }
2038 
2039     sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0;
2040     if (nPrec && bSign)
2041         // Subtract the negative sign.
2042         --nPrec;
2043     if (nPrec)
2044         // Subtract the decimal point.
2045         --nPrec;
2046 
2047     ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec);
2048     if (rOutString.Len() > nCharCount)
2049         // String still wider than desired.  Switch to scientific notation.
2050         lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2051 
2052     return true;
2053 }
2054 
2055 sal_Bool SvNumberformat::GetOutputString(double fNumber,
2056                                      String& OutString,
2057                                      Color** ppColor)
2058 {
2059     sal_Bool bRes = sal_False;
2060     OutString.Erase();                          // alles loeschen
2061     *ppColor = NULL;                            // keine Farbaenderung
2062     if (eType & NUMBERFORMAT_LOGICAL)
2063     {
2064         if (fNumber)
2065             OutString = rScan.GetTrueString();
2066         else
2067             OutString = rScan.GetFalseString();
2068         return sal_False;
2069     }
2070     if (eType & NUMBERFORMAT_TEXT)
2071     {
2072         ImpGetOutputStandard(fNumber, OutString);
2073         return sal_False;
2074     }
2075     sal_Bool bHadStandard = sal_False;
2076     if (bStandard)                              // einzelne Standardformate
2077     {
2078         if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION)     // alle Zahlformate InputLine
2079         {
2080             ImpGetOutputInputLine(fNumber, OutString);
2081             return false;
2082         }
2083         switch (eType)
2084         {
2085             case NUMBERFORMAT_NUMBER:                   // Standardzahlformat
2086             {
2087                 if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION)
2088                 {
2089                     bool bSign = ::rtl::math::isSignBitSet(fNumber);
2090                     if (bSign)
2091                         fNumber = -fNumber;
2092                     ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format.
2093                     if (fNumber < EXP_LOWER_BOUND)
2094                     {
2095                         xub_StrLen nLen = OutString.Len();
2096                         if (!nLen)
2097                             return false;
2098 
2099                         // #i112250# With the 10-decimal limit, small numbers are formatted as "0".
2100                         // Switch to scientific in that case, too:
2101                         if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0))
2102                         {
2103                             sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
2104                             nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
2105                             OutString = ::rtl::math::doubleToUString( fNumber,
2106                                     rtl_math_StringFormat_E, nStandardPrec /*2*/,
2107                                     GetFormatter().GetNumDecimalSep().GetChar(0), true);
2108                         }
2109                     }
2110                     if (bSign)
2111                         OutString.Insert('-', 0);
2112                     return false;
2113                 }
2114                 ImpGetOutputStandard(fNumber, OutString);
2115                 bHadStandard = sal_True;
2116             }
2117             break;
2118             case NUMBERFORMAT_DATE:
2119                 bRes |= ImpGetDateOutput(fNumber, 0, OutString);
2120                 bHadStandard = sal_True;
2121             break;
2122             case NUMBERFORMAT_TIME:
2123                 bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
2124                 bHadStandard = sal_True;
2125             break;
2126             case NUMBERFORMAT_DATETIME:
2127                 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
2128                 bHadStandard = sal_True;
2129             break;
2130         }
2131     }
2132     if ( !bHadStandard )
2133     {
2134         sal_uInt16 nIx;                             // Index des Teilformats
2135         short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
2136         if (nCheck == -1 || nCheck == 1)            // nur 1 String oder True
2137             nIx = 0;
2138         else
2139         {
2140             nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
2141             if (nCheck == -1 || nCheck == 1)
2142                 nIx = 1;
2143             else
2144                 nIx = 2;
2145         }
2146         if (nIx == 1 &&          // negatives Format
2147                 IsNegativeRealNegative() && fNumber < 0.0)      // ohne Vorzeichen
2148             fNumber = -fNumber;                 // Vorzeichen eliminieren
2149 		if(nIx == 0 &&
2150 				IsNegativeRealNegative2() && fNumber < 0.0)
2151 			fNumber = -fNumber;
2152         *ppColor = NumFor[nIx].GetColor();
2153         const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2154         const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
2155         if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
2156             return sal_False;                       // leer => nichts
2157         else if (nAnz == 0)                     // sonst Standard-Format
2158         {
2159             ImpGetOutputStandard(fNumber, OutString);
2160             return sal_False;
2161         }
2162         switch (rInfo.eScannedType)
2163         {
2164             case NUMBERFORMAT_TEXT:
2165             case NUMBERFORMAT_DEFINED:
2166             {
2167                 for (sal_uInt16 i = 0; i < nAnz; i++)
2168                 {
2169                     switch (rInfo.nTypeArray[i])
2170                     {
2171                         case NF_SYMBOLTYPE_STAR:
2172                             if( bStarFlag )
2173                             {
2174                                 OutString += (sal_Unicode) 0x1B;
2175                                 OutString += rInfo.sStrArray[i].GetChar(1);
2176                                 bRes = sal_True;
2177                             }
2178                             break;
2179                         case NF_SYMBOLTYPE_BLANK:
2180                             InsertBlanks( OutString, OutString.Len(),
2181                                 rInfo.sStrArray[i].GetChar(1) );
2182                             break;
2183                         case NF_SYMBOLTYPE_STRING:
2184                         case NF_SYMBOLTYPE_CURRENCY:
2185                             OutString += rInfo.sStrArray[i];
2186                             break;
2187                         case NF_SYMBOLTYPE_THSEP:
2188                             if (rInfo.nThousand == 0)
2189                                 OutString += rInfo.sStrArray[i];
2190                         break;
2191                         default:
2192                         break;
2193                     }
2194                 }
2195             }
2196             break;
2197             case NUMBERFORMAT_DATE:
2198                 bRes |= ImpGetDateOutput(fNumber, nIx, OutString);
2199             break;
2200             case NUMBERFORMAT_TIME:
2201                 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString);
2202             break;
2203             case NUMBERFORMAT_DATETIME:
2204                 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString);
2205             break;
2206             case NUMBERFORMAT_NUMBER:
2207             case NUMBERFORMAT_PERCENT:
2208             case NUMBERFORMAT_CURRENCY:
2209                 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString);
2210             break;
2211             case NUMBERFORMAT_FRACTION:
2212             {
2213                 String sStr, sFrac, sDiv;               // Strings, Wert fuer
2214                 sal_uLong nFrac, nDiv;                      // Vorkommaanteil
2215                                                         // Zaehler und Nenner
2216                 sal_Bool bSign = sal_False;
2217                 if (fNumber < 0)
2218                 {
2219                     if (nIx == 0)                       // nicht in hinteren
2220                         bSign = sal_True;                   // Formaten
2221                     fNumber = -fNumber;
2222                 }
2223                 double fNum = floor(fNumber);           // Vorkommateil
2224                 fNumber -= fNum;                        // Nachkommateil
2225                 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9)
2226                                                         // zu gross
2227                 {
2228                     OutString = rScan.GetErrorString();
2229                     return sal_False;
2230                 }
2231                 if (rInfo.nCntExp == 0)
2232                 {
2233                     DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
2234                     return sal_False;
2235                 }
2236                 sal_uLong nBasis = ((sal_uLong)floor(           // 9, 99, 999 ,...
2237                                     pow(10.0,rInfo.nCntExp))) - 1;
2238                 sal_uLong x0, y0, x1, y1;
2239 
2240                 if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
2241                 {
2242                     sal_Bool bUpperHalf;
2243                     if (fNumber > 0.5)
2244                     {
2245                         bUpperHalf = sal_True;
2246                         fNumber -= (fNumber - 0.5) * 2.0;
2247                     }
2248                     else
2249                         bUpperHalf = sal_False;
2250                                                     // Einstieg in Farey-Serie
2251                                                     // finden:
2252                     x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9
2253                     if (x0 == 0)                        //      => x0 = 2
2254                     {
2255                         y0 = 1;
2256                         x1 = 1;
2257                         y1 = nBasis;
2258                     }
2259                     else if (x0 == (nBasis-1)/2)    // (b-1)/2, 1/2
2260                     {                               // geht (nBasis ungerade)
2261                         y0 = nBasis;
2262                         x1 = 1;
2263                         y1 = 2;
2264                     }
2265                     else if (x0 == 1)
2266                     {
2267                         y0 = nBasis;                    //  1/n; 1/(n-1)
2268                         x1 = 1;
2269                         y1 = nBasis - 1;
2270                     }
2271                     else
2272                     {
2273                         y0 = nBasis;                    // z.B. 2/9   2/8
2274                         x1 = x0;
2275                         y1 = nBasis - 1;
2276                         double fUg = (double) x0 / (double) y0;
2277                         double fOg = (double) x1 / (double) y1;
2278                         sal_uLong nGgt = ImpGGT(y0, x0);       // x0/y0 kuerzen
2279                         x0 /= nGgt;
2280                         y0 /= nGgt;                     // Einschachteln:
2281                         sal_uLong x2 = 0;
2282                         sal_uLong y2 = 0;
2283                         sal_Bool bStop = sal_False;
2284                         while (!bStop)
2285                         {
2286 #ifdef GCC
2287                             // #i21648# GCC over-optimizes something resulting
2288                             // in wrong fTest values throughout the loops.
2289                             volatile
2290 #endif
2291                                 double fTest = (double)x1/(double)y1;
2292                             while (!bStop)
2293                             {
2294                                 while (fTest > fOg)
2295                                 {
2296                                     x1--;
2297                                     fTest = (double)x1/(double)y1;
2298                                 }
2299                                 while (fTest < fUg && y1 > 1)
2300                                 {
2301                                     y1--;
2302                                     fTest = (double)x1/(double)y1;
2303                                 }
2304                                 if (fTest <= fOg)
2305                                 {
2306                                     fOg = fTest;
2307                                     bStop = sal_True;
2308                                 }
2309                                 else if (y1 == 1)
2310                                     bStop = sal_True;
2311                             }                               // of while
2312                             nGgt = ImpGGT(y1, x1);             // x1/y1 kuerzen
2313                             x2 = x1 / nGgt;
2314                             y2 = y1 / nGgt;
2315                             if (x2*y0 - x0*y2 == 1 || y1 <= 1)  // Test, ob x2/y2
2316                                 bStop = sal_True;               // naechste Farey-Zahl
2317                             else
2318                             {
2319                                 y1--;
2320                                 bStop = sal_False;
2321                             }
2322                         }                                   // of while
2323                         x1 = x2;
2324                         y1 = y2;
2325                     }                                       // of else
2326                     double fup, flow;
2327                     flow = (double)x0/(double)y0;
2328                     fup  = (double)x1/(double)y1;
2329                     while (fNumber > fup)
2330                     {
2331                         sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
2332                         sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0;
2333 //                      GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
2334                         x0 = x1;
2335                         y0 = y1;
2336                         x1 = x2;
2337                         y1 = y2;
2338                         flow = fup;
2339                         fup  = (double)x1/(double)y1;
2340                     }
2341                     if (fNumber - flow < fup - fNumber)
2342                     {
2343                         nFrac = x0;
2344                         nDiv  = y0;
2345                     }
2346                     else
2347                     {
2348                         nFrac = x1;
2349                         nDiv  = y1;
2350                     }
2351                     if (bUpperHalf)                     // Original restaur.
2352                     {
2353                         if (nFrac == 0 && nDiv == 1)    // 1/1
2354                             fNum += 1.0;
2355                         else
2356                             nFrac = nDiv - nFrac;
2357                     }
2358                 }
2359                 else                                    // grosse Nenner
2360                 {                                       // 0,1234->123/1000
2361                     sal_uLong nGgt;
2362 /*
2363                     nDiv = nBasis+1;
2364                     nFrac = ((sal_uLong)floor(0.5 + fNumber *
2365                                     pow(10.0,rInfo.nCntExp)));
2366 */
2367                     nDiv = 10000000;
2368                     nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0));
2369                     nGgt = ImpGGT(nDiv, nFrac);
2370                     if (nGgt > 1)
2371                     {
2372                         nDiv  /= nGgt;
2373                         nFrac /= nGgt;
2374                     }
2375                     if (nDiv > nBasis)
2376                     {
2377                         nGgt = ImpGGTRound(nDiv, nFrac);
2378                         if (nGgt > 1)
2379                         {
2380                             nDiv  /= nGgt;
2381                             nFrac /= nGgt;
2382                         }
2383                     }
2384                     if (nDiv > nBasis)
2385                     {
2386                         nDiv = nBasis;
2387                         nFrac = ((sal_uLong)floor(0.5 + fNumber *
2388                                     pow(10.0,rInfo.nCntExp)));
2389                         nGgt = ImpGGTRound(nDiv, nFrac);
2390                         if (nGgt > 1)
2391                         {
2392                             nDiv  /= nGgt;
2393                             nFrac /= nGgt;
2394                         }
2395                     }
2396                 }
2397 
2398                 if (rInfo.nCntPre == 0)    // unechter Bruch
2399                 {
2400                     double fNum1 = fNum * (double)nDiv + (double)nFrac;
2401                     if (fNum1 > _D_MAX_U_LONG_)
2402                     {
2403                         OutString = rScan.GetErrorString();
2404                         return sal_False;
2405                     }
2406                     nFrac = (sal_uLong) floor(fNum1);
2407                     sStr.Erase();
2408                 }
2409                 else if (fNum == 0.0 && nFrac != 0)
2410                     sStr.Erase();
2411                 else
2412                 {
2413                     char aBuf[100];
2414                     sprintf( aBuf, "%.f", fNum );   // simple rounded integer (#100211# - checked)
2415                     sStr.AssignAscii( aBuf );
2416                     ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
2417                 }
2418                 if (rInfo.nCntPre > 0 && nFrac == 0)
2419                 {
2420                     sFrac.Erase();
2421                     sDiv.Erase();
2422                 }
2423                 else
2424                 {
2425                     sFrac = ImpIntToString( nIx, nFrac );
2426                     sDiv = ImpIntToString( nIx, nDiv );
2427                 }
2428 
2429                 sal_uInt16 j = nAnz-1;                  // letztes Symbol->rueckw.
2430                 xub_StrLen k;                       // Nenner:
2431                 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
2432                 sal_Bool bCont = sal_True;
2433                 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
2434                 {
2435                     if (rInfo.nCntPre > 0 && nFrac == 0)
2436                         sDiv.Insert(' ',0);
2437                     else
2438                         sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 );
2439                     if ( j )
2440                         j--;
2441                     else
2442                         bCont = sal_False;
2443                 }
2444                                                     // weiter Zaehler:
2445                 if ( !bCont )
2446                     sFrac.Erase();
2447                 else
2448                 {
2449                     bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
2450                     if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
2451                     {
2452                         sFrac.Insert(rInfo.sStrArray[j],0);
2453                         if ( j )
2454                             j--;
2455                         else
2456                             bCont = sal_False;
2457                     }
2458                 }
2459                                                     // weiter Hauptzahl
2460                 if ( !bCont )
2461                     sStr.Erase();
2462                 else
2463                 {
2464                     k = sStr.Len();                 // hinter letzter Ziffer
2465                     bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
2466                                             rInfo.nCntPre);
2467                 }
2468                 if (bSign && !(nFrac == 0 && fNum == 0.0))
2469                     OutString.Insert('-',0);        // nicht -0
2470                 OutString += sStr;
2471                 OutString += sFrac;
2472                 OutString += sDiv;
2473             }
2474             break;
2475             case NUMBERFORMAT_SCIENTIFIC:
2476             {
2477                 sal_Bool bSign = sal_False;
2478                 if (fNumber < 0)
2479                 {
2480                     if (nIx == 0)                       // nicht in hinteren
2481                         bSign = sal_True;                   // Formaten
2482                     fNumber = -fNumber;
2483                 }
2484                 String sStr( ::rtl::math::doubleToUString( fNumber,
2485                             rtl_math_StringFormat_E,
2486                             rInfo.nCntPre + rInfo.nCntPost - 1, '.' ));
2487 
2488                 String ExpStr;
2489                 short nExpSign = 1;
2490                 xub_StrLen nExPos = sStr.Search('E');
2491                 if ( nExPos != STRING_NOTFOUND )
2492                 {
2493                     // split into mantisse and exponent and get rid of "E+" or "E-"
2494                     xub_StrLen nExpStart = nExPos + 1;
2495                     switch ( sStr.GetChar( nExpStart ) )
2496                     {
2497                         case '-' :
2498                             nExpSign = -1;
2499                             // fallthru
2500                         case '+' :
2501                             ++nExpStart;
2502                         break;
2503                     }
2504                     ExpStr = sStr.Copy( nExpStart );    // part following the "E+"
2505                     sStr.Erase( nExPos );
2506                     sStr.EraseAllChars('.');        // cut any decimal delimiter
2507                     if ( rInfo.nCntPre != 1 )       // rescale Exp
2508                     {
2509                         sal_Int32 nExp = ExpStr.ToInt32() * nExpSign;
2510                         nExp -= sal_Int32(rInfo.nCntPre)-1;
2511                         if ( nExp < 0 )
2512                         {
2513                             nExpSign = -1;
2514                             nExp = -nExp;
2515                         }
2516                         else
2517                             nExpSign = 1;
2518                         ExpStr = String::CreateFromInt32( nExp );
2519                     }
2520                 }
2521                 sal_uInt16 j = nAnz-1;                  // last symbol
2522                 xub_StrLen k;                       // position in ExpStr
2523                 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
2524 
2525                 xub_StrLen nZeros = 0;              // erase leading zeros
2526                 while (nZeros < k && ExpStr.GetChar(nZeros) == '0')
2527                     ++nZeros;
2528                 if (nZeros)
2529                     ExpStr.Erase( 0, nZeros);
2530 
2531                 sal_Bool bCont = sal_True;
2532                 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
2533                 {
2534                     const String& rStr = rInfo.sStrArray[j];
2535                     if (nExpSign == -1)
2536                         ExpStr.Insert('-',0);
2537                     else if (rStr.Len() > 1 && rStr.GetChar(1) == '+')
2538                         ExpStr.Insert('+',0);
2539                     ExpStr.Insert(rStr.GetChar(0),0);
2540                     if ( j )
2541                         j--;
2542                     else
2543                         bCont = sal_False;
2544                 }
2545                                                     // weiter Hauptzahl:
2546                 if ( !bCont )
2547                     sStr.Erase();
2548                 else
2549                 {
2550                     k = sStr.Len();                 // hinter letzter Ziffer
2551                     bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx,
2552                                             rInfo.nCntPre +
2553                                             rInfo.nCntPost);
2554                 }
2555                 if (bSign)
2556                     sStr.Insert('-',0);
2557                 OutString = sStr;
2558                 OutString += ExpStr;
2559             }
2560             break;
2561         }
2562     }
2563     return bRes;
2564 }
2565 
2566 sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber,
2567                                    sal_uInt16 nIx,
2568                                    String& OutString)
2569 {
2570     using namespace ::com::sun::star::i18n;
2571     sal_Bool bCalendarSet = sal_False;
2572     double fNumberOrig = fNumber;
2573     sal_Bool bRes = sal_False;
2574     sal_Bool bSign = sal_False;
2575     if (fNumber < 0.0)
2576     {
2577         fNumber = -fNumber;
2578         if (nIx == 0)
2579             bSign = sal_True;
2580     }
2581     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2582     if (rInfo.bThousand)       // []-Format
2583     {
2584         if (fNumber > 1.0E10)               // zu gross
2585         {
2586             OutString = rScan.GetErrorString();
2587             return sal_False;
2588         }
2589     }
2590     else
2591         fNumber -= floor(fNumber);          // sonst Datum abtrennen
2592     sal_Bool bInputLine;
2593     xub_StrLen nCntPost;
2594     if ( rScan.GetStandardPrec() == 300 &&
2595             0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
2596     {   // round at 7 decimals (+5 of 86400 == 12 significant digits)
2597         bInputLine = sal_True;
2598         nCntPost = 7;
2599     }
2600     else
2601     {
2602         bInputLine = sal_False;
2603         nCntPost = xub_StrLen(rInfo.nCntPost);
2604     }
2605     if (bSign && !rInfo.bThousand)     // kein []-Format
2606         fNumber = 1.0 - fNumber;        // "Kehrwert"
2607     double fTime = fNumber * 86400.0;
2608     fTime = ::rtl::math::round( fTime, int(nCntPost) );
2609     if (bSign && fTime == 0.0)
2610         bSign = sal_False;                      // nicht -00:00:00
2611 
2612     if( floor( fTime ) > _D_MAX_U_LONG_ )
2613     {
2614         OutString = rScan.GetErrorString();
2615         return sal_False;
2616     }
2617     sal_uLong nSeconds = (sal_uLong)floor( fTime );
2618 
2619     String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
2620                 rtl_math_StringFormat_F, int(nCntPost), '.'));
2621     sSecStr.EraseLeadingChars('0');
2622     sSecStr.EraseLeadingChars('.');
2623     if ( bInputLine )
2624     {
2625         sSecStr.EraseTrailingChars('0');
2626         if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
2627             sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
2628         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2629         nCntPost = sSecStr.Len();
2630     }
2631     else
2632         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
2633 
2634     xub_StrLen nSecPos = 0;                 // Zum Ziffernweisen
2635                                             // abarbeiten
2636     sal_uLong nHour, nMin, nSec;
2637     if (!rInfo.bThousand)      // kein [] Format
2638     {
2639         nHour = (nSeconds/3600) % 24;
2640         nMin = (nSeconds%3600) / 60;
2641         nSec = nSeconds%60;
2642     }
2643     else if (rInfo.nThousand == 3) // [ss]
2644     {
2645         nHour = 0;
2646         nMin = 0;
2647         nSec = nSeconds;
2648     }
2649     else if (rInfo.nThousand == 2) // [mm]:ss
2650     {
2651         nHour = 0;
2652         nMin = nSeconds / 60;
2653         nSec = nSeconds % 60;
2654     }
2655     else if (rInfo.nThousand == 1) // [hh]:mm:ss
2656     {
2657         nHour = nSeconds / 3600;
2658         nMin = (nSeconds%3600) / 60;
2659         nSec = nSeconds%60;
2660     }
2661 	else {
2662 		// TODO  What should these be set to?
2663 		nHour = 0;
2664 		nMin  = 0;
2665 		nSec  = 0;
2666 	}
2667 
2668     sal_Unicode cAmPm = ' ';                   // a oder p
2669     if (rInfo.nCntExp)     // AM/PM
2670     {
2671         if (nHour == 0)
2672         {
2673             nHour = 12;
2674             cAmPm = 'a';
2675         }
2676         else if (nHour < 12)
2677             cAmPm = 'a';
2678         else
2679         {
2680             cAmPm = 'p';
2681             if (nHour > 12)
2682                 nHour -= 12;
2683         }
2684     }
2685     const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
2686     for (sal_uInt16 i = 0; i < nAnz; i++)
2687     {
2688         switch (rInfo.nTypeArray[i])
2689         {
2690             case NF_SYMBOLTYPE_STAR:
2691                 if( bStarFlag )
2692                 {
2693                     OutString += (sal_Unicode) 0x1B;
2694                     OutString += rInfo.sStrArray[i].GetChar(1);
2695                     bRes = sal_True;
2696                 }
2697                 break;
2698             case NF_SYMBOLTYPE_BLANK:
2699                 InsertBlanks( OutString, OutString.Len(),
2700                     rInfo.sStrArray[i].GetChar(1) );
2701                 break;
2702             case NF_SYMBOLTYPE_STRING:
2703             case NF_SYMBOLTYPE_CURRENCY:
2704             case NF_SYMBOLTYPE_DATESEP:
2705             case NF_SYMBOLTYPE_TIMESEP:
2706             case NF_SYMBOLTYPE_TIME100SECSEP:
2707                 OutString += rInfo.sStrArray[i];
2708                 break;
2709             case NF_SYMBOLTYPE_DIGIT:
2710             {
2711                 xub_StrLen nLen = ( bInputLine && i > 0 &&
2712                     (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
2713                      rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
2714                     nCntPost : rInfo.sStrArray[i].Len() );
2715                 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
2716                 {
2717                     OutString += sSecStr.GetChar(nSecPos);
2718                     nSecPos++;
2719                 }
2720             }
2721             break;
2722             case NF_KEY_AMPM:               // AM/PM
2723             {
2724                 if ( !bCalendarSet )
2725                 {
2726                     double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
2727                     fDiff += fNumberOrig;
2728                     GetCal().setLocalDateTime( fDiff );
2729                     bCalendarSet = sal_True;
2730                 }
2731                 if (cAmPm == 'a')
2732                     OutString += GetCal().getDisplayName(
2733                         CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 );
2734                 else
2735                     OutString += GetCal().getDisplayName(
2736                         CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 );
2737             }
2738             break;
2739             case NF_KEY_AP:                 // A/P
2740             {
2741                 if (cAmPm == 'a')
2742                     OutString += 'a';
2743                 else
2744                     OutString += 'p';
2745             }
2746             break;
2747             case NF_KEY_MI:                 // M
2748                 OutString += ImpIntToString( nIx, nMin );
2749             break;
2750             case NF_KEY_MMI:                // MM
2751                 OutString += ImpIntToString( nIx, nMin, 2 );
2752             break;
2753             case NF_KEY_H:                  // H
2754                 OutString += ImpIntToString( nIx, nHour );
2755             break;
2756             case NF_KEY_HH:                 // HH
2757                 OutString += ImpIntToString( nIx, nHour, 2 );
2758             break;
2759             case NF_KEY_S:                  // S
2760                 OutString += ImpIntToString( nIx, nSec );
2761             break;
2762             case NF_KEY_SS:                 // SS
2763                 OutString += ImpIntToString( nIx, nSec, 2 );
2764             break;
2765             default:
2766             break;
2767         }
2768     }
2769     if (bSign && rInfo.bThousand)
2770         OutString.Insert('-',0);
2771     return bRes;
2772 }
2773 
2774 
2775 sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
2776 {
2777     if ( GetCal().getUniqueID() != Gregorian::get() )
2778         return sal_False;
2779     const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2780     const sal_uInt16 nAnz = rNumFor.GetnAnz();
2781     sal_uInt16 i;
2782     for ( i = 0; i < nAnz; i++ )
2783     {
2784         switch ( rInfo.nTypeArray[i] )
2785         {
2786             case NF_SYMBOLTYPE_CALENDAR :
2787                 return sal_False;
2788             case NF_KEY_EC :
2789             case NF_KEY_EEC :
2790             case NF_KEY_R :
2791             case NF_KEY_RR :
2792             case NF_KEY_AAA :
2793             case NF_KEY_AAAA :
2794                 return sal_True;
2795         }
2796     }
2797     return sal_False;
2798 }
2799 
2800 
2801 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar,
2802         double& fOrgDateTime ) const
2803 {
2804     CalendarWrapper& rCal = GetCal();
2805     const rtl::OUString &rGregorian = Gregorian::get();
2806     if ( rCal.getUniqueID() == rGregorian )
2807     {
2808         using namespace ::com::sun::star::i18n;
2809         ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals
2810             = rCal.getAllCalendars( rLoc().getLocale() );
2811         sal_Int32 nCnt = xCals.getLength();
2812         if ( nCnt > 1 )
2813         {
2814             for ( sal_Int32 j=0; j < nCnt; j++ )
2815             {
2816                 if ( xCals[j] != rGregorian )
2817                 {
2818                     if ( !rOrgCalendar.Len() )
2819                     {
2820                         rOrgCalendar = rCal.getUniqueID();
2821                         fOrgDateTime = rCal.getDateTime();
2822                     }
2823                     rCal.loadCalendar( xCals[j], rLoc().getLocale() );
2824                     rCal.setDateTime( fOrgDateTime );
2825                     break;  // for
2826                 }
2827             }
2828         }
2829     }
2830 }
2831 
2832 
2833 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar,
2834         double fOrgDateTime ) const
2835 {
2836     CalendarWrapper& rCal = GetCal();
2837     const rtl::OUString &rGregorian = Gregorian::get();
2838     if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian )
2839     {
2840         rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2841         rCal.setDateTime( fOrgDateTime );
2842     }
2843 }
2844 
2845 
2846 sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime )
2847 {
2848     using namespace ::com::sun::star::i18n;
2849     CalendarWrapper& rCal = GetCal();
2850     const rtl::OUString &rGregorian = Gregorian::get();
2851     if ( rCal.getUniqueID() != rGregorian )
2852     {
2853         sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2854         if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL(
2855                 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
2856         {
2857             if ( !rOrgCalendar.Len() )
2858             {
2859                 rOrgCalendar = rCal.getUniqueID();
2860                 fOrgDateTime = rCal.getDateTime();
2861             }
2862             else if ( rOrgCalendar == String(rGregorian) )
2863                 rOrgCalendar.Erase();
2864             rCal.loadCalendar( rGregorian, rLoc().getLocale() );
2865             rCal.setDateTime( fOrgDateTime );
2866             return sal_True;
2867         }
2868     }
2869     return sal_False;
2870 }
2871 
2872 
2873 sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
2874         double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
2875 {
2876     const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2877     const sal_uInt16 nAnz = rNumFor.GetnAnz();
2878     for ( sal_uInt16 i = 0; i < nAnz; i++ )
2879     {
2880         if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
2881         {
2882             CalendarWrapper& rCal = GetCal();
2883             if ( !rOrgCalendar.Len() )
2884             {
2885                 rOrgCalendar = rCal.getUniqueID();
2886                 fOrgDateTime = rCal.getDateTime();
2887             }
2888             rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2889             rCal.setDateTime( fOrgDateTime );
2890             return sal_True;
2891         }
2892     }
2893     return sal_False;
2894 }
2895 
2896 
2897 // static
2898 void SvNumberformat::ImpAppendEraG( String& OutString,
2899         const CalendarWrapper& rCal, sal_Int16 nNatNum )
2900 {
2901     using namespace ::com::sun::star::i18n;
2902     if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
2903     {
2904         sal_Unicode cEra;
2905         sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
2906         switch ( nVal )
2907         {
2908             case 1 :    cEra = 'M'; break;
2909             case 2 :    cEra = 'T'; break;
2910             case 3 :    cEra = 'S'; break;
2911             case 4 :    cEra = 'H'; break;
2912             default:
2913                 cEra = '?';
2914         }
2915         OutString += cEra;
2916     }
2917     else
2918         OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum );
2919 }
2920 
2921 
2922 sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber,
2923                                    sal_uInt16 nIx,
2924                                    String& OutString)
2925 {
2926     using namespace ::com::sun::star::i18n;
2927     sal_Bool bRes = sal_False;
2928     CalendarWrapper& rCal = GetCal();
2929     double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
2930     fNumber += fDiff;
2931     rCal.setLocalDateTime( fNumber );
2932     String aOrgCalendar;        // empty => not changed yet
2933     double fOrgDateTime;
2934     sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
2935     if ( bOtherCalendar )
2936         SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
2937     if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
2938         bOtherCalendar = sal_False;
2939     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2940     const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
2941     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
2942     for (sal_uInt16 i = 0; i < nAnz; i++)
2943     {
2944         switch (rInfo.nTypeArray[i])
2945         {
2946             case NF_SYMBOLTYPE_CALENDAR :
2947                 if ( !aOrgCalendar.Len() )
2948                 {
2949                     aOrgCalendar = rCal.getUniqueID();
2950                     fOrgDateTime = rCal.getDateTime();
2951                 }
2952                 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
2953                 rCal.setDateTime( fOrgDateTime );
2954                 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
2955             break;
2956             case NF_SYMBOLTYPE_STAR:
2957                 if( bStarFlag )
2958                 {
2959                     OutString += (sal_Unicode) 0x1B;
2960                     OutString += rInfo.sStrArray[i].GetChar(1);
2961                     bRes = sal_True;
2962                 }
2963             break;
2964             case NF_SYMBOLTYPE_BLANK:
2965                 InsertBlanks( OutString, OutString.Len(),
2966                     rInfo.sStrArray[i].GetChar(1) );
2967             break;
2968             case NF_SYMBOLTYPE_STRING:
2969             case NF_SYMBOLTYPE_CURRENCY:
2970             case NF_SYMBOLTYPE_DATESEP:
2971             case NF_SYMBOLTYPE_TIMESEP:
2972             case NF_SYMBOLTYPE_TIME100SECSEP:
2973                 OutString += rInfo.sStrArray[i];
2974             break;
2975             case NF_KEY_M:                  // M
2976                 OutString += rCal.getDisplayString(
2977                         CalendarDisplayCode::SHORT_MONTH, nNatNum );
2978             break;
2979             case NF_KEY_MM:                 // MM
2980                 OutString += rCal.getDisplayString(
2981                         CalendarDisplayCode::LONG_MONTH, nNatNum );
2982             break;
2983             case NF_KEY_MMM:                // MMM
2984                 OutString += rCal.getDisplayString(
2985                         CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
2986             break;
2987             case NF_KEY_MMMM:               // MMMM
2988                 OutString += rCal.getDisplayString(
2989                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
2990             break;
2991             case NF_KEY_MMMMM:              // MMMMM
2992                 OutString += rCal.getDisplayString(
2993                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
2994             break;
2995             case NF_KEY_Q:                  // Q
2996                 OutString += rCal.getDisplayString(
2997                         CalendarDisplayCode::SHORT_QUARTER, nNatNum );
2998             break;
2999             case NF_KEY_QQ:                 // QQ
3000                 OutString += rCal.getDisplayString(
3001                         CalendarDisplayCode::LONG_QUARTER, nNatNum );
3002             break;
3003             case NF_KEY_D:                  // D
3004                 OutString += rCal.getDisplayString(
3005                         CalendarDisplayCode::SHORT_DAY, nNatNum );
3006             break;
3007             case NF_KEY_DD:                 // DD
3008                 OutString += rCal.getDisplayString(
3009                         CalendarDisplayCode::LONG_DAY, nNatNum );
3010             break;
3011             case NF_KEY_DDD:                // DDD
3012             {
3013                 if ( bOtherCalendar )
3014                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3015                 OutString += rCal.getDisplayString(
3016                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3017                 if ( bOtherCalendar )
3018                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3019             }
3020             break;
3021             case NF_KEY_DDDD:               // DDDD
3022             {
3023                 if ( bOtherCalendar )
3024                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3025                 OutString += rCal.getDisplayString(
3026                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3027                 if ( bOtherCalendar )
3028                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3029             }
3030             break;
3031             case NF_KEY_YY:                 // YY
3032             {
3033                 if ( bOtherCalendar )
3034                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3035                 OutString += rCal.getDisplayString(
3036                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3037                 if ( bOtherCalendar )
3038                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3039             }
3040             break;
3041             case NF_KEY_YYYY:               // YYYY
3042             {
3043                 if ( bOtherCalendar )
3044                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3045                 OutString += rCal.getDisplayString(
3046                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3047                 if ( bOtherCalendar )
3048                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3049             }
3050             break;
3051             case NF_KEY_EC:                 // E
3052                 OutString += rCal.getDisplayString(
3053                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3054             break;
3055             case NF_KEY_EEC:                // EE
3056             case NF_KEY_R:                  // R
3057                 OutString += rCal.getDisplayString(
3058                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3059             break;
3060             case NF_KEY_NN:                 // NN
3061             case NF_KEY_AAA:                // AAA
3062                 OutString += rCal.getDisplayString(
3063                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3064             break;
3065             case NF_KEY_NNN:                // NNN
3066             case NF_KEY_AAAA:               // AAAA
3067                 OutString += rCal.getDisplayString(
3068                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3069             break;
3070             case NF_KEY_NNNN:               // NNNN
3071             {
3072                 OutString += rCal.getDisplayString(
3073                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3074                 OutString += rLoc().getLongDateDayOfWeekSep();
3075             }
3076             break;
3077             case NF_KEY_WW :                // WW
3078             {
3079                 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
3080                 OutString += ImpIntToString( nIx, nVal );
3081             }
3082             break;
3083             case NF_KEY_G:                  // G
3084                 ImpAppendEraG( OutString, rCal, nNatNum );
3085             break;
3086             case NF_KEY_GG:                 // GG
3087                 OutString += rCal.getDisplayString(
3088                         CalendarDisplayCode::SHORT_ERA, nNatNum );
3089             break;
3090             case NF_KEY_GGG:                // GGG
3091                 OutString += rCal.getDisplayString(
3092                         CalendarDisplayCode::LONG_ERA, nNatNum );
3093             break;
3094             case NF_KEY_RR:                 // RR => GGGEE
3095                 OutString += rCal.getDisplayString(
3096                         CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
3097             break;
3098         }
3099     }
3100     if ( aOrgCalendar.Len() )
3101         rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() );  // restore calendar
3102     return bRes;
3103 }
3104 
3105 sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
3106                                        sal_uInt16 nIx,
3107                                        String& OutString)
3108 {
3109     using namespace ::com::sun::star::i18n;
3110     sal_Bool bRes = sal_False;
3111 
3112     CalendarWrapper& rCal = GetCal();
3113     double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
3114     fNumber += fDiff;
3115 
3116     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3117     sal_Bool bInputLine;
3118     xub_StrLen nCntPost;
3119     if ( rScan.GetStandardPrec() == 300 &&
3120             0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
3121     {   // round at 7 decimals (+5 of 86400 == 12 significant digits)
3122         bInputLine = sal_True;
3123         nCntPost = 7;
3124     }
3125     else
3126     {
3127         bInputLine = sal_False;
3128         nCntPost = xub_StrLen(rInfo.nCntPost);
3129     }
3130     double fTime = (fNumber - floor( fNumber )) * 86400.0;
3131     fTime = ::rtl::math::round( fTime, int(nCntPost) );
3132     if (fTime >= 86400.0)
3133     {
3134         // result of fNumber==x.999999999... rounded up, use correct date/time
3135         fTime -= 86400.0;
3136         fNumber = floor( fNumber + 0.5) + fTime;
3137     }
3138     rCal.setLocalDateTime( fNumber );
3139 
3140     String aOrgCalendar;        // empty => not changed yet
3141     double fOrgDateTime;
3142     sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
3143     if ( bOtherCalendar )
3144         SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3145     if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
3146         bOtherCalendar = sal_False;
3147     sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
3148 
3149     sal_uLong nSeconds = (sal_uLong)floor( fTime );
3150     String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
3151                 rtl_math_StringFormat_F, int(nCntPost), '.'));
3152     sSecStr.EraseLeadingChars('0');
3153     sSecStr.EraseLeadingChars('.');
3154     if ( bInputLine )
3155     {
3156         sSecStr.EraseTrailingChars('0');
3157         if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
3158             sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
3159         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3160         nCntPost = sSecStr.Len();
3161     }
3162     else
3163         ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
3164 
3165     xub_StrLen nSecPos = 0;                     // Zum Ziffernweisen
3166                                             // abarbeiten
3167     sal_uLong nHour, nMin, nSec;
3168     if (!rInfo.bThousand)      // [] Format
3169     {
3170         nHour = (nSeconds/3600) % 24;
3171         nMin = (nSeconds%3600) / 60;
3172         nSec = nSeconds%60;
3173     }
3174     else if (rInfo.nThousand == 3) // [ss]
3175     {
3176         nHour = 0;
3177         nMin = 0;
3178         nSec = nSeconds;
3179     }
3180     else if (rInfo.nThousand == 2) // [mm]:ss
3181     {
3182         nHour = 0;
3183         nMin = nSeconds / 60;
3184         nSec = nSeconds % 60;
3185     }
3186     else if (rInfo.nThousand == 1) // [hh]:mm:ss
3187     {
3188         nHour = nSeconds / 3600;
3189         nMin = (nSeconds%3600) / 60;
3190         nSec = nSeconds%60;
3191     }
3192     else {
3193         nHour = 0;  // TODO What should these values be?
3194         nMin  = 0;
3195         nSec  = 0;
3196     }
3197     sal_Unicode cAmPm = ' ';                   // a oder p
3198     if (rInfo.nCntExp)     // AM/PM
3199     {
3200         if (nHour == 0)
3201         {
3202             nHour = 12;
3203             cAmPm = 'a';
3204         }
3205         else if (nHour < 12)
3206             cAmPm = 'a';
3207         else
3208         {
3209             cAmPm = 'p';
3210             if (nHour > 12)
3211                 nHour -= 12;
3212         }
3213     }
3214     const sal_uInt16 nAnz = NumFor[nIx].GetnAnz();
3215     for (sal_uInt16 i = 0; i < nAnz; i++)
3216     {
3217         switch (rInfo.nTypeArray[i])
3218         {
3219             case NF_SYMBOLTYPE_CALENDAR :
3220                 if ( !aOrgCalendar.Len() )
3221                 {
3222                     aOrgCalendar = rCal.getUniqueID();
3223                     fOrgDateTime = rCal.getDateTime();
3224                 }
3225                 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
3226                 rCal.setDateTime( fOrgDateTime );
3227                 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3228                 break;
3229             case NF_SYMBOLTYPE_STAR:
3230                 if( bStarFlag )
3231                 {
3232                     OutString += (sal_Unicode) 0x1B;
3233                     OutString += rInfo.sStrArray[i].GetChar(1);
3234                     bRes = sal_True;
3235                 }
3236                 break;
3237             case NF_SYMBOLTYPE_BLANK:
3238                 InsertBlanks( OutString, OutString.Len(),
3239                     rInfo.sStrArray[i].GetChar(1) );
3240                 break;
3241             case NF_SYMBOLTYPE_STRING:
3242             case NF_SYMBOLTYPE_CURRENCY:
3243             case NF_SYMBOLTYPE_DATESEP:
3244             case NF_SYMBOLTYPE_TIMESEP:
3245             case NF_SYMBOLTYPE_TIME100SECSEP:
3246                 OutString += rInfo.sStrArray[i];
3247                 break;
3248             case NF_SYMBOLTYPE_DIGIT:
3249             {
3250                 xub_StrLen nLen = ( bInputLine && i > 0 &&
3251                     (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
3252                      rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
3253                     nCntPost : rInfo.sStrArray[i].Len() );
3254                 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
3255                 {
3256                     OutString += sSecStr.GetChar(nSecPos);
3257                     nSecPos++;
3258                 }
3259             }
3260             break;
3261             case NF_KEY_AMPM:               // AM/PM
3262             {
3263                 if (cAmPm == 'a')
3264                     OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3265                         AmPmValue::AM, 0 );
3266                 else
3267                     OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3268                         AmPmValue::PM, 0 );
3269             }
3270             break;
3271             case NF_KEY_AP:                 // A/P
3272             {
3273                 if (cAmPm == 'a')
3274                     OutString += 'a';
3275                 else
3276                     OutString += 'p';
3277             }
3278             break;
3279             case NF_KEY_MI:                 // M
3280                 OutString += ImpIntToString( nIx, nMin );
3281             break;
3282             case NF_KEY_MMI:                // MM
3283                 OutString += ImpIntToString( nIx, nMin, 2 );
3284             break;
3285             case NF_KEY_H:                  // H
3286                 OutString += ImpIntToString( nIx, nHour );
3287             break;
3288             case NF_KEY_HH:                 // HH
3289                 OutString += ImpIntToString( nIx, nHour, 2 );
3290             break;
3291             case NF_KEY_S:                  // S
3292                 OutString += ImpIntToString( nIx, nSec );
3293             break;
3294             case NF_KEY_SS:                 // SS
3295                 OutString += ImpIntToString( nIx, nSec, 2 );
3296             break;
3297             case NF_KEY_M:                  // M
3298                 OutString += rCal.getDisplayString(
3299                         CalendarDisplayCode::SHORT_MONTH, nNatNum );
3300             break;
3301             case NF_KEY_MM:                 // MM
3302                 OutString += rCal.getDisplayString(
3303                         CalendarDisplayCode::LONG_MONTH, nNatNum );
3304             break;
3305             case NF_KEY_MMM:                // MMM
3306                 OutString += rCal.getDisplayString(
3307                         CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
3308             break;
3309             case NF_KEY_MMMM:               // MMMM
3310                 OutString += rCal.getDisplayString(
3311                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
3312             break;
3313             case NF_KEY_MMMMM:              // MMMMM
3314                 OutString += rCal.getDisplayString(
3315                         CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
3316             break;
3317             case NF_KEY_Q:                  // Q
3318                 OutString += rCal.getDisplayString(
3319                         CalendarDisplayCode::SHORT_QUARTER, nNatNum );
3320             break;
3321             case NF_KEY_QQ:                 // QQ
3322                 OutString += rCal.getDisplayString(
3323                         CalendarDisplayCode::LONG_QUARTER, nNatNum );
3324             break;
3325             case NF_KEY_D:                  // D
3326                 OutString += rCal.getDisplayString(
3327                         CalendarDisplayCode::SHORT_DAY, nNatNum );
3328             break;
3329             case NF_KEY_DD:                 // DD
3330                 OutString += rCal.getDisplayString(
3331                         CalendarDisplayCode::LONG_DAY, nNatNum );
3332             break;
3333             case NF_KEY_DDD:                // DDD
3334             {
3335                 if ( bOtherCalendar )
3336                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3337                 OutString += rCal.getDisplayString(
3338                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3339                 if ( bOtherCalendar )
3340                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3341             }
3342             break;
3343             case NF_KEY_DDDD:               // DDDD
3344             {
3345                 if ( bOtherCalendar )
3346                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3347                 OutString += rCal.getDisplayString(
3348                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3349                 if ( bOtherCalendar )
3350                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3351             }
3352             break;
3353             case NF_KEY_YY:                 // YY
3354             {
3355                 if ( bOtherCalendar )
3356                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3357                 OutString += rCal.getDisplayString(
3358                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3359                 if ( bOtherCalendar )
3360                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3361             }
3362             break;
3363             case NF_KEY_YYYY:               // YYYY
3364             {
3365                 if ( bOtherCalendar )
3366                     SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3367                 OutString += rCal.getDisplayString(
3368                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3369                 if ( bOtherCalendar )
3370                     SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3371             }
3372             break;
3373             case NF_KEY_EC:                 // E
3374                 OutString += rCal.getDisplayString(
3375                         CalendarDisplayCode::SHORT_YEAR, nNatNum );
3376             break;
3377             case NF_KEY_EEC:                // EE
3378             case NF_KEY_R:                  // R
3379                 OutString += rCal.getDisplayString(
3380                         CalendarDisplayCode::LONG_YEAR, nNatNum );
3381             break;
3382             case NF_KEY_NN:                 // NN
3383             case NF_KEY_AAA:                // AAA
3384                 OutString += rCal.getDisplayString(
3385                         CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
3386             break;
3387             case NF_KEY_NNN:                // NNN
3388             case NF_KEY_AAAA:               // AAAA
3389                 OutString += rCal.getDisplayString(
3390                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3391             break;
3392             case NF_KEY_NNNN:               // NNNN
3393             {
3394                 OutString += rCal.getDisplayString(
3395                         CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
3396                 OutString += rLoc().getLongDateDayOfWeekSep();
3397             }
3398             break;
3399             case NF_KEY_WW :                // WW
3400             {
3401                 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
3402                 OutString += ImpIntToString( nIx, nVal );
3403             }
3404             break;
3405             case NF_KEY_G:                  // G
3406                 ImpAppendEraG( OutString, rCal, nNatNum );
3407             break;
3408             case NF_KEY_GG:                 // GG
3409                 OutString += rCal.getDisplayString(
3410                         CalendarDisplayCode::SHORT_ERA, nNatNum );
3411             break;
3412             case NF_KEY_GGG:                // GGG
3413                 OutString += rCal.getDisplayString(
3414                         CalendarDisplayCode::LONG_ERA, nNatNum );
3415             break;
3416             case NF_KEY_RR:                 // RR => GGGEE
3417                 OutString += rCal.getDisplayString(
3418                         CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
3419             break;
3420         }
3421     }
3422     if ( aOrgCalendar.Len() )
3423         rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() );  // restore calendar
3424     return bRes;
3425 }
3426 
3427 sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber,
3428                                      sal_uInt16 nIx,
3429                                      String& OutString)
3430 {
3431     sal_Bool bRes = sal_False;
3432     sal_Bool bSign;
3433     if (fNumber < 0.0)
3434     {
3435         if (nIx == 0)                       // nicht in hinteren
3436             bSign = sal_True;                   // Formaten
3437         else
3438             bSign = sal_False;
3439         fNumber = -fNumber;
3440     }
3441     else
3442     {
3443         bSign = sal_False;
3444         if ( ::rtl::math::isSignBitSet( fNumber ) )
3445             fNumber = -fNumber;     // yes, -0.0 is possible, eliminate '-'
3446     }
3447     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3448     if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
3449     {
3450         if (fNumber < _D_MAX_D_BY_100)
3451             fNumber *= 100.0;
3452         else
3453         {
3454             OutString = rScan.GetErrorString();
3455             return sal_False;
3456         }
3457     }
3458     sal_uInt16 i, j;
3459     xub_StrLen k;
3460     String sStr;
3461     long nPrecExp;
3462     sal_Bool bInteger = sal_False;
3463     if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
3464     {   // special formatting only if no GENERAL keyword in format code
3465         const sal_uInt16 nThousand = rInfo.nThousand;
3466         for (i = 0; i < nThousand; i++)
3467         {
3468            if (fNumber > _D_MIN_M_BY_1000)
3469                fNumber /= 1000.0;
3470            else
3471                fNumber = 0.0;
3472         }
3473         if (fNumber > 0.0)
3474             nPrecExp = GetPrecExp( fNumber );
3475         else
3476             nPrecExp = 0;
3477         if (rInfo.nCntPost)    // NachkommaStellen
3478         {
3479             if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15)
3480             {
3481                 sStr = ::rtl::math::doubleToUString( fNumber,
3482                         rtl_math_StringFormat_F, 15-nPrecExp, '.');
3483                 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
3484                     sStr += '0';
3485             }
3486             else
3487                 sStr = ::rtl::math::doubleToUString( fNumber,
3488                         rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
3489             sStr.EraseLeadingChars('0');        // fuehrende Nullen weg
3490         }
3491         else if (fNumber == 0.0)            // Null
3492         {
3493             // nothing to be done here, keep empty string sStr,
3494             // ImpNumberFillWithThousands does the rest
3495         }
3496         else                                // Integer
3497         {
3498             sStr = ::rtl::math::doubleToUString( fNumber,
3499                     rtl_math_StringFormat_F, 0, '.');
3500             sStr.EraseLeadingChars('0');        // fuehrende Nullen weg
3501         }
3502         xub_StrLen nPoint = sStr.Search( '.' );
3503         if ( nPoint != STRING_NOTFOUND )
3504         {
3505             register const sal_Unicode* p = sStr.GetBuffer() + nPoint;
3506             while ( *++p == '0' )
3507                 ;
3508             if ( !*p )
3509                 bInteger = sal_True;
3510             sStr.Erase( nPoint, 1 );            //  . herausnehmen
3511         }
3512         if (bSign &&
3513             (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1))   // nur 00000
3514             bSign = sal_False;              // nicht -0.00
3515     }                                   // End of != FLAG_STANDARD_IN_FORMAT
3516 
3517                                         // von hinten nach vorn
3518                                         // editieren:
3519     k = sStr.Len();                     // hinter letzter Ziffer
3520     j = NumFor[nIx].GetnAnz()-1;        // letztes Symbol
3521                                         // Nachkommastellen:
3522     if (rInfo.nCntPost > 0)
3523     {
3524         sal_Bool bTrailing = sal_True;          // ob Endnullen?
3525         sal_Bool bFilled = sal_False;           // ob aufgefuellt wurde ?
3526         short nType;
3527         while (j > 0 &&                 // rueckwaerts
3528            (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
3529         {
3530             switch ( nType )
3531             {
3532                 case NF_SYMBOLTYPE_STAR:
3533                     if( bStarFlag )
3534                     {
3535                         sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
3536                         sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3537                         bRes = sal_True;
3538                     }
3539                     break;
3540                 case NF_SYMBOLTYPE_BLANK:
3541                     /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3542                     break;
3543                 case NF_SYMBOLTYPE_STRING:
3544                 case NF_SYMBOLTYPE_CURRENCY:
3545                 case NF_SYMBOLTYPE_PERCENT:
3546                     sStr.Insert(rInfo.sStrArray[j],k);
3547                     break;
3548                 case NF_SYMBOLTYPE_THSEP:
3549                     if (rInfo.nThousand == 0)
3550                         sStr.Insert(rInfo.sStrArray[j],k);
3551                 break;
3552                 case NF_SYMBOLTYPE_DIGIT:
3553                 {
3554                     const String& rStr = rInfo.sStrArray[j];
3555                     const sal_Unicode* p1 = rStr.GetBuffer();
3556                     register const sal_Unicode* p = p1 + rStr.Len();
3557                     while ( p1 < p-- )
3558                     {
3559                         const sal_Unicode c = *p;
3560                         k--;
3561                         if ( sStr.GetChar(k) != '0' )
3562                             bTrailing = sal_False;
3563                         if (bTrailing)
3564                         {
3565                             if ( c == '0' )
3566                                 bFilled = sal_True;
3567                             else if ( c == '-' )
3568                             {
3569                                 if ( bInteger )
3570                                     sStr.SetChar( k, '-' );
3571                                 bFilled = sal_True;
3572                             }
3573                             else if ( c == '?' )
3574                             {
3575                                 sStr.SetChar( k, ' ' );
3576                                 bFilled = sal_True;
3577                             }
3578                             else if ( !bFilled )    // #
3579                                 sStr.Erase(k,1);
3580                         }
3581                     }                           // of for
3582                 }                               // of case digi
3583                 break;
3584                 case NF_KEY_CCC:                // CCC-Waehrung
3585                     sStr.Insert(rScan.GetCurAbbrev(), k);
3586                 break;
3587                 case NF_KEY_GENERAL:            // Standard im String
3588                 {
3589                     String sNum;
3590                     ImpGetOutputStandard(fNumber, sNum);
3591                     sNum.EraseLeadingChars('-');
3592                     sStr.Insert(sNum, k);
3593                 }
3594                 break;
3595                 default:
3596                 break;
3597             }                                   // of switch
3598             j--;
3599         }                                       // of while
3600     }                                           // of Nachkomma
3601 
3602     bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit .
3603                             rInfo.nCntPre);
3604     if ( rInfo.nCntPost > 0 )
3605     {
3606         const String& rDecSep = GetFormatter().GetNumDecimalSep();
3607         xub_StrLen nLen = rDecSep.Len();
3608         if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) )
3609             sStr.Erase( sStr.Len() - nLen );        // no decimals => strip DecSep
3610     }
3611     if (bSign)
3612         sStr.Insert('-',0);
3613     ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
3614     OutString = sStr;
3615     return bRes;
3616 }
3617 
3618 sal_Bool SvNumberformat::ImpNumberFillWithThousands(
3619                                 String& sStr,       // number string
3620                                 double& rNumber,    // number
3621                                 xub_StrLen k,       // position within string
3622                                 sal_uInt16 j,           // symbol index within format code
3623                                 sal_uInt16 nIx,         // subformat index
3624                                 sal_uInt16 nDigCnt)     // count of integer digits in format
3625 {
3626     sal_Bool bRes = sal_False;
3627     xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
3628     xub_StrLen nDigitCount = 0;         // count of integer digits from the right
3629     sal_Bool bStop = sal_False;
3630     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3631     // no normal thousands separators if number divided by thousands
3632     sal_Bool bDoThousands = (rInfo.nThousand == 0);
3633     utl::DigitGroupingIterator aGrouping(
3634             GetFormatter().GetLocaleData()->getDigitGrouping());
3635     while (!bStop)                                      // backwards
3636     {
3637         if (j == 0)
3638             bStop = sal_True;
3639         switch (rInfo.nTypeArray[j])
3640         {
3641             case NF_SYMBOLTYPE_DECSEP:
3642                 aGrouping.reset();
3643                 // fall thru
3644             case NF_SYMBOLTYPE_STRING:
3645             case NF_SYMBOLTYPE_CURRENCY:
3646             case NF_SYMBOLTYPE_PERCENT:
3647                 sStr.Insert(rInfo.sStrArray[j],k);
3648                 if ( k == 0 )
3649                     nLeadingStringChars =
3650                         nLeadingStringChars + rInfo.sStrArray[j].Len();
3651             break;
3652             case NF_SYMBOLTYPE_STAR:
3653                 if( bStarFlag )
3654                 {
3655                     sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
3656                     sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3657                     bRes = sal_True;
3658                 }
3659                 break;
3660             case NF_SYMBOLTYPE_BLANK:
3661                 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3662                 break;
3663             case NF_SYMBOLTYPE_THSEP:
3664             {
3665                 // #i7284# #102685# Insert separator also if number is divided
3666                 // by thousands and the separator is specified somewhere in
3667                 // between and not only at the end.
3668                 // #i12596# But do not insert if it's a parenthesized negative
3669                 // format like (#,)
3670                 // In fact, do not insert if divided and regex [0#,],[^0#] and
3671                 // no other digit symbol follows (which was already detected
3672                 // during scan of format code, otherwise there would be no
3673                 // division), else do insert. Same in ImpNumberFill() below.
3674                 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3675                     bDoThousands = ((j == 0) ||
3676                             (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3677                              rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3678                             (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3679                 if ( bDoThousands )
3680                 {
3681                     if (k > 0)
3682                         sStr.Insert(rInfo.sStrArray[j],k);
3683                     else if (nDigitCount < nDigCnt)
3684                     {
3685                         // Leading '#' displays nothing (e.g. no leading
3686                         // separator for numbers <1000 with #,##0 format).
3687                         // Leading '?' displays blank.
3688                         // Everything else, including nothing, displays the
3689                         // separator.
3690                         sal_Unicode cLeader = 0;
3691                         if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
3692                         {
3693                             const String& rStr = rInfo.sStrArray[j-1];
3694                             xub_StrLen nLen = rStr.Len();
3695                             if (nLen)
3696                                 cLeader = rStr.GetChar(nLen-1);
3697                         }
3698                         switch (cLeader)
3699                         {
3700                             case '#':
3701                                 ;   // nothing
3702                                 break;
3703                             case '?':
3704                                 // erAck: 2008-04-03T16:24+0200
3705                                 // Actually this currently isn't executed
3706                                 // because the format scanner in the context of
3707                                 // "?," doesn't generate a group separator but
3708                                 // a literal ',' character instead that is
3709                                 // inserted unconditionally. Should be changed
3710                                 // on some occasion.
3711                                 sStr.Insert(' ',k);
3712                                 break;
3713                             default:
3714                                 sStr.Insert(rInfo.sStrArray[j],k);
3715                         }
3716                     }
3717                     aGrouping.advance();
3718                 }
3719             }
3720             break;
3721             case NF_SYMBOLTYPE_DIGIT:
3722             {
3723                 const String& rStr = rInfo.sStrArray[j];
3724                 const sal_Unicode* p1 = rStr.GetBuffer();
3725                 register const sal_Unicode* p = p1 + rStr.Len();
3726                 while ( p1 < p-- )
3727                 {
3728                     nDigitCount++;
3729                     if (k > 0)
3730                         k--;
3731                     else
3732                     {
3733                         switch (*p)
3734                         {
3735                             case '0':
3736                                 sStr.Insert('0',0);
3737                                 break;
3738                             case '?':
3739                                 sStr.Insert(' ',0);
3740                                 break;
3741                         }
3742                     }
3743                     if (nDigitCount == nDigCnt && k > 0)
3744                     {   // more digits than specified
3745                         ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping);
3746                     }
3747                 }
3748             }
3749             break;
3750             case NF_KEY_CCC:                        // CCC currency
3751                 sStr.Insert(rScan.GetCurAbbrev(), k);
3752             break;
3753             case NF_KEY_GENERAL:                    // "General" in string
3754             {
3755                 String sNum;
3756                 ImpGetOutputStandard(rNumber, sNum);
3757                 sNum.EraseLeadingChars('-');
3758                 sStr.Insert(sNum, k);
3759             }
3760             break;
3761 
3762             default:
3763             break;
3764         } // switch
3765         j--;        // next format code string
3766     } // while
3767     k = k + nLeadingStringChars;    // MSC converts += to int and then warns, so ...
3768     if (k > nLeadingStringChars)
3769         ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
3770     return bRes;
3771 }
3772 
3773 void SvNumberformat::ImpDigitFill(
3774         String& sStr,                   // number string
3775         xub_StrLen nStart,              // start of digits
3776         xub_StrLen& k,                  // position within string
3777         sal_uInt16 nIx,                     // subformat index
3778         xub_StrLen & nDigitCount,       // count of integer digits from the right so far
3779         utl::DigitGroupingIterator & rGrouping )    // current grouping
3780 {
3781     if (NumFor[nIx].Info().bThousand)               // only if grouping
3782     {                                               // fill in separators
3783         const String& rThousandSep = GetFormatter().GetNumThousandSep();
3784         while (k > nStart)
3785         {
3786             if (nDigitCount == rGrouping.getPos())
3787             {
3788                 sStr.Insert( rThousandSep, k );
3789                 rGrouping.advance();
3790             }
3791             nDigitCount++;
3792             k--;
3793         }
3794     }
3795     else                                            // simply skip
3796         k = nStart;
3797 }
3798 
3799 sal_Bool SvNumberformat::ImpNumberFill( String& sStr,       // number string
3800                                 double& rNumber,        // number for "General" format
3801                                 xub_StrLen& k,          // position within string
3802                                 sal_uInt16& j,              // symbol index within format code
3803                                 sal_uInt16 nIx,             // subformat index
3804                                 short eSymbolType )     // type of stop condition
3805 {
3806     sal_Bool bRes = sal_False;
3807     k = sStr.Len();                         // behind last digit
3808     const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3809     // no normal thousands separators if number divided by thousands
3810     sal_Bool bDoThousands = (rInfo.nThousand == 0);
3811     short nType;
3812     while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
3813     {                                       // rueckwaerts:
3814         switch ( nType )
3815         {
3816             case NF_SYMBOLTYPE_STAR:
3817                 if( bStarFlag )
3818                 {
3819                     sStr.Insert( sal_Unicode(0x1B), k++ );
3820                     sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
3821                     bRes = sal_True;
3822                 }
3823                 break;
3824             case NF_SYMBOLTYPE_BLANK:
3825                 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
3826                 break;
3827             case NF_SYMBOLTYPE_THSEP:
3828             {
3829                 // Same as in ImpNumberFillWithThousands() above, do not insert
3830                 // if divided and regex [0#,],[^0#] and no other digit symbol
3831                 // follows (which was already detected during scan of format
3832                 // code, otherwise there would be no division), else do insert.
3833                 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
3834                     bDoThousands = ((j == 0) ||
3835                             (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
3836                              rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
3837                             (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
3838                 if ( bDoThousands && k > 0 )
3839                 {
3840                     sStr.Insert(rInfo.sStrArray[j],k);
3841                 }
3842             }
3843             break;
3844             case NF_SYMBOLTYPE_DIGIT:
3845             {
3846                 const String& rStr = rInfo.sStrArray[j];
3847                 const sal_Unicode* p1 = rStr.GetBuffer();
3848                 register const sal_Unicode* p = p1 + rStr.Len();
3849                 while ( p1 < p-- )
3850                 {
3851                     if (k > 0)
3852                         k--;
3853                     else
3854                     {
3855                         switch (*p)
3856                         {
3857                             case '0':
3858                                 sStr.Insert('0',0);
3859                                 break;
3860                             case '?':
3861                                 sStr.Insert(' ',0);
3862                                 break;
3863                         }
3864                     }
3865                 }
3866             }
3867             break;
3868             case NF_KEY_CCC:                // CCC-Waehrung
3869                 sStr.Insert(rScan.GetCurAbbrev(), k);
3870             break;
3871             case NF_KEY_GENERAL:            // Standard im String
3872             {
3873                 String sNum;
3874                 ImpGetOutputStandard(rNumber, sNum);
3875                 sNum.EraseLeadingChars('-');    // Vorzeichen weg!!
3876                 sStr.Insert(sNum, k);
3877             }
3878             break;
3879 
3880             default:
3881                 sStr.Insert(rInfo.sStrArray[j],k);
3882             break;
3883         }                                       // of switch
3884         j--;                                    // naechster String
3885     }                                           // of while
3886     return bRes;
3887 }
3888 
3889 void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand,
3890                                           sal_Bool& IsRed,
3891                                           sal_uInt16& nPrecision,
3892                                           sal_uInt16& nAnzLeading) const
3893 {
3894     // as before: take info from nNumFor=0 for whole format (for dialog etc.)
3895 
3896     short nDummyType;
3897     GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
3898 
3899     // "negative in red" is only useful for the whole format
3900 
3901     const Color* pColor = NumFor[1].GetColor();
3902     if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
3903                        && (*pColor == rScan.GetRedColor()))
3904         IsRed = sal_True;
3905     else
3906         IsRed = sal_False;
3907 }
3908 
3909 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType,
3910                     sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const
3911 {
3912     // take info from a specified sub-format (for XML export)
3913 
3914     if ( nNumFor > 3 )
3915         return;             // invalid
3916 
3917     const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
3918     rScannedType = rInfo.eScannedType;
3919     bThousand = rInfo.bThousand;
3920     nPrecision = rInfo.nCntPost;
3921     if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
3922                                                         // StandardFormat
3923         nAnzLeading = 1;
3924     else
3925     {
3926         nAnzLeading = 0;
3927         sal_Bool bStop = sal_False;
3928         sal_uInt16 i = 0;
3929         const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
3930         while (!bStop && i < nAnz)
3931         {
3932             short nType = rInfo.nTypeArray[i];
3933             if ( nType == NF_SYMBOLTYPE_DIGIT)
3934             {
3935                 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
3936                 while ( *p == '#' )
3937                     p++;
3938                 while ( *p++ == '0' )
3939                     nAnzLeading++;
3940             }
3941             else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
3942                 bStop = sal_True;
3943             i++;
3944         }
3945     }
3946 }
3947 
3948 const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos,
3949             sal_Bool bString /* = sal_False */ ) const
3950 {
3951     if ( nNumFor > 3 )
3952         return NULL;
3953     sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
3954     if ( !nAnz )
3955         return NULL;
3956     if ( nPos == 0xFFFF )
3957     {
3958         nPos = nAnz - 1;
3959         if ( bString )
3960         {   // rueckwaerts
3961             short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3962             while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
3963                     (*pType != NF_SYMBOLTYPE_CURRENCY) )
3964             {
3965                 pType--;
3966                 nPos--;
3967             }
3968             if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
3969                 return NULL;
3970         }
3971     }
3972     else if ( nPos > nAnz - 1 )
3973         return NULL;
3974     else if ( bString )
3975     {   // vorwaerts
3976         short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
3977         while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
3978                 (*pType != NF_SYMBOLTYPE_CURRENCY) )
3979         {
3980             pType++;
3981             nPos++;
3982         }
3983         if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
3984                     (*pType != NF_SYMBOLTYPE_CURRENCY)) )
3985             return NULL;
3986     }
3987     return &NumFor[nNumFor].Info().sStrArray[nPos];
3988 }
3989 
3990 
3991 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos,
3992             sal_Bool bString /* = sal_False */ ) const
3993 {
3994     if ( nNumFor > 3 )
3995         return 0;
3996     sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
3997     if ( !nAnz )
3998         return 0;
3999     if ( nPos == 0xFFFF )
4000     {
4001         nPos = nAnz - 1;
4002         if ( bString )
4003         {   // rueckwaerts
4004             short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4005             while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
4006                     (*pType != NF_SYMBOLTYPE_CURRENCY) )
4007             {
4008                 pType--;
4009                 nPos--;
4010             }
4011             if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
4012                 return 0;
4013         }
4014     }
4015     else if ( nPos > nAnz - 1 )
4016         return 0;
4017     else if ( bString )
4018     {   // vorwaerts
4019         short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4020         while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
4021                 (*pType != NF_SYMBOLTYPE_CURRENCY) )
4022         {
4023             pType++;
4024             nPos++;
4025         }
4026         if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
4027             return 0;
4028     }
4029     return NumFor[nNumFor].Info().nTypeArray[nPos];
4030 }
4031 
4032 
4033 sal_Bool SvNumberformat::IsNegativeWithoutSign() const
4034 {
4035     if ( IsNegativeRealNegative() )
4036     {
4037         const String* pStr = GetNumForString( 1, 0, sal_True );
4038         if ( pStr )
4039             return !HasStringNegativeSign( *pStr );
4040     }
4041     return sal_False;
4042 }
4043 
4044 
4045 DateFormat SvNumberformat::GetDateOrder() const
4046 {
4047     if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
4048     {
4049         short const * const pType = NumFor[0].Info().nTypeArray;
4050         sal_uInt16 nAnz = NumFor[0].GetnAnz();
4051         for ( sal_uInt16 j=0; j<nAnz; j++ )
4052         {
4053             switch ( pType[j] )
4054             {
4055                 case NF_KEY_D :
4056                 case NF_KEY_DD :
4057                     return DMY;
4058                 case NF_KEY_M :
4059                 case NF_KEY_MM :
4060                 case NF_KEY_MMM :
4061                 case NF_KEY_MMMM :
4062                 case NF_KEY_MMMMM :
4063                     return MDY;
4064                 case NF_KEY_YY :
4065                 case NF_KEY_YYYY :
4066                 case NF_KEY_EC :
4067                 case NF_KEY_EEC :
4068                 case NF_KEY_R :
4069                 case NF_KEY_RR :
4070                     return YMD;
4071             }
4072         }
4073     }
4074     else
4075     {
4076        DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
4077     }
4078     return rLoc().getDateFormat();
4079 }
4080 
4081 
4082 sal_uInt32 SvNumberformat::GetExactDateOrder() const
4083 {
4084     sal_uInt32 nRet = 0;
4085     if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
4086     {
4087         DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
4088         return nRet;
4089     }
4090     short const * const pType = NumFor[0].Info().nTypeArray;
4091     sal_uInt16 nAnz = NumFor[0].GetnAnz();
4092     int nShift = 0;
4093     for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ )
4094     {
4095         switch ( pType[j] )
4096         {
4097             case NF_KEY_D :
4098             case NF_KEY_DD :
4099                 nRet = (nRet << 8) | 'D';
4100                 ++nShift;
4101             break;
4102             case NF_KEY_M :
4103             case NF_KEY_MM :
4104             case NF_KEY_MMM :
4105             case NF_KEY_MMMM :
4106             case NF_KEY_MMMMM :
4107                 nRet = (nRet << 8) | 'M';
4108                 ++nShift;
4109             break;
4110             case NF_KEY_YY :
4111             case NF_KEY_YYYY :
4112             case NF_KEY_EC :
4113             case NF_KEY_EEC :
4114             case NF_KEY_R :
4115             case NF_KEY_RR :
4116                 nRet = (nRet << 8) | 'Y';
4117                 ++nShift;
4118             break;
4119         }
4120     }
4121     return nRet;
4122 }
4123 
4124 
4125 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
4126                           SvNumberformatLimitOps& rOper2, double& rVal2 ) const
4127 {
4128     rOper1 = eOp1;
4129     rOper2 = eOp2;
4130     rVal1  = fLimit1;
4131     rVal2  = fLimit2;
4132 }
4133 
4134 
4135 Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const
4136 {
4137     if ( nNumFor > 3 )
4138         return NULL;
4139 
4140     return NumFor[nNumFor].GetColor();
4141 }
4142 
4143 
4144 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr,
4145             SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep )
4146 {
4147     if ( eOp != NUMBERFORMAT_OP_NO )
4148     {
4149         switch ( eOp )
4150         {
4151             case NUMBERFORMAT_OP_EQ :
4152                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
4153             break;
4154             case NUMBERFORMAT_OP_NE :
4155                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
4156             break;
4157             case NUMBERFORMAT_OP_LT :
4158                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
4159             break;
4160             case NUMBERFORMAT_OP_LE :
4161                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
4162             break;
4163             case NUMBERFORMAT_OP_GT :
4164                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
4165             break;
4166             case NUMBERFORMAT_OP_GE :
4167                 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
4168             break;
4169             default:
4170                 OSL_ASSERT( "unsupported number format" );
4171                 break;
4172         }
4173         rStr += String( ::rtl::math::doubleToUString( fLimit,
4174                 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
4175                 rDecSep.GetChar(0), sal_True));
4176         rStr += ']';
4177     }
4178 }
4179 
4180 
4181 String SvNumberformat::GetMappedFormatstring(
4182         const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp,
4183         sal_Bool bDontQuote ) const
4184 {
4185     String aStr;
4186     sal_Bool bDefault[4];
4187     // 1 subformat matches all if no condition specified,
4188     bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
4189     // with 2 subformats [>=0];[<0] is implied if no condition specified
4190     bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 &&
4191         eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
4192         eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
4193     // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4194     // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4195     bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
4196         eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
4197         eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
4198     sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
4199     // from now on bDefault[] values are used to append empty subformats at the end
4200     bDefault[3] = sal_False;
4201     if ( !bDefaults )
4202     {   // conditions specified
4203         if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
4204             bDefault[0] = bDefault[1] = sal_True;                               // [];x
4205         else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
4206                 NumFor[2].GetnAnz() == 0 )
4207             bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True;   // [];[];;
4208         // nothing to do if conditions specified for every subformat
4209     }
4210     else if ( bDefault[0] )
4211         bDefault[0] = sal_False;    // a single unconditional subformat is never delimited
4212     else
4213     {
4214         if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
4215             bDefault[3] = sal_True;     // special cases x;x;; and ;x;;
4216         for ( int i=0; i<3 && !bDefault[i]; ++i )
4217             bDefault[i] = sal_True;
4218     }
4219     int nSem = 0;       // needed ';' delimiters
4220     int nSub = 0;       // subformats delimited so far
4221     for ( int n=0; n<4; n++ )
4222     {
4223         if ( n > 0 )
4224             nSem++;
4225 
4226         String aPrefix;
4227 
4228         if ( !bDefaults )
4229         {
4230             switch ( n )
4231             {
4232                 case 0 :
4233                     lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
4234                         fLimit1, rLocWrp.getNumDecimalSep() );
4235                 break;
4236                 case 1 :
4237                     lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
4238                         fLimit2, rLocWrp.getNumDecimalSep() );
4239                 break;
4240             }
4241         }
4242 
4243         const String& rColorName = NumFor[n].GetColorName();
4244         if ( rColorName.Len() )
4245         {
4246             const NfKeywordTable & rKey = rScan.GetKeywords();
4247             for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ )
4248             {
4249                 if ( rKey[j] == rColorName )
4250                 {
4251                     aPrefix += '[';
4252                     aPrefix += rKeywords[j];
4253                     aPrefix += ']';
4254                     break;  // for
4255                 }
4256             }
4257         }
4258 
4259         const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
4260         // The Thai T NatNum modifier during Xcl export.
4261         if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
4262                 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") &&
4263                 MsLangId::getRealLanguage( rNum.GetLang()) ==
4264                 LANGUAGE_THAI)
4265         {
4266             aPrefix += 't';     // must be lowercase, otherwise taken as literal
4267         }
4268 
4269         sal_uInt16 nAnz = NumFor[n].GetnAnz();
4270         if ( nSem && (nAnz || aPrefix.Len()) )
4271         {
4272             for ( ; nSem; --nSem )
4273                 aStr += ';';
4274             for ( ; nSub <= n; ++nSub )
4275                 bDefault[nSub] = sal_False;
4276         }
4277 
4278         if ( aPrefix.Len() )
4279             aStr += aPrefix;
4280 
4281         if ( nAnz )
4282         {
4283             const short* pType = NumFor[n].Info().nTypeArray;
4284             const String* pStr = NumFor[n].Info().sStrArray;
4285             for ( sal_uInt16 j=0; j<nAnz; j++ )
4286             {
4287                 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
4288                 {
4289                     aStr += rKeywords[pType[j]];
4290                     if( NF_KEY_NNNN == pType[j] )
4291                         aStr += rLocWrp.getLongDateDayOfWeekSep();
4292                 }
4293                 else
4294                 {
4295                     switch ( pType[j] )
4296                     {
4297                         case NF_SYMBOLTYPE_DECSEP :
4298                             aStr += rLocWrp.getNumDecimalSep();
4299                         break;
4300                         case NF_SYMBOLTYPE_THSEP :
4301                             aStr += rLocWrp.getNumThousandSep();
4302                         break;
4303                         case NF_SYMBOLTYPE_DATESEP :
4304                             aStr += rLocWrp.getDateSep();
4305                         break;
4306                         case NF_SYMBOLTYPE_TIMESEP :
4307                             aStr += rLocWrp.getTimeSep();
4308                         break;
4309                         case NF_SYMBOLTYPE_TIME100SECSEP :
4310                             aStr += rLocWrp.getTime100SecSep();
4311                         break;
4312                         case NF_SYMBOLTYPE_STRING :
4313                             if( bDontQuote )
4314                                 aStr += pStr[j];
4315                             else if ( pStr[j].Len() == 1 )
4316                             {
4317                                 aStr += '\\';
4318                                 aStr += pStr[j];
4319                             }
4320                             else
4321                             {
4322                                 aStr += '"';
4323                                 aStr += pStr[j];
4324                                 aStr += '"';
4325                             }
4326                             break;
4327                         default:
4328                             aStr += pStr[j];
4329                     }
4330 
4331                 }
4332             }
4333         }
4334     }
4335     for ( ; nSub<4 && bDefault[nSub]; ++nSub )
4336     {   // append empty subformats
4337         aStr += ';';
4338     }
4339     return aStr;
4340 }
4341 
4342 
4343 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
4344         sal_Int32 nVal, sal_uInt16 nMinDigits ) const
4345 {
4346     String aStr;
4347     if ( nMinDigits )
4348     {
4349         if ( nMinDigits == 2 )
4350         {   // speed up the most common case
4351             if ( 0 <= nVal && nVal < 10 )
4352             {
4353                 sal_Unicode* p = aStr.AllocBuffer( 2 );
4354                 *p++ = '0';
4355                 *p = sal_Unicode( '0' + nVal );
4356             }
4357             else
4358                 aStr = String::CreateFromInt32( nVal );
4359         }
4360         else
4361         {
4362             String aValStr( String::CreateFromInt32( nVal ) );
4363             if ( aValStr.Len() >= nMinDigits )
4364                 aStr = aValStr;
4365             else
4366             {
4367                 aStr.Fill( nMinDigits - aValStr.Len(), '0' );
4368                 aStr += aValStr;
4369             }
4370         }
4371     }
4372     else
4373         aStr = String::CreateFromInt32( nVal );
4374     ImpTransliterate( aStr, rNum );
4375     return aStr;
4376 }
4377 
4378 
4379 void SvNumberformat::ImpTransliterateImpl( String& rStr,
4380         const SvNumberNatNum& rNum ) const
4381 {
4382     com::sun::star::lang::Locale aLocale(
4383             MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4384     rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
4385             aLocale, rNum.GetNatNum() );
4386 }
4387 
4388 
4389 void SvNumberformat::GetNatNumXml(
4390         com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
4391         sal_uInt16 nNumFor ) const
4392 {
4393     if ( nNumFor <= 3 )
4394     {
4395         const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
4396         if ( rNum.IsSet() )
4397         {
4398             com::sun::star::lang::Locale aLocale(
4399                     MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
4400             rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
4401                     aLocale, rNum.GetNatNum() );
4402         }
4403         else
4404             rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4405     }
4406     else
4407         rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4408 }
4409 
4410 // static
4411 sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr )
4412 {
4413     // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
4414     xub_StrLen nLen = rStr.Len();
4415     if ( !nLen )
4416         return sal_False;
4417     const sal_Unicode* const pBeg = rStr.GetBuffer();
4418     const sal_Unicode* const pEnd = pBeg + nLen;
4419     register const sal_Unicode* p = pBeg;
4420     do
4421     {   // Anfang
4422         if ( *p == '-' )
4423             return sal_True;
4424     } while ( *p == ' ' && ++p < pEnd );
4425     p = pEnd - 1;
4426     do
4427     {   // Ende
4428         if ( *p == '-' )
4429             return sal_True;
4430     } while ( *p == ' ' && pBeg < --p );
4431     return sal_False;
4432 }
4433 
4434 
4435 // static
4436 void SvNumberformat::SetComment( const String& rStr, String& rFormat,
4437         String& rComment )
4438 {
4439     if ( rComment.Len() )
4440     {   // alten Kommentar aus Formatstring loeschen
4441         //! nicht per EraseComment, der Kommentar muss matchen
4442         String aTmp( '{' );
4443         aTmp += ' ';
4444         aTmp += rComment;
4445         aTmp += ' ';
4446         aTmp += '}';
4447         xub_StrLen nCom = 0;
4448         do
4449         {
4450             nCom = rFormat.Search( aTmp, nCom );
4451         } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) );
4452         if ( nCom != STRING_NOTFOUND )
4453             rFormat.Erase( nCom );
4454     }
4455     if ( rStr.Len() )
4456     {   // neuen Kommentar setzen
4457         rFormat += '{';
4458         rFormat += ' ';
4459         rFormat += rStr;
4460         rFormat += ' ';
4461         rFormat += '}';
4462         rComment = rStr;
4463     }
4464 }
4465 
4466 
4467 // static
4468 void SvNumberformat::EraseCommentBraces( String& rStr )
4469 {
4470     xub_StrLen nLen = rStr.Len();
4471     if ( nLen && rStr.GetChar(0) == '{' )
4472     {
4473         rStr.Erase( 0, 1 );
4474         --nLen;
4475     }
4476     if ( nLen && rStr.GetChar(0) == ' ' )
4477     {
4478         rStr.Erase( 0, 1 );
4479         --nLen;
4480     }
4481     if ( nLen && rStr.GetChar( nLen-1 ) == '}' )
4482         rStr.Erase( --nLen, 1 );
4483     if ( nLen && rStr.GetChar( nLen-1 ) == ' ' )
4484         rStr.Erase( --nLen, 1 );
4485 }
4486 
4487 
4488 // static
4489 void SvNumberformat::EraseComment( String& rStr )
4490 {
4491     register const sal_Unicode* p = rStr.GetBuffer();
4492     sal_Bool bInString = sal_False;
4493     sal_Bool bEscaped = sal_False;
4494     sal_Bool bFound = sal_False;
4495     xub_StrLen nPos = 0;
4496     while ( !bFound && *p )
4497     {
4498         switch ( *p )
4499         {
4500             case '\\' :
4501                 bEscaped = !bEscaped;
4502             break;
4503             case '\"' :
4504                 if ( !bEscaped )
4505                     bInString = !bInString;
4506             break;
4507             case '{' :
4508                 if ( !bEscaped && !bInString )
4509                 {
4510                     bFound = sal_True;
4511                     nPos = sal::static_int_cast< xub_StrLen >(
4512                         p - rStr.GetBuffer());
4513                 }
4514             break;
4515         }
4516         if ( bEscaped && *p != '\\' )
4517             bEscaped = sal_False;
4518         ++p;
4519     }
4520     if ( bFound )
4521         rStr.Erase( nPos );
4522 }
4523 
4524 
4525 // static
4526 sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos,
4527             sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4528 {
4529     xub_StrLen nLen = rStr.Len();
4530     if ( nPos >= nLen )
4531         return sal_False;
4532     register const sal_Unicode* p0 = rStr.GetBuffer();
4533     register const sal_Unicode* p = p0;
4534     register const sal_Unicode* p1 = p0 + nPos;
4535     sal_Bool bQuoted = sal_False;
4536     while ( p <= p1 )
4537     {
4538         if ( *p == cQuote )
4539         {
4540             if ( p == p0 )
4541                 bQuoted = sal_True;
4542             else if ( bQuoted )
4543             {
4544                 if ( *(p-1) != cEscIn )
4545                     bQuoted = sal_False;
4546             }
4547             else
4548             {
4549                 if ( *(p-1) != cEscOut )
4550                     bQuoted = sal_True;
4551             }
4552         }
4553         p++;
4554     }
4555     return bQuoted;
4556 }
4557 
4558 
4559 // static
4560 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos,
4561             sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
4562 {
4563     xub_StrLen nLen = rStr.Len();
4564     if ( nPos >= nLen )
4565         return STRING_NOTFOUND;
4566     if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
4567     {
4568         if ( rStr.GetChar( nPos ) == cQuote )
4569             return nPos;        // schliessendes cQuote
4570         return STRING_NOTFOUND;
4571     }
4572     register const sal_Unicode* p0 = rStr.GetBuffer();
4573     register const sal_Unicode* p = p0 + nPos;
4574     register const sal_Unicode* p1 = p0 + nLen;
4575     while ( p < p1 )
4576     {
4577         if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
4578             return sal::static_int_cast< xub_StrLen >(p - p0);
4579         p++;
4580     }
4581     return nLen;        // String Ende
4582 }
4583 
4584 
4585 sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const
4586 {
4587     sal_uInt16 nCnt = 0;
4588     sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz();
4589     short const * const pType = NumFor[nNumFor].Info().nTypeArray;
4590     for ( sal_uInt16 j=0; j<nAnz; ++j )
4591     {
4592         switch ( pType[j] )
4593         {
4594             case NF_SYMBOLTYPE_STRING:
4595             case NF_SYMBOLTYPE_CURRENCY:
4596             case NF_SYMBOLTYPE_DATESEP:
4597             case NF_SYMBOLTYPE_TIMESEP:
4598             case NF_SYMBOLTYPE_TIME100SECSEP:
4599             case NF_SYMBOLTYPE_PERCENT:
4600                 ++nCnt;
4601             break;
4602         }
4603     }
4604     return nCnt;
4605 }
4606 
4607