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